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