Error executing template "Designs/Keflico/eCom/Product/Product-pdf.cshtml"
System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at CompiledRazorTemplates.Dynamic.RazorEngine_42209971d5174e71800cbadc36a56317.Execute() in D:\dynamicweb.net\Solutions\keflico.live\Files\Templates\Designs\Keflico\eCom\Product\Product-pdf.cshtml:line 340
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 += GetInteger("Ecom:Product:Field.ProductPieceOnPurchase.Value");
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 background-transparent product-details product-details-pdf">
166 <div class="product-details__info">
167 <div class="product-details__info-labels-pdf">
168 @if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductCertification")) && GetString("Ecom:Product:Field.ProductCertification") != "-1")
169 {
170 string certification = GetString("Ecom:Product:Field.ProductCertification").ToLower();
171 if (certification.Contains("pefc"))
172 {
173 <a href="@pefcLink" target="_blank">
174 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/pefc-logo.svg")))
175 {
176 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/pefc-logo.svg"))
177 }
178 </a>
179 }
180 else if (certification.Contains("fsc"))
181 {
182 <a href="@fscLink" target="_blank">
183 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/fsc-logo.svg")))
184 {
185 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/fsc-logo.svg"))
186 }
187 </a>
188 }
189 }
190 @if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductNordicEcoLabel")) && GetString("Ecom:Product:Field.ProductNordicEcoLabel") != "-1")
191 {
192 <a href="@ecoNordicLink" target="_blank">
193 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/svanemaerket-logo.svg")))
194 {
195 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/svanemaerket-logo.svg"))
196 }
197 </a>
198 }
199 @if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductCradleToCradle.Value")) && GetString("Ecom:Product:Field.ProductCradleToCradle.Value") != "-1" && GetString("Ecom:Product:Field.ProductCradleToCradle.Value") != "N/A")
200 {
201 <a href="@cradleToCradleLink" target="_blank">
202 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/cradle-logo.svg")))
203 {
204 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/cradle-logo.svg"))
205 }
206 </a>
207 }
208 </div>
209 </div>
210 <div class="product-details__info-meta">
211 <ul class="product-details__info-meta-list">
212 <li id="productNumber">@Translate("Translate_Product_Page_ProductNumber"): @productNumber</li>
213 @if (!string.IsNullOrWhiteSpace(dbNumber))
214 {
215 <li>@GetString("Ecom:Product:Field.ProductDbNumber.Name"): @dbNumber</li>
216 }
217 </ul>
218 </div>
219 <h1 id="productName" class="product-details__info-title-pdf">@productName</h1>
220 <div class="product-details__info-size-pdf">@GetString("Ecom:Product:Field.Name2")</div>
221 </div>
222
223 <div>
224 @switch (labelCode.ToLower())
225 {
226 case "prøver":
227 <div class="product-details__label-code label-code label-code--samples">@Translate("LabelCode_" + labelCode.ToLower().Replace("ø", "oe"))</div>
228 break;
229 case "skaffe":
230 case "relatordre":
231 <div class="product-details__label-code label-code">@Translate("LabelCode_" + labelCode.ToLower())</div>
232 break;
233 default:
234 break;
235 }
236 @{
237 var imageList = new List<string>();
238 if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product.ImageDefault.Clean")))
239 {
240 imageList.Add(GetString("Ecom:Product.ImageDefault.Clean"));
241 }
242 foreach (var category in GetLoop("ImageCategories"))
243 {
244 if (category.GetString("Category.SystemName") == "Images")
245 {
246 foreach (var image in category.GetLoop("Category.Images"))
247 {
248 imageList.Add(image.GetString("Ecom:Product:Detail.Image.Clean"));
249 }
250 }
251 }
252
253 for (int i = 0; i < imageList.Count; i += 2)
254 {
255 <div class="product-details-pdf__media">
256 <picture class="product-details__image-wrap">
257 <img src="@imageList[i]" alt="@productName" loading="lazy">
258 </picture>
259 @if (i + 1 < imageList.Count)
260 {
261 <picture class="product-details__image-wrap">
262 <img src="@imageList[i + 1]" alt="@productName" loading="lazy">
263 </picture>
264 }
265 </div>
266 }
267 }
268 </div>
269 <span class="disclaimer">(@Translate("Translate_Product_Page_ImageDisclaimer"))</span>
270 </article>
271
272
273
274 <article class="module module-sand background-transparent product-description product-description-pdf">
275 <div class="tabs">
276
277 <div id="description" class="tab__content tab__content--active" role="tabpanel" aria-hidden="false" aria-labelledby="description-tab">
278 <h2>@Translate("Translate_Product_Page_ProductDescription")</h2>
279 <div class="tab__content-wrapper">
280 <div class="rich-text">
281 <div class="large-text">@GetString("Ecom:Product.LongDescription")</div>
282 @GetString("Ecom:Product:Field.ProductDescriptionShortLongText.Value")
283 </div>
284 @if (hasDownloads)
285 {
286 <div class="tab__content-sidebar">
287 <strong>@Translate("Translate__Product_Page_Downloads")</strong>
288 <ul class="tab__content-list">
289 @foreach (var fileCat in GetLoop("ImageCategories"))
290 {
291 if (fileCat.GetString("Category.SystemName") != "Images")
292 {
293 foreach (var file in fileCat.GetLoop("Category.Images"))
294 {
295 string fileLink = file.GetString("Ecom:Product:Detail.Image.Clean");
296 string fileName = file.GetString("Ecom:Product:Detail.Name");
297
298 if (String.IsNullOrWhiteSpace(fileName))
299 {
300 fileName = Path.GetFileNameWithoutExtension(fileLink);
301 }
302
303 <li>
304 <a class="swap-link" href="@fileLink" data-link="@fileLink" target="_blank">
305 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/file.svg")))
306 {
307 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/file.svg"))
308 }
309 @fileName.Replace("-", " ").Replace("_", " ")
310 </a>
311 </li>
312 }
313 }
314 }
315
316 </ul>
317 </div>
318 }
319 </div>
320 </div>
321 <div id="technical" class="tab__content technical-specs tab__content--active" role="tabpanel" aria-hidden="false" aria-labelledby="technical-tab">
322 <div class="rich-text">
323 <h2>@Translate("Translate_Product_Page_TechnicalSpecifications")</h2>
324
325 @{
326 CategoryFieldViewModel specs = productViewmodel.FieldDisplayGroups.Values.Where(x => x.Id.ToLower() == "technicalspecifications").FirstOrDefault();
327 CategoryFieldViewModel specsWithInfo = productViewmodel.FieldDisplayGroups.Values.Where(x => x.Id.ToLower() == "technicalspecificationswithinfo").FirstOrDefault();
328 }
329
330 @if (specs != null)
331 {
332 <ul class="product-description__technical-list">
333 @foreach (var field in specs.Fields.Values)
334 {
335 if (field.Type.ToLower() == "list")
336 {
337 List<FieldOptionValueViewModel> fieldValue = (List<FieldOptionValueViewModel>)field.Value;
338 int i = 0;
339
340 if (fieldValue.First().Value.ToString() != "-1" && fieldValue.Where(x => x.Name.ToLower() == "ingen").Count() == 0)
341 {
342 <li class="product-description__technical-list-item">
343 <div class="key">@field.Name</div>
344 <div class="value">
345 <span class="line">
346 @foreach (FieldOptionValueViewModel info in fieldValue)
347 {
348 if (i > 0)
349 {
350 @(", " + info.Name)
351 }
352 else
353 {
354 @info.Name
355 }
356 i++;
357 }
358 </span>
359 </div>
360 </li>
361 }
362 }
363 else
364 {
365 if (field.Value.ToString() != "0" && field.Value.ToString().ToLower() != "ingen")
366 {
367 <li class="product-description__technical-list-item">
368 @if (field.Name.ToLower() == "number")
369 {
370 <div class="key">@Translate("Translate_General_ProductNumber")</div>
371 }
372 else if (field.Name.ToLower() == "weight")
373 {
374 <div class="key">@Translate("Translate_General_Weight")</div>
375 }
376 else
377 {
378 <div class="key">@field.Name</div>
379 }
380 <div class="value">
381 <span class="line">@field.Value</span>
382 </div>
383 </li>
384 }
385 }
386 }
387 </ul>
388 }
389 @if (specsWithInfo != null)
390 {
391 <ul class="product-description__technical-list">
392 @foreach (var field in specsWithInfo.Fields.Values)
393 {
394 if (field.Type.ToLower() == "list")
395 {
396 List<FieldOptionValueViewModel> fieldValue = (List<FieldOptionValueViewModel>)field.Value;
397 int i = 0;
398
399 if (fieldValue.First().Value.ToString() != "-1" && fieldValue.Where(x => x.Name.ToLower() == "ingen").Count() == 0)
400 {
401 <li class="product-description__technical-list-item">
402 <div class="key">@field.Name</div>
403 <div class="value">
404 <span class="line with-toolip">
405 @foreach (FieldOptionValueViewModel info in fieldValue)
406 {
407 if (i > 0)
408 {
409 @(", " + info.Name)
410 }
411 else
412 {
413 @info.Name
414 }
415 i++;
416 }
417 <span class="tooltip">
418 <span class="tooltip__icon">
419 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")))
420 {
421 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))
422 }
423 </span>
424 <span class="tooltip__text tooltip__text--left">
425 <p>@Translate("Translate_Product_Spec_Info_" + field.SystemName)</p>
426 </span>
427 </span>
428 </span>
429 </div>
430 </li>
431 }
432 }
433 else
434 {
435 if (field.Value.ToString() != "0" && field.Value.ToString().ToLower() != "ingen")
436 {
437 <li class="product-description__technical-list-item">
438 <div class="key">@field.Name</div>
439 <div class="value">
440 <span class="line with-tooltip">
441 @if (field.SystemName.ToLower() == "productdensity")
442 {
443 @field.Value.ToString().Replace(",", ".")
444 }
445 else
446 {
447 @field.Value
448 }
449 <span class="tooltip">
450 <span class="tooltip__icon">
451 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")))
452 {
453 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))
454 }
455 </span>
456 <span class="tooltip__text tooltip__text--left">
457 <p>@Translate("Translate_Product_Spec_Info_" + field.SystemName)</p>
458 </span>
459 </span>
460 </span>
461 </div>
462 </li>
463 }
464 }
465 }
466 </ul>
467 }
468 </div>
469 </div>
470 @if (hasNewDownloads)
471 {
472 <div id="documents" class="tab__content documents tab__content--active" role="tabpanel" aria-hidden="false" aria-labelledby="documents-tab">
473 <div class="rich-text">
474 <h2>@Translate("Translate_Product_Page_Documents")</h2>
475
476 <ul class="tab__content-list product-description__documents-list">
477 @foreach (var fileCat in GetLoop("ImageCategories"))
478 {
479 if (fileCat.GetString("Category.SystemName").StartsWith("docView_") && fileCat.GetLoop("Category.Images").Count() > 0)
480 {
481 <li class="product-description__documents-list-item">
482 <p class="product-description__documents-list-item-title">@fileCat.GetString("Category.Name")</p>
483 @foreach (var file in fileCat.GetLoop("Category.Images"))
484 {
485 string fileLink = file.GetString("Ecom:Product:Detail.Image.Clean");
486 string fileName = file.GetString("Ecom:Product:Detail.Name");
487
488 if (String.IsNullOrWhiteSpace(fileName))
489 {
490 fileName = Path.GetFileNameWithoutExtension(fileLink);
491 }
492
493 Uri uri = new Uri(HttpContext.Current.Request.Url.AbsoluteUri);
494 string baseUrl = $"{uri.Scheme}://{uri.Host}";
495 string pathName = baseUrl + fileLink;
496
497 if (!String.IsNullOrEmpty(fileLink))
498 {
499 <a href="@pathName" data-link="@pathName" target="_blank">
500 @GetFileIcon(fileLink)
501 @fileName.Replace("-", " ").Replace("_", " ")
502 </a>
503 }
504 }
505 </li>
506 }
507 }
508 </ul>
509 </div>
510 </div>
511 }
512
513 <div id="more-info" class="tab__content more-info-content tab__content--active" role="tabpanel" aria-hidden="false" aria-labelledby="more-info-tab">
514 <div class="rich-text">
515 <h2>@Translate("Translate_Product_Page_MoreInformation")</h2>
516 @{
517 CategoryFieldViewModel moreInfo = productViewmodel.FieldDisplayGroups.Values.Where(x => x.Id.ToLower() == "yderlig_information").FirstOrDefault();
518
519 if (moreInfo != null && moreInfo.Fields != null)
520 {
521 var groups = moreInfo.Fields.Values;
522
523 foreach (var group in groups)
524 {
525 <strong>@Translate("Translate_ProductPage_" + group.SystemName)</strong>
526 @group.Value
527 }
528 }
529 }
530 </div>
531 </div>
532 </div>
533
534 </article>
535
536 @RenderSnippet("EnquireProductForm")
537
538
539 @SnippetEnd("Javascripts")
540
541 @if(productLayout != "group32" && productLayout != "group73" && productLayout != "group1") {
542 @SnippetStart("JavaScripts")
543 <script>
544 const orderButton = document.getElementById("product-order-button");
545
546 if(orderButton) {
547 const form = orderButton.closest('form');
548
549 orderButton.addEventListener('click', (event) => {
550 event.preventDefault();
551
552 const formData = new FormData(form);
553 const qty = parseInt(formData.get('Quantity1'))
554
555 const price = @GetString("Ecom:Product.Discount.Price.PriceWithoutVAT.Value").Replace(",", ".");
556 const halfPrice = @GetString("Ecom:Product:Field.ProductPriceHalfParcel").Replace(",", "");
557 const fullPrice = @GetString("Ecom:Product:Field.ProductPriceCompleteParcel").Replace(",", "");
558
559 const halfParcel = @halfParcelAmount;
560 const fullParcel = @completeParcelAmount;
561
562 const salesUnit = "@salesUnit";
563 const productLength = @GetString("Ecom:Product:Field.ProductLengthSale.Value.Raw");
564 const lengthUnit = "@GetString("Ecom:Product:Field.ProductLengthUnitCode.Value")";
565
566 let value = 0;
567
568 addToValue(qty)
569
570 function addToValue(remainingQty) {
571 if(salesUnit == "m") {
572 value += remainingQty * (productLength/1000) * price;
573 } else {
574 value += remainingQty * price;
575 }
576 }
577
578 dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
579 dataLayer.push({
580 event: "add_to_cart",
581 ecommerce: {
582 currency: "@GetString("Ecom:Product.Currency.Code")",
583 value: value,
584 items: [
585 {
586 item_id: "@productNumber",
587 item_name: "@productName",
588 quantity: qty
589
590 }
591 ]
592 }
593 });
594 form.submit()
595 });
596 }
597 </script>
598 @SnippetEnd("Javascripts")
599 }
600
601 @if(productLayout == "group32" || productLayout == "group73" || productLayout == "group1") {
602 <div id="orderFlowApp" class="product-modal" :class="{ 'not-logged-in': !isLoggedIn, 'upsell js-slide-in' : showAccessories || showStep1 }">
603 <div v-if="showAccessories" class="product-modal__content product-modal__upsell-section">
604 <div class="product-modal__content-top">
605 <a href="/" class="navigation__logo">
606 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/keflico_logo.svg")))
607 {
608 <text>@System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/keflico_logo.svg"))</text>
609 }
610 </a>
611 <a href="@CartPage" class="navigation__cart">
612 <svg xmlns="http://www.w3.org/2000/svg" width="21.773" height="19.513" viewBox="0 0 21.773 19.513">
613 <g transform="translate(0.75 0.75)">
614 <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"/>
615 <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"/>
616 <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"/>
617 <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"/>
618 <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"/>
619 <line x2="11.102" transform="translate(6.374 13.37)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
620 </g>
621 </svg>
622 <span class="cart-qty" data-count="@cartCount">@cartCount</span>
623 </a>
624 <a href="#" class="navigation__return product-modal__back-link" @@click="showAccessories = false">
625 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20.006 12.445">
626 <g transform="translate(-421.494 -889.275)">
627 <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"/>
628 <line x2="17" transform="translate(423.5 895.5)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="2" />
629 </g>
630 </svg>
631 </a>
632 <div v-if="accessoriesList.length > 0" class="breadcrumbs breadcrumbs--no-seperator">
633 <ul class="breadcrumbs__list">
634 <li class="breadcrumbs__item">1. Vælg produkter</li>
635 <li class="breadcrumbs__item active">2. Vælg tilbehør</li>
636 </ul>
637 </div>
638 </div>
639 <div class="upsell-section__top">
640 <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>
641 <h2 class="upsell-section__subtitle">@Translate("Translate_OrderFlow_UpsellReminder")</h2>
642 </div>
643 <div class="upsell-section__card-list">
644
645 <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)">
646 <div class="counter-amount" v-if="getQty(product.Number) > 0">{{ getQty(product.Number) }}</div>
647 <div class="upsell__content-info">
648 <div class="upsell__content-info-media">
649 <a :href="'/@(EcomPage)&ProductID=' + product.Number" target="_blank">
650 <img :src="'/admin/public/getimage.ashx?Image=' + product.DefaultImage.Value + '&width=175&height=175&Crop=0&Compression=100'" :alt="product.Name" loading="lazy">
651 </a>
652 </div>
653 <div class="upsell__content-info-container">
654 <div class="product-details__info-meta">
655 <ul class="product-details__info-meta-list">
656 <li>@Translate("Translate_Product_Page_ProductNumber") {{ product.Number }}</li>
657 @if(!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductDbNumber.Value"))) {
658 <li>@GetString("Ecom:Product:Field.ProductDbNumber.Name") {{ product.EAN }}</li>
659 }
660 </ul>
661 </div>
662 <div class="product-details__info-title">{{ product.Name }}</div>
663 <div class="product-details__info-size">{{ product.ProductFields.Name2.Value }}</div>
664 <div class="product-details__info-quantity">
665 <div class="info-quantity" v-if="product.ProductFields.ProductNumberPerPackage.Value && product.ProductFields.ProductNumberPerPackage.Value > 0">{{ product.ProductFields.ProductNumberPerPackage.Value }} @Translate("Translate_General_Pieces")</div>
666 <div class="info-price" v-if="product.Price.Price">{{ prettyPrice(product.Price.Price) }} @priceCurrencySymbol</div>
667 </div>
668 <div class="product-details__info-actions" v-if="product.Price.Price && product.Price.Price > 0 && !product.VariantInfo.VariantInfo">
669 <vue-counter :ref="'accCounter' + product.Number" :min="0" @@valueupdate="updateAccButton($event, product.Number)"></vue-counter>
670 <a href="#" class="confirm disabled" :ref="'confirmBtn' + product.Number" @@click="addAcc($event, product.Number)">
671 <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">
672 <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"/>
673 </svg>
674 <svg v-else xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.773 19.513">
675 <g transform="translate(-87.571 -246.25)">
676 <g transform="translate(88.321 247)">
677 <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"/>
678 <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"/>
679 <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"/>
680 <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"/>
681 <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"/>
682 <line x2="11.102" transform="translate(6.374 13.37)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
683 </g>
684 </g>
685 </svg>
686 </a>
687 </div>
688 </div>
689 </div>
690 </div>
691 </div>
692 <div class="notification-bar">
693 <div class="notification-bar__text">
694 @Translate("Translate_OrderFlow_HelpText")
695 <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>
696 </div>
697 </div>
698 <div class="product-modal__content-bottom"></div>
699 </div>
700 <div v-if="!showAccessories" class="product-modal__content">
701 <div class="product-modal__content-top">
702 <a href="/" class="navigation__logo">
703 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/keflico_logo.svg")))
704 {
705 <text>@System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/keflico_logo.svg"))</text>
706 }
707 </a>
708 <a href="@CartPage" class="navigation__cart">
709 <svg xmlns="http://www.w3.org/2000/svg" width="21.773" height="19.513" viewBox="0 0 21.773 19.513">
710 <g transform="translate(0.75 0.75)">
711 <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"/>
712 <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"/>
713 <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"/>
714 <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"/>
715 <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"/>
716 <line x2="11.102" transform="translate(6.374 13.37)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/>
717 </g>
718 </svg>
719 <span class="cart-qty" data-count="@cartCount">@cartCount</span>
720 </a>
721 <a href="#" class="navigation__return product-modal__back-link" @@click="showAccessories = false">
722 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20.006 12.445">
723 <g transform="translate(-421.494 -889.275)">
724 <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"/>
725 <line x2="17" transform="translate(423.5 895.5)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="2" />
726 </g>
727 </svg>
728 </a>
729 <div v-if="accessoriesList.length > 0" class="breadcrumbs breadcrumbs--no-seperator">
730 <ul class="breadcrumbs__list">
731 <li class="breadcrumbs__item active">1. Vælg produkter</li>
732 <li class="breadcrumbs__item">2. Vælg tilbehør</li>
733 </ul>
734 </div>
735 </div>
736 <div class="product-modal__content-info">
737 <div class="product-modal__content-info-media">
738 <picture v-if="mainProduct.image">
739 <img :src="mainProduct.image" :alt="mainProduct.name" loading="lazy">
740 </picture>
741 </div>
742 <div class="product-modal__content-info-container">
743 <div class="product-details__info-meta">
744 <ul class="product-details__info-meta-list">
745 <li>{{ mainProduct.number }}</li>
746 @if(!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductDbNumber.Value"))) {
747 <li>{{ mainProduct.dbNumber }}</li>
748 }
749 </ul>
750 </div>
751 <div class="product-details__info-title">{{ mainProduct.name }}</div>
752 <div class="product-details__info-size">
753 @if(primaryGroup == "group1") {
754 <text>{{ mainProduct.size }}</text>
755 } else {
756 <div class="product-details__info-size-thickness">
757 <strong>@Translate("Translate_OrderFlow_Thickness")</strong>
758 {{ mainProduct.thickness }} {{ thicknessUnit }}
759 </div>
760 <div class="product-details__info-size-width">
761 <strong>@Translate("Translate_OrderFlow_Width")</strong>
762 {{ mainProduct.width }} {{ widthUnit }}
763 </div>
764 }
765 </div>
766 </div>
767 </div>
768 <div class="product-modal__content-product-stock">
769 @if(primaryGroup == "group1") {
770 <div class="tabs">
771 <div v-if="bundles.length > 0" class="tabs__nav">
772 <ul role="tablist" class="tabs__list" data-action="tabs">
773 <li role="none" class="tabs__item">
774 @Translate("Translate_OrderFlow_Choose_ProductType")
775 </li>
776 <li role="none" class="tabs__item">
777 <a href="#helbundt" @@click.prevent="showBundles = true;" class="tab" :class="{ 'tab--active': showBundles }" role="tab" id="helbundt-tab" aria-controls="helbundt" aria-selected="true">
778 <span>@Translate("Translate_OrderFlow_Bundle")</span>
779 </a>
780 </li>
781 @if(!isBundleOnly) {
782 <li role="none" class="tabs__item">
783 <a href="#anbrud" @@click.prevent="showBundles = false;" class="tab" :class="{ 'tab--active': !showBundles }" role="tab" id="anbrud-tab" aria-controls="anbrud" aria-selected="false">
784 <span>@Translate("Translate_OrderFlow_Pieces")</span>
785 </a>
786 </li>
787 }
788 </ul>
789 </div>
790 <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">
791 <div class="product-modal__stock">
792 <div class="product-modal__stock-line product-modal__stock-line--header bundle-header">
793 <div class="product-modal__stock-cell mobile-cell filler"></div>
794 <div class="product-modal__stock-cell">@Translate("Translate_OrderFlow_BundleNo")</div>
795 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Thickness")</div>
796 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Width")</div>
797 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Length")</div>
798 <div v-if="!enquireProduct" class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_InStock")</div>
799 <div v-if="!enquireProduct" class="product-modal__stock-cell">
800 @Translate("Translate_OrderFlow_OnWayHome"):
801 <span v-html="onTheWayHome"></span>
802 </div>
803 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell product-modal__stock-cell--highlighted">@Translate("Translate_OrderFlow_ChooseAmount")</div>
804 </div>
805 <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)">
806 <div class="stock-bundle__header">
807 <div class="product-modal__stock-cell mobile-cell">
808 <div class="cell-radio counter-amount bundle-amount" v-html="getQty(bundle.bundleNo) > 0 ? getQty(bundle.bundleNo) : ''" :data-id="bundle.bundleNo"></div>
809 </div>
810 <div class="product-modal__stock-cell">
811 <span class="bundle-toggle" @@click="toggleBundle(bundle.bundleNo)">
812 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12.446 7.223">
813 <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"/>
814 </svg>
815 </span>
816 {{ bundle.bundleNo }}
817 </div>
818 <div class="product-modal__stock-cell mobile-cell"></div>
819 <div class="product-modal__stock-cell mobile-cell"></div>
820 </div>
821 <div class="stock-bundle__body">
822 <div class="stock-bundle__body-columns">
823 <div class="stock-bundle__cell">
824 @Translate("Translate_OrderFlow_Dimensions")
825 </div>
826 <div class="stock-bundle__cell">
827 @Translate("Translate_OrderFlow_InStock")
828 </div>
829 </div>
830 <div v-for="(product, index) in bundle.productsInBundle" class="stock-bundle__stick">
831 <div class="stock-bundle__cell mobile-cell">
832 <div class="cell-stack">
833 @Translate("Translate_OrderFlow_Thickness_Short") {{ product.thickness }} {{ thicknessUnit }}
834 </div>
835 <div class="cell-stack">
836 @Translate("Translate_OrderFlow_Width_Short") {{ product.width }} {{ widthUnit }}
837 </div>
838 <div class="cell-stack">
839 @Translate("Translate_OrderFlow_Length_Short") {{ product.length.replace(",", "") }} {{ lenghtUnit }}
840 </div>
841 </div>
842 <div class="stock-bundle__cell desktop-cell">{{ product.thickness }} {{ thicknessUnit }}</div>
843 <div class="stock-bundle__cell desktop-cell">{{ product.width }} {{ widthUnit }}</div>
844 <div class="stock-bundle__cell desktop-cell">{{ product.length.replace(",", "") }} {{ lenghtUnit }}</div>
845 <div v-if="!enquireProduct" class="stock-bundle__cell">{{ product.stock.units > 500 ? '+500' : product.stock.units }} @Translate("Translate_General_Pieces")</div>
846 <div v-if="!enquireProduct" class="stock-bundle__cell desktop-cell"></div>
847 <div v-if="isLoggedIn && !enquireProduct" class="stock-bundle__cell product-modal__stock-cell--highlighted desktop-cell">
848 <vue-counter v-if="index == 0 && isLoggedIn && !enquireProduct" ref="counter" :min="0" :max="1" @@valueupdate="addBundleToTempCart($event, bundle.bundleNo)" />
849 </div>
850 </div>
851 </div>
852 </div>
853 <div v-if="loadingBundles" class="bundle-loading">
854 <span class="loader"></span>
855 </div>
856 </div>
857 </div>
858 @if(!isBundleOnly) {
859 <div id="anbrud" class="tab__content" :class="{ 'tab__content--active': !showBundles }" role="tabpanel" aria-hidden="false" aria-labelledby="anbrud-tab">
860 <div class="product-modal__stock">
861 <div class="product-modal__stock-line product-modal__stock-line--header">
862 <div class="product-modal__stock-cell filler mobile-cell" v-if="isLoggedIn && !enquireProduct"></div>
863 <div class="product-modal__stock-cell mobile-cell">@Translate("Translate_OrderFlow_Dimension")</div>
864 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Thickness")</div>
865 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Width")</div>
866 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Length")</div>
867 <div v-if="!enquireProduct" class="product-modal__stock-cell">@Translate("Translate_OrderFlow_InStock")</div>
868 <div v-if="!enquireProduct" class="product-modal__stock-cell">
869 @Translate("Translate_OrderFlow_OnWayHome"):
870 <span v-html="onTheWayHome"></span>
871 </div>
872 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell product-modal__stock-cell--highlighted">@Translate("Translate_OrderFlow_ChooseAmount")</div>
873 </div>
874 <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">
875 <div class="product-modal__stock-cell quantity" v-if="isLoggedIn && !enquireProduct">
876 <div class="cell-radio counter-amount" :data-id="variant.id" v-html="getQty(variant.id) > 0 ? getQty(variant.id) : ''"></div>
877 </div>
878 <div class="product-modal__stock-cell cell-stack">
879 <span class="stack">@Translate("Translate_OrderFlow_Thickness_Short") {{ variant.size.thickness }} {{ thicknessUnit }}</span>
880 <span class="stack">@Translate("Translate_OrderFlow_Width_Short") {{ variant.size.width }} {{ widthUnit }}</span>
881 <span class="stack">@Translate("Translate_OrderFlow_Length_Short") {{ variant.size.length }} {{ lenghtUnit }}</span>
882 </div>
883 <div class="product-modal__stock-cell desktop-cell">{{ variant.size.thickness }} {{ thicknessUnit }}</div>
884 <div class="product-modal__stock-cell desktop-cell">{{ variant.size.width }} {{ widthUnit }}</div>
885 <div class="product-modal__stock-cell desktop-cell">{{ variant.size.length }} {{ lenghtUnit }}</div>
886 <div v-if="!enquireProduct" class="product-modal__stock-cell">{{ calculateStockLevel(variant.stock.warehouse) }} @Translate("Translate_General_Pieces") </div>
887 <div v-if="!enquireProduct" class="product-modal__stock-cell"></div>
888 <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}">
889 <vue-counter v-if="variant.stock.warehouse + variant.stock.purchase > 0 && isLoggedIn && !enquireProduct" ref="counter" :min="0" @@valueupdate="addToTempCart($event, variant.id)" />
890 </div>
891 </div>
892 </div>
893 </div>
894 }
895 </div>
896 } else {
897 <div class="product-modal__stock">
898 <div class="product-modal__stock-line product-modal__stock-line--header product-modal__stock-line--terrace">
899 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell filler mobile-cell"></div>
900 <div class="product-modal__stock-cell">@Translate("Translate_OrderFlow_Length")</div>
901 <div class="product-modal__stock-cell">@Translate("Translate_OrderFlow_InStock")</div>
902 <div class="product-modal__stock-cell">@Translate("Translate_OrderFlow_OnWayHome")</div>
903 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell product-modal__stock-cell--highlighted">@Translate("Translate_OrderFlow_ChooseAmount")</div>
904 </div>
905 <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">
906 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell quantity">
907 <div class="cell-radio counter-amount" :data-id="variant.id" v-html="getQty(variant.id) > 0 ? getQty(variant.id) : ''"></div>
908 </div>
909 <div class="product-modal__stock-cell">{{ variant.size.length }} {{ lenghtUnit }}</div>
910 <div class="product-modal__stock-cell">{{ calculateStockLevel(variant.stock.warehouse) }}</div>
911 @if(primaryGroup == "group73") {
912 <div class="product-modal__stock-cell">{{ variant.stock.purchase > 0 ? "@Translate("Translate_General_Yes")" : "@Translate("Translate_General_No")" }}</div>
913 } else {
914 <div class="product-modal__stock-cell">{{ calculateStockLevel(variant.stock.sea) }}</div>
915 }
916
917 @if(primaryGroup == "group32") {
918 <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}">
919 <vue-counter v-if="variant.stock.warehouse + variant.stock.sea > 0 && isLoggedIn && !enquireProduct" ref="counter" :min="0" @@valueupdate="addToTempCart($event, variant.id)" />
920 </div>
921 } else {
922 <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}">
923 <vue-counter v-if="variant.stock.warehouse + variant.stock.purchase > 0 && isLoggedIn && !enquireProduct" ref="counter" :min="0" @@valueupdate="addToTempCart($event, variant.id)" />
924 </div>
925 }
926 </div>
927 </div>
928 }
929 </div>
930 <div class="notification-bar">
931 <div class="notification-bar__text">
932 @Translate("Translate_OrderFlow_HelpText")
933 <a href="#product-inquire-form" id="product-orderflow-inquire-button" data-action="open-content" data-target="#enquireForm">@Translate("Translate_Product_Page_EnquireButton")</a>
934 </div>
935 </div>
936 <div class="product-modal__content-bottom"></div>
937 </div>
938 <div class="product-modal__side">
939 <div class="product-modal__side-top">
940 <a href="#" class="product-modal__back-link" @@click="showAccessories = false">
941 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20.006 12.445">
942 <g transform="translate(-421.494 -889.275)">
943 <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"/>
944 <line x2="17" transform="translate(423.5 895.5)" fill="none" stroke="#fff" stroke-linecap="round" stroke-width="2" />
945 </g>
946 </svg>
947 @Translate("Translate_ProductFlow_Back")
948 </a>
949 <div class="product-modal__basket-icon">
950 <span class="icon"></span>
951 <span class="badge"></span>
952 </div>
953 </div>
954 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__side-basket" :class="{ 'popup--active': showMobileBasket }">
955 <div v-if="pickedVariants.length > 0" class="side-basket__product">
956 <div class="side-basket__product-head">
957 <div class="product-name">{{ mainProduct.name }}</div>
958 <div class="product-price">
959 @if(primaryGroup == "group1") {
960 <span v-if="!loadingPrice">{{ prettyPrice(priceObject.unitPrice) }} @priceCurrencySymbol / {{ mainProduct.prices.unit.label }}</span>
961 <span v-if="loadingPrice" class="loader"></span>
962 } else {
963 <span v-if="!loadingPrice">{{ prettyPrice(priceObject.unitPrice) }} @priceCurrencySymbol / @Translate("Translate_General_RunningMeters")</span>
964 <span v-if="loadingPrice" class="loader"></span>
965 }
966 </div>
967 <div class="product-toggle" @@click="toggleState">
968 <span class="close">@Translate("Translate_General_Close")</span>
969 <span class="open">@Translate("Translate_General_Open")</span>
970 </div>
971 </div>
972 <div v-for="(line, index) in sortedPickedVariants" class="side-basket__product-variant">
973 @if(primaryGroup == "group1") {
974 <template v-if="line.bundle">
975 <div class="size size__header">
976 <strong>@Translate("Translate_OrderFlow_BundleNo") {{ line.bundleNo }}</strong>
977 </div>
978 <template v-for="variant in line.productsInBundle">
979 <div class="size">
980 <template v-if="lenghtUnit == 'mm'">
981 {{ variant.thickness.replace(".", ",") }} x {{ variant.width }} x {{ variant.length.replace(",", "") }}mm
982 </template>
983 <template v-else>
984 {{ variant.thickness.replace(".", ",") }}{{ thicknessUnit }} x {{ variant.width }}{{ widthUnit }} x {{ variant.length.replace(",", "") }} {{ lenghtUnit }}
985 </template>
986 </div>
987 <div class="quantity">{{ prettyNumber(variant.stock.units) }} @Translate("Translate_General_Pieces")</div>
988 </template>
989 </template>
990 <template v-else>
991 <div class="size size__header">
992 <strong>@Translate("Translate_OrderFlow_Pieces")</strong>
993 </div>
994 <div class="size">{{ line.thickness }} x {{ line.width }} x {{ line.length }}mm</div>
995 <div class="quantity">{{ prettyNumber(line.qty) }} @Translate("Translate_General_Pieces")</div>
996 </template>
997 } else {
998 <div class="size">{{ mainProduct.thickness }} x {{ mainProduct.width }} x {{ line.length }}mm</div>
999 <div class="quantity">{{ prettyNumber(line.qty) }} @Translate("Translate_General_Pieces")</div>
1000 }
1001 </div>
1002 <div class="side-basket__product-total">
1003 <div class="product-meters">
1004 @Translate("Translate_General_InTotal")
1005 <span v-if="mainProduct.prices.unit.label == 'm²' || mainProduct.prices.unit.label == 'm'">{{ prettyNumber(calculateMeters()) }} {{ mainProduct.prices.unit.label }}</span>
1006 <span v-else>{{ prettyNumber(calculatePieces()) }} @Translate("Translate_General_Pieces")</span>
1007 </div>
1008 <div class="product-square-meters">
1009 @Translate("Translate_General_TranslatesTo")
1010 <span v-if="mainProduct.prices.unit.label == 'm²' || mainProduct.prices.unit.label == 'm'">{{ prettyNumber(calculateSquareMeters()) }} m<sup>2</sup></span>
1011 <span v-else-if="mainProduct.prices.unit.label == 'm³'">{{ prettyNumber(calculateCubicMeters(), 3) }} m<sup>3</sup></span>
1012 <span v-else-if="mainProduct.prices.unit.label == 'kbf'">{{ prettyNumber(calculateCubicFeet()) }} kbf</span>
1013 </div>
1014 </div>
1015 </div>
1016 <div v-for="product in pickedAcc" class="side-basket__product">
1017 <div class="side-basket__product-head">
1018 <div class="product-name">{{ product.name }}</div>
1019 <div class="product-price">{{ prettyPrice(product.price.unitPrice) }}</div>
1020 <div class="product-toggle" @@click="toggleState">
1021 <span class="close">@Translate("Translate_General_Close")</span>
1022 <span class="open">@Translate("Translate_General_Open")</span>
1023 </div>
1024 </div>
1025 <div class="side-basket__product-variant">
1026 <div class="size">{{ product.name2 }}</div>
1027 <div class="quantity">{{ product.qty }} @Translate("Translate_General_Pieces")</div>
1028 </div>
1029 </div>
1030 <div class="side-basket__summary">
1031 <div class="price-raw">
1032 @Translate("Translate_General_PriceWithoutVat")
1033 <span v-if="!loadingPrice">{{ prettyPrice(priceObject.totalEx) }} @priceCurrencySymbol</span>
1034 <span v-if="loadingPrice" class="loader"></span>
1035 </div>
1036 <div class="vat">
1037 @Translate("Translate_General_Vat")
1038 <span v-if="!loadingPrice">{{ prettyPrice(priceObject.vat) }} @priceCurrencySymbol</span>
1039 <span v-if="loadingPrice" class="loader"></span>
1040 </div>
1041 <div class="price-vat">
1042 @Translate("Translate_General_PriceWithVat")
1043 <span v-if="!loadingPrice">{{ prettyPrice(priceObject.totalInc) }} @priceCurrencySymbol</span>
1044 <span v-if="loadingPrice" class="loader"></span>
1045 </div>
1046 </div>
1047
1048 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__floating-cart">
1049 <div class="floating-cart__bar" :class="{ 'active-bar': showMobileActionBar }">
1050 <div v-if="showMobileActionControls" class="product-modal__stock-control floating-cart__stock-control counter">
1051 <button id="amount-subtract" @@click="currentMobileQty > 0 ? currentMobileQty-- : currentMobileQty = 0" class="substract"><span>−</span></button>
1052 <input id="amount-input" @@keyup="editMobileQty" class="amount" pattern="[0-9.]+" type="tel" data-min="0" min="0" :value="currentMobileQty">
1053 <button id="amount-add" @@click="currentMobileQty++" class="add"><span>+</span></button>
1054 </div>
1055 <div v-if="!showMobileActionControls" @@click="showMobileBasket = !showMobileBasket" class="floating-cart__toggle cart-toggle">
1056 <span v-if="!showMobileBasket" class="cart-toggle--open">Se kurv</span>
1057 <span v-if="showMobileBasket" class="cart-toggle--close">Luk kurv</span>
1058 </div>
1059 <div class="floating-cart__btn-wrapper">
1060 <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>
1061 <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>
1062 <button v-if="currentActiveMobileButton == 'next'" class="btn btn-secondary floating-cart__btn btn--next" @@click="addToBasket">
1063 <template v-if="!loading">Gå videre</template>
1064 <span v-if="loading" class="loader"></span>
1065 </button>
1066 <button v-if="currentActiveMobileButton == 'order' && !showAccessories" class="btn btn-secondary floating-cart__btn btn--order" @@click="addToBasket">
1067 <template v-if="!loading">Gå til bestilling</template>
1068 <span v-if="loading" class="loader"></span>
1069 </button>
1070 <button v-if="currentActiveMobileButton == 'order' && showAccessories" class="btn btn-secondary floating-cart__btn btn--order" @@click="addAccToBasket">
1071 <template v-if="!loading">Gå til bestilling</template>
1072 <span v-if="loading" class="loader"></span>
1073 </button>
1074 </div>
1075 </div>
1076 </div>
1077
1078 <div class="side-basket__actions">
1079 <template v-if="!showAccessories">
1080 <button type="button" @@click="resetBasket" class="btn btn-link btn-link--underlined" :class="{ disabled: pickedVariants.length == 0 }">@Translate("Translate_General_EmptyCart")</button>
1081 <button type="button" :class="{ disabled: pickedVariants.length == 0 }" @@click="addToBasket" class="btn btn-secondary">
1082 <template v-if="!loading">@Translate("Translate_General_AddToCart")</template>
1083 <span v-if="loading" class="loader"></span>
1084 </button>
1085 </template>
1086 <template v-else>
1087 <a href="@CartPage" class="btn btn-link btn-link--underlined">@Translate("Translate_General_GoToCheckout")</a>
1088 <button type="button" @@click="addAccToBasket" class="btn btn-secondary" :class="{ disabled: pickedAcc.length == 0}">
1089 <template v-if="!loading">@Translate("Translate_OrderFlow_AddAccessories")</template>
1090 <span v-if="loading" class="loader"></span>
1091 </button>
1092 </template>
1093 </div>
1094 </div>
1095 </div>
1096 </div>
1097
1098
1099 @SnippetStart("JavaScripts")
1100 <script>
1101 dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
1102 dataLayer.push({
1103 event: "view_item",
1104 ecommerce: {
1105 items: [
1106 {
1107 item_id: "@productNumber",
1108 item_name: "@productName",
1109 }
1110 ]
1111 }
1112 });
1113
1114 </script>
1115 <script async>
1116 const vueCounter = {
1117 name: "VueCounter",
1118 props: ['min', 'max'],
1119 data: () => {
1120 return {
1121 value: 0,
1122 hasError: false,
1123 }
1124 },
1125 methods: {
1126 substract() {
1127 if(this.min || this.min === 0) {
1128 if(this.value > this.min) {
1129 this.value--
1130 } else {
1131 this.handleError();
1132 }
1133 } else {
1134 this.value--
1135 }
1136 },
1137 add() {
1138 if(this.max) {
1139 if(this.value < this.max) {
1140 this.value++
1141 } else {
1142 this.handleError();
1143 }
1144 } else {
1145 this.value++
1146 }
1147 },
1148 handleError() {
1149 this.hasError = true;
1150 setTimeout(() => {
1151 this.hasError = false;
1152 }, 1000);
1153 }
1154 },
1155 watch: {
1156 value(newValue, oldValue) {
1157 this.$emit('valueupdate', newValue)
1158 }
1159 },
1160 template: `<div class="vue-counter" :class="hasError ? 'counter--error' : ''" >
1161 <a class="counter__sub" @@click="substract">-</a>
1162 <input class="counter__value" type="tel" v-model="value" :disabled="value == max ? true : false">
1163 <a class="counter__add" @@click="add">+</a>
1164 </div>`
1165 }
1166
1167 new Vue({
1168 el: '#orderFlowApp',
1169 name: 'Bestillings flow',
1170 components: {
1171 'vue-counter': vueCounter
1172 },
1173 computed: {
1174 lenghtUnit() {
1175 return this.sizeUnitValues[this.mainProduct.sizeUnits.length];
1176 },
1177 widthUnit() {
1178 return this.sizeUnitValues[this.mainProduct.sizeUnits.width];
1179 },
1180 thicknessUnit() {
1181 return this.sizeUnitValues[this.mainProduct.sizeUnits.thickness];
1182 },
1183 sortedVariants() {
1184 return this.variants.sort((a,b) => {
1185 if (a.length !== b.length) {
1186 return a.length - b.length;
1187 } else if (a.width !== b.width) {
1188 return a.width - b.width;
1189 } else {
1190 return a.thickness - b.thickness;
1191 }
1192 }).filter(x => x.size.length > 0);
1193 },
1194 sortedBundles() {
1195 let newBundleList = [];
1196
1197 if(this.bundles.length > 0) {
1198 this.bundles.forEach(bundle => {
1199 const index = newBundleList.findIndex(x => x.bundleNo == bundle.bundleNo);
1200
1201 if(parseFloat(bundle.stock.warehouse) > 0) {
1202 if(index > -1) {
1203 newBundleList[index].productsInBundle.push(
1204 {
1205 length: bundle.length,
1206 width: bundle.width,
1207 thickness: bundle.thickness,
1208 stock: bundle.stock
1209 }
1210 )
1211 } else {
1212 this.toggleBundles.push({
1213 bundle: bundle.bundleNo,
1214 expanded: true,
1215 });
1216 newBundleList.push(
1217 {
1218 bundleNo: bundle.bundleNo,
1219 productsInBundle: [
1220 {
1221 length: bundle.length,
1222 width: bundle.width,
1223 thickness: bundle.thickness,
1224 stock: bundle.stock
1225 }
1226 ]
1227 }
1228 )
1229 }
1230 }
1231 })
1232 }
1233
1234 return newBundleList;
1235 },
1236 sortedPickedVariants() {
1237 return this.pickedVariants.sort((x,y) => x.bundle - y.bundle);
1238 },
1239 ga4Products() {
1240 let list = [];
1241
1242 this.sortedPickedVariants.forEach(product => {
1243 let productObject = {};
1244
1245 if(product.bundle) {
1246 productObject.item_name = this.mainProduct.name;
1247 productObject.item_id = product.bundleNo;
1248 productObject.productsInBundle = product.productsInBundle;
1249 } else {
1250 productObject.item_id = product.id,
1251 productObject.item_name = this.mainProduct.name,
1252 productObject.item_variant = product.variantId,
1253 productObject.quantity = product.qty,
1254 productObject.price = this.priceObject.unitPrice
1255 }
1256
1257 list.push(productObject)
1258 })
1259
1260 return list;
1261 },
1262 onTheWayHome() {
1263 if(this.variants.filter(x => x.stock.pieces > 0).length > 0) {
1264 return "@Translate("Translate_General_Yes")";
1265 }
1266
1267 return "@Translate("Translate_General_No")";
1268 },
1269 accessoriesList() {
1270 let list = [];
1271
1272 if(this.relatedProducts && this.relatedProducts.length > 0) {
1273 this.relatedProducts.forEach(product => {
1274 let group = this.relatedGroups.find(x => x.Id == "RELGRP1");
1275
1276 if(group && group.Products.find(x => x.ProductId == product.Id)) {
1277 list.push(product);
1278 }
1279 })
1280 }
1281
1282 return list;
1283 }
1284 },
1285 mounted() {
1286 this.getVariants(@(productNumber))
1287 @if(primaryGroup == "group1") {
1288 <text>
1289 this.lookUpBundle(@(productNumber));
1290 </text>
1291 }
1292
1293 this.getAccessories();
1294
1295 if(!this.enquireProduct && this.isLoggedIn) {
1296 this.orderButtonSpinner = setTimeout(() => {
1297 document.querySelector('#product-order-button .loader').style.display = "inline-block";
1298 }, 3000);
1299 } else {
1300 document.querySelector('#product-order-button .product-order-form-button').style.display = "block";
1301 }
1302 },
1303 data() {
1304 return {
1305 isLoggedIn: @isloggedin.ToString().ToLower(),
1306 enquireProduct: @enquireProduct.ToString().ToLower(),
1307 lang: document.querySelector('html').getAttribute('data-lang'),
1308 loading: false,
1309 loadingPrice: false,
1310 loadingBundles: false,
1311 loadingVariants: false,
1312 orderLoader: true,
1313 orderButtonSpinner: null,
1314 timeOut: null,
1315 priceObject: {
1316 unitPrice: 0,
1317 totalEx: 0,
1318 vat: 0,
1319 totalInc: 0,
1320 corePrice: 0
1321 },
1322 customerNumber: '@GetGlobalValue("Global:Extranet.CustomerNumber")',
1323 sizeUnitValues: {
1324 'ZOLL/00': '@Translate("Translate_Product_SizeUnit_Inch")',
1325 'ZOLL/01': '@Translate("Translate_Product_SizeUnit_Inch")',
1326 'FUß/00': '@Translate("Translate_Product_SizeUnit_Foot")',
1327 'FUß/01': '@Translate("Translate_Product_SizeUnit_Foot")',
1328 'MM/00': '@Translate("Translate_Product_SizeUnit_Millimeter")',
1329 'MM/01': '@Translate("Translate_Product_SizeUnit_Millimeter")'
1330 },
1331 mainProduct: {
1332 name: '@productName',
1333 id: @productNumber,
1334 number: '@Translate("Translate_Product_Page_ProductNumber"): @productNumber',
1335 dbNumber: '@GetString("Ecom:Product:Field.ProductDbNumber.Name"): @GetString("Ecom:Product:Field.ProductDbNumber.Value")',
1336 width: '@GetString("Ecom:Product:Field.ProductWidthSale.Value.Raw")',
1337 thickness: '@GetString("Ecom:Product:Field.ProductThicknessSale.Value.Raw")',
1338 image: '@GetString("Ecom:Product.ImageDefault.Clean")',
1339 size: @Json.Encode(GetString("Ecom:Product:Field.Name2")),
1340 prices: {
1341 unit: {
1342 code: "@salesUnitCode",
1343 label: "@salesUnit"
1344 },
1345 standard: @standardPriceJS,
1346 above100: @above100PriceJS,
1347 bundle: @bundlePriceJS
1348 },
1349 sizeUnits: {
1350 length: '@GetString("Ecom:Product:Field.ProductLengthUnitCode.Value")',
1351 width: '@GetString("Ecom:Product:Field.ProductWidthUnitCode.Value")',
1352 thickness: '@GetString("Ecom:Product:Field.ProductThicknessUnitCode.Value")',
1353 }
1354 },
1355 relatedGroups: null,
1356 relatedProducts: null,
1357 variants: [],
1358 showAccessories: false,
1359 showStep1: false,
1360 showBundles: false,
1361 bundles: [],
1362 pickedVariants: [],
1363 productsAdded: 0,
1364 pickedAcc: [],
1365 currentMobileProduct: '',
1366 showMobileBasket: false,
1367 showMobileActionBar: false,
1368 showMobileActionControls: false,
1369 currentActiveMobileButton: 'none',
1370 currentMobileQty: 0,
1371 toggleBundles: [],
1372 }
1373 },
1374 methods: {
1375 doesCookieExist(cookieName) {
1376 const cookies = document.cookie.split('; ');
1377 const cookieExists = cookies.some(cookie => cookie.startsWith(cookieName + '='));
1378 return cookieExists;
1379 },
1380 setCookie(name, value, days) {
1381 let expires = "";
1382 if (days) {
1383 const date = new Date();
1384 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
1385 expires = "; expires=" + date.toUTCString();
1386 }
1387 document.cookie = name + "=" + (value || "") + expires + "; path=/";
1388 },
1389 deleteCookie(name) {
1390 document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
1391 },
1392 async getAccessories() {
1393 await fetch(`/dwapi/ecommerce/products/@(productNumber)`)
1394 .then(response => response.json())
1395 .then(response => {
1396 this.relatedGroups = response.RelatedGroups;
1397 })
1398
1399 await fetch(`/dwapi/ecommerce/products/@(productNumber)/related`)
1400 .then(response => response.json())
1401 .then(response => {
1402 if(response.TotalProductsCount > 0) {
1403 this.relatedProducts = response.Products;
1404 }
1405 })
1406 .catch(error => {
1407 console.log(error)
1408 })
1409 },
1410 getVariants: async function(productNo, url) {
1411 this.loadingVariants = true;
1412 let requestUrl = `@(VariantsLookup)&ICC_itemId=${productNo}`;
1413
1414 if(url && url != "") {
1415 requestUrl = url;
1416 }
1417
1418 if(!this.isLoggedIn) {
1419 if(requestUrl.indexOf('username') < 0) {
1420 requestUrl += '&username=marketing@keflico.com&password=K123456';
1421 }
1422
1423 if (!this.doesCookieExist('tempLogin')) {
1424 this.setCookie('tempLogin', true, 1);
1425 }
1426 }
1427
1428 let credentials = this.isLoggedIn ? "same-origin" : "omit"
1429
1430 fetch(requestUrl, {
1431 credentials: credentials
1432 })
1433 .then(response => response.json())
1434 .then(response => {
1435 if(response.variants && response.variants.length > 0) {
1436 this.variants = this.variants.concat(response.variants);
1437
1438 this.orderLoader = false;
1439
1440 if(response.nextPage != "") {
1441 this.getVariants(productNo, response.nextPage);
1442 } else {
1443 this.loadingVariants = false;
1444
1445 if(!this.isLoggedIn) {
1446 fetch('/Admin/Public/ExtranetLogoff.aspx');
1447 }
1448 }
1449 } else {
1450 this.loadingVariants = false;
1451
1452 if(!this.loadingBundles) {
1453 clearTimeout(this.orderButtonSpinner);
1454 document.querySelector('#product-order-button .product-order-form-button').style.display = "block";
1455 document.querySelector('#product-order-button .loader').style.display = "none";
1456 }
1457 }
1458 })
1459 },
1460 lookUpBundle: async function(productNo, url) {
1461 this.loadingBundles = true;
1462 let requestUrl = `@(BundleLookup)&ICC_itemId=${productNo}`;
1463
1464 if(url && url != "") {
1465 requestUrl = url;
1466 }
1467
1468 if(!this.isLoggedIn) {
1469 if(requestUrl.indexOf('username') < 0) {
1470 requestUrl += '&username=marketing@keflico.com&password=K123456';
1471 }
1472
1473 if (!this.doesCookieExist('tempLogin')) {
1474 this.setCookie('tempLogin', true, 1);
1475 }
1476 }
1477
1478 let credentials = this.isLoggedIn ? "same-origin" : "omit"
1479
1480 fetch(requestUrl, {
1481 credentials: credentials
1482 })
1483 .then(response => response.json())
1484 .then(response => {
1485 if(response.bundles && response.bundles.length > 0) {
1486
1487 if(response.currentPage = 1) {
1488 this.showBundles = true;
1489 }
1490
1491 this.orderLoader = false;
1492 } else {
1493 if(!this.loadingVariants) {
1494 clearTimeout(this.orderButtonSpinner);
1495 document.querySelector('#product-order-button .product-order-form-button').style.display = "block";
1496 document.querySelector('#product-order-button .loader').style.display = "none";
1497 }
1498 }
1499
1500 this.bundles = this.bundles.concat(response.bundles);
1501
1502 if(response.nextPage != "") {
1503 this.lookUpBundle(productNo, response.nextPage);
1504 } else {
1505 this.loadingBundles = false;
1506
1507 if(!this.isLoggedIn) {
1508 fetch('/Admin/Public/ExtranetLogoff.aspx');
1509 }
1510 }
1511 })
1512 },
1513 tempPriceUpdate() {
1514 let totalAccPrice = 0;
1515
1516 this.pickedAcc.forEach(acc => {
1517 totalAccPrice += parseFloat(acc.price.exVat.replace(',', ''))
1518 })
1519
1520 this.priceObject.totalEx = parseFloat(this.priceObject.corePrice) + totalAccPrice;
1521 this.priceObject.vat = parseFloat(this.priceObject.totalEx) * 0.25;
1522 this.priceObject.totalInc = parseFloat(this.priceObject.totalEx) * 1.25;
1523 },
1524 priceLookUp: async function() {
1525 let x = 1;
1526 let y = 1;
1527 let queryString = "&ICC_userId=" + this.customerNumber + "&ICC_itemId=" + this.mainProduct.id;
1528
1529 this.pickedVariants.forEach(variant => {
1530 if(variant.bundle) {
1531 queryString += "&ICC_bundle" + y + "=" + variant.bundleNo;
1532
1533 y++;
1534 } else {
1535 queryString += "&ICC_variant" + x + "=" + variant.id;
1536 queryString += "&ICC_quantity" + x + "=" + variant.qty;
1537
1538 x++;
1539 }
1540 })
1541
1542 fetch(`@(PriceLookup)${queryString}`)
1543 .then(response => response.json())
1544 .then(response => {
1545 this.priceObject.corePrice = parseFloat(response.totalPriceWithoutVat.replace(",", ""));
1546 this.priceObject.unitPrice = response.unitPrice;
1547 this.priceObject.totalEx = response.totalPriceWithoutVat;
1548 this.priceObject.vat = response.vat;
1549 this.priceObject.totalInc = response.totalPriceWithVat;
1550
1551 this.loadingPrice = false;
1552 })
1553 },
1554 toggleBundle(bundleNo) {
1555 this.toggleBundles.find(x => x.bundle == bundleNo).expanded = !this.toggleBundles.find(x => x.bundle == bundleNo).expanded;
1556 },
1557 isExpanded(bundleNo) {
1558 return this.toggleBundles.find(x => x.bundle == bundleNo).expanded;
1559 },
1560 getQty(variantId) {
1561 let product = this.pickedVariants.find(x => x.id == variantId || x.bundleNo == variantId);
1562 let acc = this.pickedAcc.find(x => x.id == variantId);
1563
1564 if(product || acc) {
1565 if(product) {
1566 if(product.bundle) {
1567 return 1;
1568 }
1569
1570 return product.qty;
1571 } else {
1572 return acc.qty;
1573 }
1574 } else {
1575 return 0;
1576 }
1577 },
1578 toggleBar(productId) {
1579 let product = this.accessoriesList.find(x => x.Id == productId); // product is acc
1580
1581 if((product && product.Price.Price && product.Price.Price > 0 && !product.VariantInfo.VariantInfo) || !product) {
1582 if(this.currentMobileProduct != productId) {
1583 this.currentMobileProduct = productId;
1584 this.showMobileActionBar = true;
1585 this.showMobileActionControls = true;
1586
1587 if(this.pickedVariants.find(x => x.id == productId)) {
1588 this.currentActiveMobileButton = 'update';
1589 this.currentMobileQty = this.pickedVariants.find(x => x.id == productId).qty;
1590 } else if(this.pickedAcc.find(x => x.id == productId)) {
1591 this.currentActiveMobileButton = 'update';
1592 this.currentMobileQty = this.pickedAcc.find(x => x.id == productId).qty;
1593 } else {
1594 this.currentActiveMobileButton = 'add';
1595 this.currentMobileQty = 0;
1596 }
1597 } else {
1598 this.currentMobileProduct = '';
1599 this.showMobileActionControls = false;
1600
1601 if(this.pickedVariants.length == 0) {
1602 this.showMobileActionBar = false;
1603 }
1604
1605 if(this.showAccessories || this.accessoriesList.length == 0) {
1606 this.currentActiveMobileButton = 'order';
1607 } else {
1608 this.currentActiveMobileButton = 'next';
1609 }
1610 }
1611 }
1612 },
1613 addToTempCart(amount, id) {
1614 this.loadingPrice = true;
1615 clearTimeout(this.timeOut);
1616
1617 if(this.pickedVariants.filter(x => x.id == id).length > 0) {
1618 if(amount > 0) {
1619 this.pickedVariants.find(x => x.id == id).qty = amount;
1620 } else {
1621 const index = this.pickedVariants.findIndex(x => x.id == id);
1622 this.pickedVariants.splice(index, 1);
1623 }
1624 } else {
1625 if(amount > 0) {
1626 const data = this.sortedVariants.find(x => x.id == id);
1627
1628 this.pickedVariants.push({
1629 bundle: false,
1630 id: id,
1631 qty: parseInt(amount),
1632 length: data.size.length,
1633 width: data.size.width,
1634 thickness: data.size.thickness,
1635 variantId: data.id
1636 });
1637 }
1638 }
1639
1640 if(this.pickedVariants.length > 0) {
1641 this.timeOut = setTimeout(() => {
1642 this.priceLookUp();
1643 }, 1000);
1644 } else {
1645 this.priceObject.totalEx = 0;
1646 this.priceObject.totalInc = 0;
1647 this.priceObject.vat = 0;
1648 this.priceObject.unitPrice = 0;
1649
1650 this.loadingPrice = false;
1651 }
1652 },
1653 editMobileQty($event) {
1654 this.currentMobileQty = $event.target.value
1655 },
1656 updateMobileBasket() {
1657 let productToUpdate = this.sortedVariants.find(x => x.id == this.currentMobileProduct);
1658
1659 if(!productToUpdate) {
1660 productToUpdate = this.sortedBundles.find(x => x.bundleNo == this.currentMobileProduct);
1661 }
1662
1663 if(productToUpdate) {
1664 if(productToUpdate.bundleNo) {
1665 this.addBundleToTempCart(1, this.currentMobileProduct);
1666 } else {
1667 this.addToTempCart(this.currentMobileQty, this.currentMobileProduct);
1668 }
1669
1670 this.showMobileActionControls = false;
1671 this.currentMobileProduct = '';
1672
1673 if(this.accessoriesList.length == 0) {
1674 this.currentActiveMobileButton = 'order';
1675 } else {
1676 this.currentActiveMobileButton = 'next';
1677 }
1678 } else {
1679 productToUpdate = this.accessoriesList.find(x => x.id == this.currentMobileProduct);
1680
1681 this.addAcc(this.currentMobileQty, this.currentMobileProduct);
1682
1683 this.showMobileActionControls = false;
1684 this.currentMobileProduct = '';
1685 this.currentActiveMobileButton = 'order';
1686 }
1687 },
1688 addBundleToTempCart(amount, bundleNo) {
1689 this.loadingPrice = true;
1690 clearTimeout(this.timeOut);
1691
1692 if(amount > 0) {
1693 this.pickedVariants.push({
1694 bundle: true,
1695 bundleNo: bundleNo,
1696 productsInBundle: this.sortedBundles.filter(x => x.bundleNo == bundleNo)[0].productsInBundle
1697 })
1698 } else {
1699 const index = this.pickedVariants.findIndex(x => x.bundleNo == bundleNo);
1700 this.pickedVariants.splice(index, 1);
1701 }
1702
1703 if(this.pickedVariants.length > 0) {
1704 this.timeOut = setTimeout(() => {
1705 this.priceLookUp();
1706 }, 1000);
1707 } else {
1708 this.priceObject.totalEx = 0;
1709 this.priceObject.totalInc = 0;
1710 this.priceObject.vat = 0;
1711 this.priceObject.unitPrice = 0;
1712
1713 this.loadingPrice = false;
1714 }
1715 },
1716 updateAccButton(amount, productNumber) {
1717 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)) {
1718 this.$refs['confirmBtn' + productNumber][0].classList.remove('disabled')
1719 } else {
1720 this.$refs['confirmBtn' + productNumber][0].classList.add('disabled')
1721 }
1722 },
1723 addAcc(event, productNumber) {
1724 let product = this.pickedAcc.find(x => x.id == productNumber);
1725 let qty = typeof event == 'number' ? event : this.$refs['accCounter' + productNumber][0].value;
1726
1727 let queryString = `&ICC_userId=${this.customerNumber}&ICC_itemId=${productNumber}&ICC_quantity1=`;
1728
1729 if(product) {
1730 if(qty > 0) {
1731 product.qty = qty;
1732 queryString += product.qty;
1733 } else {
1734 this.pickedAcc.splice(this.pickedAcc.findIndex(x => x.id == product.id), 1);
1735 }
1736 } else {
1737 this.pickedAcc.push({
1738 id: productNumber,
1739 name: this.accessoriesList.find(x => x.Number == productNumber).Name,
1740 name2: this.accessoriesList.find(x => x.Number == productNumber).ProductFields.Name2.Value,
1741 qty: qty,
1742 price: {
1743 exVat: 0,
1744 vat: 0,
1745 withVat: 0,
1746 unitPrice: 0
1747 }
1748 })
1749
1750 queryString += qty;
1751 }
1752
1753 if(qty > 0) {
1754 fetch(`/Default.aspx?ID=1115${queryString}`)
1755 .then(response => response.json())
1756 .then(response => {
1757 if(product) {
1758 product.price.exVat = response.totalPriceWithoutVat;
1759 product.price.vat = response.vat;
1760 product.price.withVat = response.totalPriceWithVat;
1761 product.price.unitPrice = response.unitPrice;
1762 } else {
1763 const newProduct = this.pickedAcc.at(-1);
1764
1765 newProduct.price.exVat = response.totalPriceWithoutVat;
1766 newProduct.price.vat = response.vat;
1767 newProduct.price.withVat = response.totalPriceWithVat;
1768 newProduct.price.unitPrice = response.unitPrice;
1769 }
1770
1771 this.tempPriceUpdate();
1772 })
1773 } else {
1774 this.tempPriceUpdate();
1775 }
1776
1777 this.$refs['confirmBtn' + productNumber][0].classList.add('disabled');
1778 },
1779 prettyNumber(number, minDigits) {
1780 return parseFloat(number).toLocaleString(this.lang, { minimumFractionDigits: minDigits ? minDigits : 0 })
1781 },
1782 prettyPrice(price) {
1783 let rawPrice = price;
1784
1785 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))) {
1786 // Price is over 1000 in danish format
1787
1788 rawPrice = rawPrice.replaceAll(".", "");
1789 rawPrice = rawPrice.replaceAll(",", ".");
1790 } 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))) {
1791 // Price is over 1000 in english format
1792
1793 rawPrice = rawPrice.replaceAll(",", "");
1794 }
1795
1796 rawPrice = parseFloat(rawPrice);
1797 return rawPrice.toLocaleString(this.lang, { minimumFractionDigits: 2, maximumFractionDigits: 2 } )
1798 },
1799 calculateStockLevel(stock) {
1800 if(this.isLoggedIn && stock >= 0) {
1801 return stock > 500 ? '+500' : stock;
1802 } else {
1803 return stock > 100 ? '+100' : stock;
1804 }
1805
1806 return 0;
1807 },
1808 toggleState($event) {
1809 $event.target.closest('.side-basket__product').classList.toggle('closed');
1810 },
1811 openForm(e) {
1812 document.querySelector('.product-modal').classList.remove('js-slide-in');
1813
1814 const toggleTrigger = e.currentTarget;
1815 const target = document.querySelector(toggleTrigger.getAttribute('data-target'));
1816
1817 if (target) {
1818 disableScrollLock()
1819 history.back();
1820
1821 if (!target.classList.contains('js-open')) {
1822 toggleTrigger.classList.add('js-open');
1823 target.classList.add('js-open');
1824 target.style.height = `${target.scrollHeight}px`;
1825
1826 if (toggleTrigger.getAttribute('data-action-scroll') != 'no-scroll') {
1827 setTimeout(function() {
1828 target.scrollIntoView({behavior: 'smooth'});
1829 },300);
1830 }
1831
1832 if (target.classList.contains('dialog')) {
1833 document.querySelector('body').style.overflow = 'hidden';
1834 }
1835 } else {
1836 toggleTrigger.classList.remove('js-open');
1837 target.classList.remove('js-open');
1838 target.style.height = null;
1839
1840 if (target.classList.contains('dialog')) {
1841 document.querySelector('body').style.overflow = null;
1842 }
1843 }
1844 }
1845 },
1846 calculateMeters() {
1847 let meters = 0;
1848
1849 this.pickedVariants.forEach(variant => {
1850 let length = variant['length'];
1851
1852 if(this.mainProduct.sizeUnits.length.indexOf('FUß') > -1) {
1853 length = length * 304.8;
1854 }
1855
1856 let variantMeters = parseFloat(length) * variant.qty / 1000;
1857 meters += variantMeters;
1858 })
1859
1860 return parseFloat(meters).toFixed(3);
1861 },
1862 calculatePieces() {
1863 let pieces = 0;
1864
1865 this.pickedVariants.forEach(variant => {
1866 if(variant.bundle) {
1867 variant.productsInBundle.forEach(product => {
1868 pieces += parseInt(product.stock.units);
1869 })
1870 } else {
1871 pieces += parseInt(variant.qty);
1872 }
1873 });
1874
1875 return pieces;
1876 },
1877 calculateSquareMeters() {
1878 return parseFloat(this.calculateMeters() * (this.mainProduct.width / 1000)).toFixed(3);
1879 },
1880 calculateCubicMeters() {
1881 let cubicMeters = 0;
1882
1883 this.pickedVariants.forEach(variant => {
1884 let variantMeters = 0;
1885
1886 let lengthMultiplier = 1;
1887 let widthMultiplier = 1;
1888 let thicknessMultiplier = 1;
1889
1890 if(this.mainProduct.sizeUnits.length.indexOf('FUß') > -1) {
1891 lengthMultiplier = 304.79999025;
1892 }
1893
1894 if(this.mainProduct.sizeUnits.width.indexOf('ZOLL') > -1) {
1895 widthMultiplier = 25.39998628;
1896 }
1897
1898 if(this.mainProduct.sizeUnits.thickness.indexOf('ZOLL') > -1) {
1899 thicknessMultiplier = 25.39998628
1900 }
1901
1902 if(variant.bundle) {
1903 variant.productsInBundle.forEach(product => {
1904 variantMeters += (parseFloat(product.length.replace(",", "") * lengthMultiplier / 1000) * parseFloat(product.thickness * thicknessMultiplier / 1000) * parseFloat(product.width * widthMultiplier) / 1000) * parseInt(product.stock.units);
1905 })
1906 } else {
1907 variantMeters += (parseFloat(variant['length'] / 1000) * parseFloat(variant['thickness'] / 1000) * parseFloat(variant['width']) / 1000) * variant.qty;
1908 }
1909
1910 cubicMeters += variantMeters;
1911 })
1912
1913 return cubicMeters;
1914 },
1915 calculateCubicFeet() {
1916 let cubicFeet = 0;
1917
1918 this.pickedVariants.forEach(variant => {
1919 let variantMeters = 0;
1920
1921 let lengthMultiplier = 1;
1922 let widthMultiplier = 1;
1923 let thicknessMultiplier = 1;
1924
1925 if(this.mainProduct.sizeUnits.length.indexOf('FUß') > -1) {
1926 lengthMultiplier = 304.79999025;
1927 }
1928
1929 if(this.mainProduct.sizeUnits.width.indexOf('ZOLL') > -1) {
1930 widthMultiplier = 25.39998628;
1931 }
1932
1933 if(this.mainProduct.sizeUnits.thickness.indexOf('ZOLL') > -1) {
1934 thicknessMultiplier = 25.39998628
1935 }
1936
1937 if(variant.bundle) {
1938 variant.productsInBundle.forEach(product => {
1939 let lengthMM = product.length.replace(",", "") * lengthMultiplier;
1940 let lengthM = lengthMM / 1000;
1941 let widthMM = product.width * widthMultiplier;
1942 let widthM = widthMM / 1000;
1943 let thicknessMM = product.thickness * thicknessMultiplier;
1944 let thicknessM = thicknessMM / 1000;
1945
1946 variantMeters += Number(parseFloat(lengthM * widthM * thicknessM * 35.32 * product.stock.units))
1947 })
1948 } else {
1949 variantMeters += ((parseFloat(variant['length'] * lengthMultiplier / 1000) * parseFloat(variant['thickness'] * thicknessMultiplier / 1000) * parseFloat(variant['width'] * widthMultiplier / 1000)) * variant.qty);
1950 }
1951
1952 cubicFeet += Number(variantMeters);
1953 })
1954
1955 return Number(cubicFeet).toFixed(2);
1956 },
1957 calculateTotalQTY() {
1958 let qty = 0;
1959
1960 this.pickedVariants.forEach(variant => {
1961 qty += variant.qty;
1962 });
1963
1964 return qty;
1965 },
1966 resetBasket() {
1967 this.showAccessories = false;
1968 this.pickedVariants = [];
1969 this.showStep1 = true;
1970 this.pickedAcc = [];
1971 this.priceObject.unitPrice = 0;
1972 this.priceObject.totalEx = 0;
1973 this.priceObject.vat = 0;
1974 this.priceObject.totalInc = 0;
1975 this.priceObject.corePrice = 0;
1976
1977 Array.from(this.$refs.counter).forEach(counter => {
1978 counter.value = 0;
1979 });
1980 },
1981 async addToBasket() {
1982 this.loading = true;
1983 var params = new FormData();
1984
1985 params.append('CartCmd', "addMulti")
1986
1987 this.pickedVariants.forEach((variant, index) => {
1988 var productLoopCounter = index + 1;
1989
1990 if(variant.bundle) {
1991 params.append('ProductLoopCounter' + productLoopCounter, productLoopCounter);
1992 params.append('ProductID' + productLoopCounter, this.mainProduct.id);
1993 params.append('Quantity' + productLoopCounter, 1);
1994 params.append('EcomOrderLineFieldInput_BundleNo' + productLoopCounter, variant.bundleNo);
1995 } else {
1996 params.append('ProductLoopCounter' + productLoopCounter, productLoopCounter);
1997 params.append('ProductID' + productLoopCounter, this.mainProduct.id);
1998 params.append('VariantID' + productLoopCounter, variant.variantId);
1999 params.append('Quantity' + productLoopCounter, parseInt(variant.qty));
2000 }
2001 })
2002 const config = {
2003 method: 'POST',
2004 body: params
2005 }
2006
2007 this.productsAdded = this.pickedVariants.length;
2008
2009 const response = await fetch('@formAction' + '&redirect=false', config)
2010
2011 if (response.ok) {
2012 dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.
2013 dataLayer.push({
2014 event: "add_to_cart",
2015 ecommerce: {
2016 currency: "@GetString("Ecom:Product.Currency.Code")",
2017 value: this.priceObject.totalEx,
2018 items: this.ga4Products
2019 }
2020 });
2021
2022 if(this.accessoriesList.length > 0) {
2023 this.showAccessories = true;
2024 this.loading = false;
2025 this.currentActiveMobileButton = 'order';
2026 } else {
2027 window.location.href = "@formAction";
2028 }
2029
2030 showStep1 = false;
2031 } else {
2032 console.log(response)
2033 }
2034 },
2035 async addAccToBasket() {
2036 this.loading = true;
2037 var params = new FormData();
2038
2039 params.append('CartCmd', "addMulti")
2040
2041 this.pickedAcc.forEach((variant, index) => {
2042 var productLoopCounter = index + 1;
2043
2044 params.append('ProductLoopCounter' + productLoopCounter, productLoopCounter);
2045 params.append('ProductID' + productLoopCounter, variant.id);
2046 params.append('Quantity' + productLoopCounter, variant.qty);
2047 })
2048 const config = {
2049 method: 'POST',
2050 body: params
2051 }
2052
2053 const response = await fetch('@formAction' + '&redirect=false', config)
2054
2055 if (response.ok) {
2056 window.location.href = "@formAction";
2057 } else {
2058 console.log(response)
2059 }
2060 }
2061 },
2062 watch: {
2063 orderLoader(newValue, oldValue) {
2064 if(!newValue && !this.enquireProduct && this.isLoggedIn) {
2065 clearTimeout(this.orderButtonSpinner);
2066 document.querySelector('#product-order-button .product-order-button').style.display = "block";
2067 document.querySelector('#product-order-button .loader').style.display = "none";
2068 }
2069 }
2070 }
2071 });
2072 </script>
2073 @SnippetEnd("JavaScripts")
2074 }
2075
2076 @functions {
2077 private string GetFileIcon(string fileUrl)
2078 {
2079 string extension = Path.GetExtension(fileUrl)?.ToLower();
2080
2081 if (string.IsNullOrEmpty(extension))
2082 return System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/file.svg"));
2083
2084 switch (extension)
2085 {
2086 case ".pdf":
2087 return System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/file.svg"));
2088 case ".jpg":
2089 case ".jpeg":
2090 case ".png":
2091 case ".gif":
2092 case ".webp":
2093 return @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/image.svg"));
2094 default:
2095 return System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/file.svg"));
2096 }
2097 }
2098
2099 public List<string> GetFilters(string GroupId)
2100 {
2101 List<string> filters = new List<string>();
2102
2103 switch (GroupId)
2104 {
2105 case "group1":
2106 filters.Add("10");
2107 filters.Add("11");
2108 break;
2109 case "group32":
2110 filters.Add("17");
2111 break;
2112 case "group52":
2113 filters.Add("12");
2114 filters.Add("13");
2115 filters.Add("14");
2116 filters.Add("16");
2117 break;
2118 case "group53":
2119 filters.Add("14");
2120 break;
2121 case "group56":
2122 filters.Add("16");
2123 break;
2124 case "group61":
2125 case "group67":
2126 filters.Add("12");
2127 break;
2128 case "group63":
2129 filters.Add("13");
2130 break;
2131 case "group73":
2132 filters.Add("18");
2133 break;
2134 case "group129":
2135 filters.Add("6");
2136 break;
2137 default:
2138 filters.Add("");
2139 break;
2140 }
2141
2142 return filters;
2143 }
2144
2145 public string BuildFilterString(string group) {
2146 string filter = "";
2147 List<string> ids = GetFilters(group);
2148
2149 if(group == "group126") {
2150
2151 } else if(group == "group129") {
2152 foreach(var id in ids) {
2153 filter += filter == "" ? "Types contains \""+id+"\"" : " or Types contains \""+id+"\"";
2154 }
2155 } else {
2156 foreach(var id in ids) {
2157 filter += filter == "" ? "WoodTypes contains \""+id+"\"" : " or WoodTypes contains \""+id+"\"";
2158 }
2159 }
2160
2161 return filter;
2162 }
2163 }