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