Error executing template "Designs/Tapas/eCom/Productlist/productlist_Default.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
at CompiledRazorTemplates.Dynamic.RazorEngine_3fcd0d9c23bd475da98ec1b05ce71e63.<>c__DisplayClass16_0.<RenderGroupLevelFilter>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\millarco.staging\Files\Templates\Designs\Tapas\eCom\Productlist\productlist_Default.cshtml:line 1110
at CompiledRazorTemplates.Dynamic.RazorEngine_3fcd0d9c23bd475da98ec1b05ce71e63.<>c__DisplayClass16_0.<RenderGroupLevelFilter>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\millarco.staging\Files\Templates\Designs\Tapas\eCom\Productlist\productlist_Default.cshtml:line 1142
at CompiledRazorTemplates.Dynamic.RazorEngine_3fcd0d9c23bd475da98ec1b05ce71e63.Execute() in D:\dynamicweb.net\Solutions\millarco.staging\Files\Templates\Designs\Tapas\eCom\Productlist\productlist_Default.cshtml:line 674
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 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
2 @using Dynamicweb.Rendering;
3 @using Dynamicweb.Environment;
4
5 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
6 @using Dynamicweb.Rendering;
7 @using System.Text.RegularExpressions;
8
9
10
11 @helper renderProduct(bool showShopFunctionsAlternativeIfNotLoggedIn, LoopItem product, bool renderAs4Cols = false)
12 {
13
14 string productID = product.GetString("Ecom:Product.ID");
15 string productNumber = product.GetString("Ecom:Product.Number");
16 string mainProductID = product.GetString("Ecom:Product:Field.FirstwebMainProductID");
17 string PrimaryProductPageId = Firstweb.Custom.CustomCode.Tapas.Context.AreaPages.GetPageId("productcatalog");
18
19 string productLink = product.GetString("Ecom:Product.Link.Clean");
20
21 if (!String.IsNullOrEmpty(PrimaryProductPageId))
22 {
23 productLink = "/Default.aspx?id=" + PrimaryProductPageId + "&productid=" + productID;
24 }
25
26 string languageId = product.GetString("Ecom:Product.LanguageID");
27 string variantId = product.GetString("Ecom:Product.VariantID");
28
29 string productName = product.GetString("Ecom:Product.Name");
30 string productShortDescription = product.GetString("Ecom:Product.ShortDescription");
31
32 string nettoPrice = product.GetString("Firstweb:ErpPriceInfo.NettoPriceFormatted");
33 int bruttoPrice = product.GetInteger("Firstweb:ErpPriceInfo.BruttoAmountFormattedNoSymbol");
34
35 string availableAmount = product.GetString("Firstweb:ErpStockInfo.StockQuantity");
36 string stockColor = product.GetString("Firstweb:ErpStockInfo.StockColor");
37 bool priceAndStockFound = product.GetBoolean("Firstweb:ErpPriceInfo.PriceAndStockFound");
38 bool priceFound = product.GetBoolean("Firstweb:ErpPriceInfo.PriceFound");
39 bool hasQuantityPrices = product.GetBoolean("Firstweb:ErpPriceInfo.HasQuantityPrices");
40 string RRPrice = product.GetString("Firstweb:ErpPriceInfo:Prices.RRPFormatted");
41 string OutletPrice = product.GetString("Firstweb:ErpPriceInfo.NettoPriceFormatted");
42
43 int productPackagingQuantity = product.GetInteger("Firstweb:ErpPriceInfo:ExtraInfos.PackagingSize");
44 int defaultQuantity = productPackagingQuantity > 0 ? productPackagingQuantity : 1;
45
46
47 bool hasVariants = (product.GetLoop("VariantCombinations").Count() > 0);
48
49 //Images
50 List<Dynamicweb.Ecommerce.Products.Detail> productImages = Firstweb.Custom.CustomCode.Frontend.Helpers.ProductImages.GetProductImages(languageId, productID, variantId);
51 Dynamicweb.Ecommerce.Products.Detail primaryProductImage = productImages.FirstOrDefault(x=>x.IsDefault); //Tag you can use instead: product.GetString("Ecom:Product.ImageDefault.Clean");
52 //check for valid default image
53 if (primaryProductImage == null)
54 {
55 primaryProductImage = new Dynamicweb.Ecommerce.Products.Detail { Value = "" };
56 }
57 else if (primaryProductImage.Value == null)
58 {
59 primaryProductImage.Value = "";
60 }
61
62 //Sorted: first by imagegroup then by sortorder
63 //@foreach (var productImage in productImages)
64 //{
65 //productImage.Value; //This is the imagepath eks. /Images/products/R12155_10_2.jpg
66 //productImage.IsDefault; //If the image is default or not.
67 //}
68
69 string primaryProductImageUrl = "/admin/public/getimage.ashx?image=" + primaryProductImage.Value + "&altFmImage_path=/Files/Images/ecom/Products/no-image.jpg&width=250&height=150&Compression=90&Crop=5";
70 if (String.IsNullOrEmpty(primaryProductImage.Value))
71 {
72 primaryProductImageUrl = "/admin/public/getimage.ashx?image=/Files/Images/ecom/Products/no-image.jpg&width=250&height=150&Compression=90&Crop=5";
73 }
74
75 //Other packagings
76 var otherPackagingProducts = Firstweb.Custom.CustomCode.Frontend.Helpers.OtherPackagingProducts.GetOtherPackagingProducts(mainProductID, false).Where(i => i.Id != productID);
77 var showOtherPackagingProducts = otherPackagingProducts.Count() > 0;
78
79
80 //Customer product number
81 //string customerProductNumber = Firstweb.Custom.CustomCode.Frontend.Helpers.CustomerProductNumbers.GetCustomerProductNumber(productID);
82
83 //OrderTemplate
84 int productInFavoritLists = product.GetInteger("Firstweb:Ecom:Product:OrderTemplate.InTemplates.Count");
85
86 string orderLineId = product.GetString("Firstweb:OrderTemplate:Line.ID");
87 string orderTemplateId = product.GetString("Firstweb:OrderTemplate:Line.OrderTemplateID");
88 int orderLineQuantity = product.GetInteger("Firstweb:OrderTemplate:Line.Quantity");
89
90 bool inFavourite = productInFavoritLists > 0 ? true : false;
91 string inFavouriteBoolJS = inFavourite.ToString().ToLower();
92
93 bool isOrderTemplate = !String.IsNullOrEmpty(orderLineId);
94
95 string productPriceCacheKey = orderLineId != "" ? orderLineId : productNumber;
96
97
98
99
100 string stock = "";
101
102 string addBorderCss = isOrderTemplate ? "border-1" : "";
103
104
105 if (!priceAndStockFound)
106 {
107 stock = "asyncLoad";
108 }
109 else
110 {
111 stock = availableAmount;
112 }
113
114 string WidthClass = renderAs4Cols ? "col-md-4 col-lg-3" : "col-md-4";
115 bool ShowShopFunctions = Firstweb.Custom.CustomCode.Tapas.Context.Current.ShopFunctionsVisibility.ShowShopFunctions();
116 string BrandLogo = "/admin/public/getimage.ashx?image=" + product.GetString("Ecom:Product:Field.FirstwebBrandLogo.Value.FullPath") + "&height=25&crop=5";
117 string BrandName = product.GetString("Ecom:Product:Field.FirstwebBrand.Value.Clean");
118 string AddingToCartText = Translate("Product.AddingToCart", "Tilføjer produkt");
119 string PickListText = Translate("Ordertemplate.SelectList", "Vælg en liste");
120 bool IsOutletShop = Firstweb.Custom.CustomCode.Frontend.Helpers.Millarco.IsOutletShop();
121
122
123 <!-- ko viewModel: 'ProductViewModel'-->
124 <!-- ko initValue: {observable: ProductId, value:'@productID'}--><!-- /ko-->
125 <div class="col-xs-12 col-sm-6 @WidthClass price xs-m-b-2 asyncLoad" data-productid="@productNumber" data-productkey="@productPriceCacheKey" data-test="@PrimaryProductPageId">
126 <div class="product-list-item bg-white">
127 <a href="@productLink">
128 <div class="brand-image">
129 @if (!String.IsNullOrEmpty(product.GetString("Ecom:Product:Field.FirstwebBrandLogo.Value.FullPath")))
130 {
131 <img src="@BrandLogo" alt="@BrandName" />
132 }
133 </div>
134 <div class="product-image">
135 <img src="@primaryProductImageUrl" alt="@productName" />
136 </div>
137 <div class="product-info">
138 <p class="product-number">@Translate("Product.NumberShort", "Varenr.") @productNumber</p>
139 <p class="product-name">@productName</p>
140 </div>
141 @if (ShowShopFunctions && !IsOutletShop)
142 {
143 <p class="product-price">
144 <span class="wave">
145 <span class="dot"></span>
146 <span class="dot"></span>
147 <span class="dot"></span>
148 </span>
149 <span class="price-load-async"></span>
150 </p>
151 <p class="unit-price">@Translate("Product.PricePer", "Pris pr.") <span class="js-unit-size"></span> @Translate("Product.Unit", "stk.")</p>
152 }
153 else if (IsOutletShop)
154 {
155 <p class="product-price">
156 @nettoPrice
157 </p>
158 }
159 else if (ShowShopFunctions)
160 {
161 <p class="product-price">
162 @RRPrice
163 </p>
164 }
165 </a>
166 @if (ShowShopFunctions)
167 {
168 <div class="add-to-cart-area">
169 @if (isOrderTemplate)
170 {
171 <!-- ko initValue: {observable: Quantity, value:@orderLineQuantity}--><!-- /ko-->
172 }
173 else
174 {
175 <!-- ko initValue: {observable: Quantity, value:@defaultQuantity}--><!-- /ko-->
176 }
177 <input class="product-quantity js-product-quantity hide" type="number" name="quantity" data-bind="value: Quantity" />
178 <div class="btn btn-primary green js-product-buy-btn hide"
179 data-bind="click: function() { $parent.addItemToCart(ProductId(), Quantity(), '', '', '@AddingToCartText') }"
180 data-productid="@productID">
181 @Translate("Product.AddToCart", "TILFØJ TIL KURV")
182 </div>
183 <div class="not-in-stock-indicator js-not-in-stock-indicator width-100 is-centered hide">
184 <p>@Translate("Product.NotInStock", "Ikke på lager")</p>
185 </div>
186 @if (!isOrderTemplate)
187 {
188 <div class="favorite-list-icon" data-toggle="modal" data-target="#modal-@productID" data-bind="with: OrderTemplateViewModel">
189 <i class="fas fa-heart" data-bind="
190 oninit: function() { IsInFavoriteList('@inFavourite'.toLowerCase()) },
191 css : { showFavorite : ShowOrderTemplateDialog, showNewList : OrderTemplateShowNewList, active: IsInFavoriteList() == 'true' },
192 visible: $root.User().IsLoggedIn(),
193 click: ToggleOrderTemplateDialog">
194 </i>
195 </div>
196 <div class="modal fade" id="modal-@productID" tabindex="-1" role="dialog" data-bind="with: OrderTemplateViewModel">
197 <!-- ko initValue: {observable: OrderTemplateRelationCount, value:'@productInFavoritLists'}--><!-- /ko-->
198 <!-- ko initValue: {observable: ShowInFavourite, value: @inFavouriteBoolJS}--><!-- /ko-->
199 <!-- ko initValue: {observable: ModalSelector, value: '#modal-@productID'}--><!-- /ko-->
200 <div class="modal-dialog" role="document">
201 <div class="modal-content fav-list">
202
203 <p class="favlist-header">@Translate("Ordertemplate.AddToExistingList", "Tilføj til eksisterende favoritliste")</p>
204
205 <div class="existing-lists">
206
207 <select class="favField select-fix"
208 data-bind="options: OrderTemplateList,
209 optionsCaption: '@PickListText',
210 optionsText: function(item) { return item.Value.Name() + ' (' + item.Value.Count() + ')' },
211 value: OrderTemplateSelectedList"></select>
212
213 <input class="product-quantity" type="number" name="quantity" data-bind="textInput: OrderTemplateQuantity" />
214
215 <div class="btn btn-primary"
216 data-bind="click: function() {
217 OrderTemplateShowNewList()
218 ? CreateNewOrderTemplateList('@productID')
219 : AddProductToOrderTemplate('@productID' , OrderTemplateQuantity())
220 }">
221 @Translate("Ordertemplate.AddToList", "Tilføj")
222 </div>
223
224 </div>
225
226 <p class="or-text">@Translate("Ordertemplate.OrNewList", "eller...")</p>
227
228 <p class="favlist-header">@Translate("Ordertemplate.AddToNewList", "Tilføj til ny favoritliste")</p>
229
230 <form id="EditForm-@productID"
231 name="EditForm">
232 <label class="xs-m-b-1" for="name">@Translate("Ordertemplate.ListName", "Favoritliste navn")</label>
233 <div class="new-list">
234 <input type="text"
235 name="name"
236 _id="name"
237 data-bind="textInput: OrderTemplateNewListName"
238 autofocus
239 autocomplete="off" />
240
241 <input class="product-quantity" type="number" name="quantity" data-bind="textInput: OrderTemplateNewListQuantity" />
242
243 <button type="submit"
244 class="btn btn-primary"
245 _id="btnSave"
246 data-bind="click: function() { CreateNewOrderTemplateList('@productID', OrderTemplateNewListQuantity()) }">
247 @Translate("Ordertemplate.SaveToNewList", "Tilføj til ny favoritliste")
248 </button>
249 </div>
250 </form>
251
252 </div>
253 </div>
254 </div>
255 }
256 else
257 {
258 <div class="favorite-list-icon" data-bind="with: OrderTemplateViewModel">
259 <!-- ko initValue: {observable: OrderTemplateId, value:'@orderTemplateId'}--><!-- /ko-->
260 <!-- ko initValue: {observable: OrderTemplateLineId, value:'@orderLineId'}--><!-- /ko-->
261 <i class="fas fa-times"
262 data-bind="
263 oninit: function() { IsInFavoriteList('@inFavourite'.toLowerCase()) },
264 css: { showFavorite: ShowOrderTemplateDialog, showNewList: OrderTemplateShowNewList, active: IsInFavoriteList() == 'true' },
265 click: DeleteOrderTemplateLine">
266 </i>
267 </div>
268 }
269 </div>
270 }
271 @if (ShowShopFunctions && !IsOutletShop)
272 {
273 <p class="stock-indicator js-stock-indicator">
274 <span class="stock-load-async"></span>
275 <span class="stock-name js-stock-name">@Translate("Product.StockStatus", "Lagerstatus")</span>
276 <span class="stock-name js-in-stock-again hide">@Translate("Product.StockExpectedAgaing", "På lager: ")<span class="js-stock-date"></span></span>
277 </p>
278 }
279 @if (IsOutletShop)
280 {
281 <div class="bg-secondary regular-rrp">
282 <p class="xs-m-b-0">
283 @Translate("Product.NormalRRP", "Normal butikspris: ") @RRPrice
284 </p>
285 </div>
286 }
287 </div>
288
289 </div>
290 <!-- /ko-->
291 }
292
293
294
295
296
297 @helper renderRelatedProduct(LoopItem repatedProduct)
298 {
299 string productID = repatedProduct.GetString("Ecom:Product.ID");
300 string productNumber = repatedProduct.GetString("Ecom:Product.Number");
301 string mainProductID = GetString("Ecom:Product:Field.FirstwebMainProductID");
302
303 string productName = repatedProduct.GetString("Ecom:Product.Name");
304 string productDescription = GetString("Ecom:Product.LongDescription");
305 string productShortDescription = GetString("Ecom:Product.ShortDescription");
306
307 string nettoPrice = repatedProduct.GetString("Firstweb:ErpPriceInfo.NettoPriceFormatted");
308 int bruttoPrice = repatedProduct.GetInteger("Firstweb:ErpPriceInfo.BruttoAmountFormattedNoSymbol");
309
310 int productPackagingQuantity = repatedProduct.GetInteger("Ecom:Product:Field.FirstwebNoPerColli");
311 int defaultQuantity = productPackagingQuantity > 0 ? productPackagingQuantity : 1;
312
313 string languageId = repatedProduct.GetString("Ecom:Product.LanguageID");
314 string variantId = repatedProduct.GetString("Ecom:Product.VariantID");
315
316 int productInFavoritLists = GetInteger("Firstweb:Ecom:Product:OrderTemplate.InTemplates.Count");
317
318 List<Dynamicweb.Ecommerce.Products.Detail> productImages = Firstweb.Custom.CustomCode.Frontend.Helpers.ProductImages.GetProductImages(languageId, productID, variantId);
319 Dynamicweb.Ecommerce.Products.Detail primaryProductImage = productImages.FirstOrDefault(x=>x.IsDefault); //Tag you can use instead: product.GetString("Ecom:Product.ImageDefault.Clean");
320 //check for valid default image
321 if (primaryProductImage == null)
322 {
323 primaryProductImage = new Dynamicweb.Ecommerce.Products.Detail { Value = "" };
324 }
325 else if (primaryProductImage.Value == null)
326 {
327 primaryProductImage.Value = "";
328 }
329
330 string primaryProductImageUrl = "/admin/public/getimage.ashx?image=" + primaryProductImage.Value + "&altFmImage_path=/Files/Images/ecom/Products/no-image.jpg&width=300&height=300&Compression=90&Crop=5";
331
332 //Sorted: first by imagegroup then by sortorder
333 //@foreach (var productImage in productImages)
334 //{
335 //productImage.Value; //This is the imagepath eks. /Images/products/R12155_10_2.jpg
336 //productImage.IsDefault; //If the image is default or not.
337 //}
338
339 <li>
340 <article class="xs-p-2 lg-p-1 rounded-5 border-1 border-color-default">
341 <div class="row is-flex xs-is-flex-column sm-is-flex-col md-is-flex-col">
342
343 <div class="col-md-12 md-is-flex lg-p-r-0">
344 <section class="col-md-3 col-lg-3 xs-p-0 md-p-l-0 md-p-r-1 lg-p-r-1 lg-p-l-0">
345 <img class="img-responsive xs-auto-margin sm-auto-margin" src="@primaryProductImageUrl" />
346 </section>
347
348 <section class="col-md-9 col-lg-7 xs-m-t-2 sm-m-t-2 md-m-t-0 xs-p-0 md-p-r-0 md-p-l-1 lg-p-r-0 lg-p-l-0">
349 <header class="xs-m-b-1">
350 <h2 data-bind="text: name"
351 class="h2 tertiary-font xs-m-t-0">
352 @productName
353 </h2>
354 </header>
355
356 <section class="xs-m-b-1 clearfix">
357 <span class="pull-left font-size-small">
358 @Translate("Product.NumberShort", "Varenr."): <span>@productNumber</span>
359 </span>
360 </section>
361
362 <section class="word-break">
363 <p class="font-size-small">
364 @productShortDescription
365 </p>
366 </section>
367 </section>
368 </div>
369
370 <section class="col-md-9 col-md-offset-3 col-lg-5 col-lg-offset-0 sm-m-t-1 lg-m-t-0 md-p-l-2
371 lg-p-l-0 is-flex is-flex-col sm-is-flex-row sm-is-flex-wrap sm-flex-justify-space-between
372 md-is-flex-row md-is-flex-wrap md-flex-justify-space-between lg-flex-grow-2 lg-flex-justify-space-between">
373
374 <div class="is-flex xs-m-t-1 sm-m-t-0 is-flex-col lg-m-b-auto">
375
376 </div>
377
378 <div class="is-flex is-flex-col md-m-b-1 lg-m-b-0">
379 <h4 class="h4 tertiary-font font-size-16px xs-m-b-1 sm-m-t-0 md-text-right lg-text-right">
380 @nettoPrice
381 </h4>
382
383 <section class="xs-m-b-1 clearfix is-flex xs-flex-space-between lg-is-row-reverse">
384 <div class="pull-right margin-left-1 xs-order-1 sm-order-1 md-order-1 xs-is-self-end sm-is-self-end md-is-self-end lg-m-t-0">
385 @renderQuantityBox(defaultQuantity)
386 </div>
387
388 <div class="is-flex is-flex-col is-centered xs-margin-right-auto sm-m-r-1 md-m-r-1 font-size-small line-height-base md-text-right lg-text-right">
389 <span>@Translate("Product.Packaging", "Forpakning"): </span>
390 <span> @productPackagingQuantity</span>
391 </div>
392 </section>
393 </div>
394
395 <section class="t-align-right clearfix sm-width-100 md-width-100">
396 <button _data-bind="click: handleAddProductToCart"
397 class="btn btn-primary btn-xs tertiary-font lg-p-l-1 lg-p-r-1 xs-width-100 sm-width-100 md-width-100">
398 @Translate("Product.AddToCart", "Tilføj til kurv")
399 </button>
400 </section>
401 </section>
402
403 </div>
404 </article>
405 </li>
406
407
408
409 }
410
411 @helper renderProductBuyBox(bool showShopFunctionsAlternativeIfNotLoggedIn, string productName, string productId, string price, int productPackagingQuantity, int quantity, string stockColor)
412 {
413
414
415 <article class="product-packaging border-bottom-1">
416 <section class="row md-is-flex lg-is-flex md-is-flex-center lg-is-flex-center">
417 <section class="packaging-section col-md-4 col-lg-5">
418 <h4 class="h4 xs-m-t-0 xs-m-b-0 tertiary-font v-align-mid">@productName</h4>
419 </section>
420
421
422
423 @if (Firstweb.Custom.CustomCode.Tapas.Context.Current.ShopFunctionsVisibility.ShowShopFunctions())
424 {
425 <section class="packaging-section md-p-l-0 xs-col-12 col-md-2 col-lg-2 tertiary-font">
426 <span>@price</span>
427
428
429 </section>
430 <div class="stock md-is-self-end lg-is-self-end lg-order-0" >
431 @Translate("Product.StockStatus", "Lagerstatus"): <div class="stock-load-async @stockColor"></div>
432
433 </div>
434 <section class="packaging-section md-p-l-0 lg-p-r-8p packaging-section--alt xs-col-12 col-md-4 col-lg-3">
435 <ul class="list-unstyled lg-m-l-auto lg-p-r-24p xs-m-b-0">
436 <li>
437 <h5 class="h5 xs-m-b-0 xs-m-t-0 line-height-16px">
438 <span>@Translate("Product.Packaging", "Forpakning"): </span>
439 <span> @productPackagingQuantity</span>
440 </h5>
441 </li>
442 </ul>
443
444 @renderQuantityBox(quantity)
445
446 </section>
447
448 <section class="packaging-section md-p-l-0 packaging-section--buy xs-col-12 col-md-2 col-lg-2 t-align-right">
449 <button class="btn btn-primary btn-xs tertiary-font lg-p-l-1 lg-p-r-1 xs-width-100 sm-width-100 margin-bottom-4px"
450 _data-bind="click: handleAddProductToCart">
451 @Translate("Product.AddToCart", "Tilføj til kurv")
452 </button>
453 </section>
454
455 }
456 else if (showShopFunctionsAlternativeIfNotLoggedIn)
457 {
458 var replaceWith = Firstweb.Custom.CustomCode.Tapas.Context.Current.ShopFunctionsVisibility.ReplaceWith();
459
460 <section>
461
462 @if (replaceWith == "LOGIN")
463 {
464 <text>@renderLogin()</text>
465 }
466 else if (replaceWith == "RESELLER")
467 {
468 <text>@renderResellerLink()</text>
469 }
470 </section>
471 }
472
473 </section>
474 </article>
475 }
476
477
478 @helper renderInstantSearchProduct(LoopItem product)
479 {
480 string productID = product.GetString("Ecom:Product.ID");
481 string productNumber = product.GetString("Ecom:Product.Number");
482 string mainProductID = product.GetString("Ecom:Product:Field.FirstwebMainProductID");
483
484 string productLink = product.GetString("Ecom:Product.Link.Clean");
485
486 string productName = product.GetString("Ecom:Product.Name");
487 string productShortDescription = product.GetString("Ecom:Product.ShortDescription");
488
489 int productPackagingQuantity = product.GetInteger("Firstweb:ErpPriceInfo:ExtraInfos.PackagingSize");
490 int defaultQuantity = productPackagingQuantity > 0 ? productPackagingQuantity : 1;
491
492 string languageId = product.GetString("Ecom:Product.LanguageID");
493 string variantId = product.GetString("Ecom:Product.VariantID");
494
495 bool hasVariants = (product.GetLoop("VariantCombinations").Count() > 0);
496
497 //Images
498 List<Dynamicweb.Ecommerce.Products.Detail> productImages = Firstweb.Custom.CustomCode.Frontend.Helpers.ProductImages.GetProductImages(languageId, productID, variantId);
499 Dynamicweb.Ecommerce.Products.Detail primaryProductImage = productImages.FirstOrDefault(x=>x.IsDefault); //Tag you can use instead: product.GetString("Ecom:Product.ImageDefault.Clean");
500
501 //check for valid default image
502 if (primaryProductImage == null)
503 {
504 primaryProductImage = new Dynamicweb.Ecommerce.Products.Detail { Value = "" };
505 }
506 else if (primaryProductImage.Value == null)
507 {
508 primaryProductImage.Value = "";
509 }
510
511 string primaryProductImageUrl = "/admin/public/getimage.ashx?image=" + primaryProductImage.Value + "&altFmImage_path=/Files/Images/ecom/Products/no-image.jpg&width=200&height=125&Compression=90&Crop=5";
512 if (String.IsNullOrEmpty(primaryProductImage.Value))
513 {
514 primaryProductImageUrl = "/admin/public/getimage.ashx?image=/Files/Images/ecom/Products/no-image.jpg&width=200&height=125&Compression=90&Crop=5";
515 }
516 //Sorted: first by imagegroup then by sortorder
517 //@foreach (var productImage in productImages)
518 //{
519 //productImage.Value; //This is the imagepath eks. /Images/products/R12155_10_2.jpg
520 //productImage.IsDefault; //If the image is default or not.
521 //}
522
523 //Other packagings
524 //var otherPackagingProducts = Firstweb.Custom.CustomCode.Frontend.Helpers.OtherPackagingProducts.GetOtherPackagingProducts(mainProductID, false).Where(i => i.Id != productID);
525 //var showOtherPackagingProducts = otherPackagingProducts.Count() > 0;
526
527 int loopCount = product.GetInteger("Products.LoopCounter") - 1;
528 <div class="col-xs-12 col-sm-3 xs-m-b-1">
529
530 <article class="instant-search-product bg-white productCount @loopCount" data-bind="css: {'item--selected': navSelectedItem() == @loopCount}">
531 <div class="cursor-pointer info"
532 data-bind="click: function() { window.location.href='@productLink'}">
533 <div class="hidden-xs product-image">
534 <img class="img-responsive center-block" src="@primaryProductImageUrl">
535 </div>
536
537 <div class="name">
538 <p>@productName</p>
539
540
541 <span>@Translate("Product.NumberShort", "Varenr.") @productNumber</span>
542 </div>
543 </div>
544
545 @if (Firstweb.Custom.CustomCode.Tapas.Context.Current.ShopFunctionsVisibility.ShowShopFunctions())
546 {
547 <div class="buy-container" data-bind="defineObservable: { quantity: 1 }">
548
549 <input class="product-quantity" type="number" name="quantity" data-bind="value: quantity" />
550
551 <button class="btn btn-primary btn-xs add-to-cart"
552 data-bind="click: function(evt) { $parent.onAddToCart('@productID', quantity()) }">
553 @Translate("Product.AddToCart", "Tilføj til kurv")
554 </button>
555 </div>
556 }
557 </article>
558
559 </div>
560
561 }
562
563
564
565 @helper renderQuantityBox(int quantity)
566 {
567 <input class="product-quantity" type="number" name="quantity" value="@quantity" />
568 }
569
570
571 @helper renderLogin()
572 {
573 <button class="btn btn-primary" data-toggle="modal" data-target=".loginModal">@Translate("Product.LoginToShop", "Log ind for at købe")</button>
574 }
575 @helper renderResellerLink()
576 {
577 <a href="@Firstweb.Custom.CustomCode.Tapas.Context.Current.ShopFunctionsVisibility.ReplaceLink()" class="btn btn-primary">@Translate("Product.FindReseller", "Find forhandler")</a>
578 }
579
580 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
581 @using Dynamicweb.Rendering
582 @using Dynamicweb.Environment
583
584 @helper renderBreadcrumbs(string productId = "")
585 {
586 string currentGroupId = Dynamicweb.Context.Current.Request.GetString("GroupID");
587 string productPageID = Firstweb.Custom.CustomCode.Tapas.Context.AreaPages.GetPageId("productcatalog");
588 string productPageHref = "/Default.aspx?Id=" + productPageID;
589 var breadCrumbGroupList = Firstweb.Custom.CustomCode.Frontend.Helpers.EcomGroups.getBreadCrumbGroupList(currentGroupId, true);
590
591 if (!String.IsNullOrEmpty(productId)) {
592 breadCrumbGroupList = Firstweb.Custom.CustomCode.Frontend.Helpers.EcomGroups.getBreadCrumbGroupListByProduct(productId, true);
593 }
594
595 <div class="col-xs-12">
596 <ul class="breadcrumb">
597 <li><a href="@productPageHref" title="@Translate("Firstweb.Content.Breadcrumbs.ProductPage", "Produkter")">@Translate("Firstweb.Content.Breadcrumbs.ProductPage", "Produkter")</a></li>
598 @foreach (var g in breadCrumbGroupList) {
599 string breadCrumbLink = String.Format("/Default.aspx?Id={0}&GroupId={1}", productPageID, g.Id);
600 <li> <a href='@breadCrumbLink' title="@g.Name">@g.Name </a></li>
601 }
602 </ul>
603 </div>
604 }
605
606 @{
607 string sortOrder = GetString("Ecom:ProductList.SortOrder");
608 bool isAjaxRequest = Dynamicweb.Context.Current.Request.GetBoolean("ajaxTapas");
609 string searchQuery = Dynamicweb.Context.Current.Request.GetString("Search");
610 string currentGroupId = Dynamicweb.Context.Current.Request.GetString("GroupID");
611 int pageId = Dynamicweb.Frontend.PageView.Current().ID;
612 var breadCrumbGroupList = Firstweb.Custom.CustomCode.Frontend.Helpers.EcomGroups.getBreadCrumbGroupList(currentGroupId, false);
613 bool IsGroupList = !String.IsNullOrEmpty(currentGroupId);
614
615 int totalPages = GetInteger("Ecom:ProductList.TotalPages");
616 int currentPage = GetInteger("Ecom:ProductList.CurrentPage");
617 int productCount = GetInteger("Ecom:ProductList.PageProdCnt");
618 bool productsFound = (productCount > 0);
619 bool IsOutletShop = Firstweb.Custom.CustomCode.Frontend.Helpers.Millarco.IsOutletShop();
620
621 int ProductGroupVideoList = GetInteger("Ecom:Group:Field.FirstwebProductGroupVideoList");
622
623 bool isGroupView = GetBoolean("Ecom:Group:Field.groupview");
624 }
625
626 @if (!isAjaxRequest)
627 {
628 <div class="container">
629 <div class="row">
630 @renderBreadcrumbs()
631 </div>
632 </div>
633
634 <div class="millarco-productlist">
635
636 <section>
637
638 @if (IsGroupList)
639 {
640 @RenderGroupHeader()
641 }
642 else if (!String.IsNullOrWhiteSpace(searchQuery))
643 {
644 <div class="container xs-p-t-3">
645 @RenderSearchHeader(searchQuery)
646 </div>
647 }
648 else if (!IsOutletShop)
649 {
650 <div class="container xs-p-t-3">
651 @RenderParagraphHeader()
652 </div>
653 }
654 else
655 {
656 @RenderOutletShopHeader()
657 }
658
659 </section>
660
661 @if (!isGroupView)
662 {
663 <div class="container product-container">
664
665 <main data-bind="viewModel: 'ProductListViewModel'">
666 <div class="row">
667 <div class="col-lg-3 product-groups-wrapper">
668 <p class="h3">@Translate("ProductSubNavTitle", "Produkter")</p>
669 @if (productsFound)
670 {
671 if (IsGroupList)
672 {
673 <div class="product-groups">
674 @RenderGroupLevelFilter(Firstweb.Custom.CustomCode.Frontend.Helpers.EcomGroups.GetFilterTopLevelGroup(), currentGroupId, currentGroupId, pageId)
675 </div>
676 }
677 }
678 </div>
679 <div class="col-lg-9">
680 <div class="row">
681 @if (productsFound)
682 {
683 <div class="col-xs-12 filter-section">
684 <form method="get"
685 action="/Default.aspx"
686 data-bind="formSubmitOnChange: {
687 text: '@Translate("Productlist.UpdatingFilters", "Opdaterer filter")',
688 delay: '1000' }">
689 <input type="hidden" name="id" value="@GetString("Ecom:ProductList:Page.ID")" />
690
691 @if (!String.IsNullOrEmpty(currentGroupId))
692 {
693 <input type="hidden" name="groupid" value="@currentGroupId" />
694 }
695 @if (!String.IsNullOrEmpty(searchQuery))
696 {
697 <input type="hidden" name="search" value="@searchQuery" />
698 }
699
700 @RenderSorting(sortOrder)
701
702 @RenderFacets()
703 </form>
704 </div>
705 }
706 <div class="col-xs-12 productList"
707 data-bind="asyncPriceLoad: productListLoad,
708 loadOnBool: { observableBool: CartLoading, text: 'Tilføjer produkt' },
709 css: 'loaded'">
710
711 <div class="row row-ce">
712 @RenderProductList(GetLoop("Products"), productsFound)
713 </div>
714
715 @if (ProductGroupVideoList > 0)
716 {
717 @RenderParagraphContent(ProductGroupVideoList)
718 }
719
720 @if (totalPages > 1 && currentPage == 1)
721 {
722 <div class="loadMoreProducts"
723 data-bind="loadMoreProducts: {
724 beforeLoad: function() { $root.stuffLoadingQueue({load: true}) },
725 afterLoad: function() { $root.stuffLoadingQueue({load: false}) },
726 text: '@Translate("Productlist.LoadingProducts", "Henter produkter")',
727 currentPage: @currentPage,
728 totalPages: @totalPages
729 }">
730 </div>
731 }
732
733 @if (!String.IsNullOrEmpty(GetString("Ecom:Group:Field.GroupDescriptionBottom")))
734 {
735 <div class="group-description">@GetString("Ecom:Group:Field.GroupDescriptionBottom")</div>
736 }
737 </div>
738 </div>
739 </div>
740 </div>
741 </main>
742 </div>
743 }
744 else
745 {
746 int subGroupCount = 0;
747 List<LoopItem> subGroups = GetLoop("Subgroups");
748 bool anySelectedGroups = subGroups.Any(g => g.GetBoolean("Ecom:Group:Field.selectedgroup.Value"));
749 bool anyUnselectedGroups = subGroups.Any(g => !g.GetBoolean("Ecom:Group:Field.selectedgroup.Value"));
750 string hideIfAnySelectedGroupsClass = !anySelectedGroups && anyUnselectedGroups ? "" : "hidden";
751
752 <div class="container">
753 <main class="group-view">
754 <div class="row">
755 <div class="col-lg-12">
756 @if (anySelectedGroups)
757 {
758 <div class="selected-groups">
759 <p class="h2 margin-top-40px">@Translate("GroupViewTitle", "Udvalgte kategorier")</p>
760 <div class="row">
761 @foreach (LoopItem group in subGroups.Where(g => g.GetBoolean("Ecom:Group:Field.selectedgroup.Value")))
762 {
763 string imagePath = group.GetString("Ecom:Group.SmallImage");
764 string imagePathCustom = group.GetString("Ecom:Group:Field.selectedgroupimage.Value.Clean");
765 string image;
766 string cssBackground;
767
768 if (!string.IsNullOrEmpty(imagePathCustom))
769 {
770 image = "/admin/public/GetImage.ashx?image=" + imagePathCustom + "&width=400";
771 cssBackground = "background:#fff url('" + image + "') no-repeat center center / cover;";
772 }
773 else
774 {
775 image = "/admin/public/GetImage.ashx?image=" + imagePath + "&width=400";
776 cssBackground = "background:#fff url('" + image + "') no-repeat center center / 200px;";
777 }
778 string groupName = group.GetString("Ecom:Group.Name");
779
780 <div class="col-12 col-sm-6 col-lg-4">
781 <a href="@group.GetString("Ecom:Group.Link.Clean")">
782 <div style="@cssBackground" class="img-responsive margin-bottom-24px group-image">
783 <div class="group-name">@groupName</div>
784 </div>
785 </a>
786 </div>
787 }
788 </div>
789 </div>
790 }
791
792 @if (anySelectedGroups && anyUnselectedGroups)
793 {
794 <div class="row margin-top-18px margin-bottom-18px">
795 <div class="col-12">
796 <div class="groups-view-all centerText">
797 <div onclick="$('.all-groups').removeClass('hidden'), $(this).addClass('hidden');" class="btn btn-primary">@Translate("GroupViewMoreButton", "Se alle grupper")</div>
798 </div>
799 </div>
800 </div>
801 }
802
803 <div class="all-groups @hideIfAnySelectedGroupsClass">
804 <p class="h2 margin-top-40px">@Translate("AllGroupViewTitle", "Alle kategorier")</p>
805 <div class="row">
806 @foreach (LoopItem group in subGroups.Where(g => !g.GetBoolean("Ecom:Group:Field.selectedgroup.Value")))
807 {
808 string imagePath = group.GetString("Ecom:Group.SmallImage");
809 string imagePathCustom = group.GetString("Ecom:Group:Field.selectedgroupimage.Value.Clean");
810 string image;
811 string cssBackground;
812
813 if (!string.IsNullOrEmpty(imagePathCustom))
814 {
815 image = "/admin/public/GetImage.ashx?image=" + imagePathCustom + "&width=400";
816 cssBackground = "background:#fff url('" + image + "') no-repeat center center / cover;";
817 }
818 else
819 {
820 image = "/admin/public/GetImage.ashx?image=" + imagePath + "&width=400";
821 cssBackground = "background:#fff url('" + image + "') no-repeat center center / 200px;";
822 }
823 string groupName = group.GetString("Ecom:Group.Name");
824
825 <div class="col-12 col-sm-6 col-lg-4">
826 <a href="@group.GetString("Ecom:Group.Link.Clean")">
827 <div style="@cssBackground" class="img-responsive margin-bottom-24px group-image">
828 <div class="group-name">@groupName</div>
829 </div>
830 </a>
831 </div>
832 }
833 </div>
834 </div>
835 <div class="margin-top-40px margin-bottom-40px">
836 @if (!String.IsNullOrEmpty(GetString("Ecom:Group:Field.GroupDescriptionBottom")))
837 {
838 <div class="group-description">@GetString("Ecom:Group:Field.GroupDescriptionBottom")</div>
839 }
840 </div>
841 </div>
842 </div>
843 </main>
844 </div>
845 }
846
847 </div>
848 }
849 else
850 {
851 <div class="productsContainer">
852 @RenderProductList(GetLoop("Products"), productsFound)
853 </div>
854 }
855
856 @helper RenderProductList(IEnumerable<LoopItem> Loop, bool productsFound)
857 {
858 if (!productsFound)
859 {
860 <div class="is-flex col-xs-12 xs-m-t-3 xs-m-b-4 sm-m-b-7 font-primary">
861 <h1>@Translate("ProductList.NoProductsFound", ":( There are no products in this category")</h1>
862 </div>
863 }
864 else
865 {
866 var productLoop = Loop.ToList();
867 int currentPage = GetInteger("Ecom:ProductList.CurrentPage");
868 int totalPages = GetInteger("Ecom:ProductList.TotalPages");
869 var count = 0;
870
871 for (int i = 0; i < productLoop.Count(); i++)
872 {
873 var item = productLoop[i];
874 int loopMod = item.GetInteger("Products.LoopMod4");
875 bool renderStartRow = i % 3 == 0 ? true : false;
876 bool renderEndRow = i % 3 == 0 ? true : false;
877
878 if (i == 0 && totalPages > 1)
879 {
880 @:<div class="row row-ce" id="@currentPage">
881 }
882
883 @renderProduct(true, item, true); //This is from renderProduct.cshtml
884
885
886 if (productLoop.Count() - 1 == i && totalPages > 1)
887 {
888 @:</div>
889 }
890 }
891 }
892 }
893
894 @helper RenderOutletShopHeader()
895 {
896 <div class="content-element solid-bg bg-image-and-text-element bg-secondary" style="background-image:url('/Files/Images/@Dynamicweb.Frontend.PageView.Current().CurrentParagraph.Image')">
897 <div class="container">
898 <div class="row">
899 <div class="col-xs-12 col-md-8 col-lg-6">
900 <div class="text-area">
901 <div class="rte-content">
902 @Dynamicweb.Frontend.PageView.Current().CurrentParagraph.Text
903 </div>
904 <div class="red-divider"></div>
905 </div>
906 </div>
907 </div>
908 </div>
909 </div>
910 }
911
912
913 @helper RenderGroupHeader()
914 {
915 int ProductGroupVideoTop = GetInteger("Ecom:Group:Field.FirstwebProductGroupVideoTop");
916 string Description = GetString("Ecom:Group.Description");
917 string GroupName = GetString("Ecom:Group.Name");
918 string BgImage = GetString("Ecom:Group.LargeImage");
919 bool IsOutletShop = Firstweb.Custom.CustomCode.Frontend.Helpers.Millarco.IsOutletShop();
920 if (IsOutletShop && !String.IsNullOrEmpty(GetString("Ecom:Group:Field.FirstwebOutletGroupImage.Value.Clean")))
921 {
922 BgImage = GetString("Ecom:Group:Field.FirstwebOutletGroupImage.Value.Clean");
923 }
924
925 if (ProductGroupVideoTop > 0)
926 {
927 @RenderParagraphContent(ProductGroupVideoTop)
928 }
929 else
930 {
931 <div class="content-element solid-bg bg-image-and-text-element bg-secondary" style="background-image:url('@BgImage')">
932 <div class="container">
933 <div class="row">
934 <div class="col-xs-12 col-md-8 col-lg-6">
935 <div class="text-area">
936 @if (!String.IsNullOrEmpty(Description))
937 {
938 <div class="rte-content">
939 @Description
940 </div>
941 }
942 else
943 {
944 <h1 class="xs-m-t-0">@GroupName</h1>
945 }
946 <div class="red-divider"></div>
947 </div>
948 </div>
949 </div>
950 </div>
951 </div>
952 }
953 }
954
955 @helper RenderSearchHeader(string searchQuery)
956 {
957 <h1 class="h1 xs-m-t-0 tertiary-font">
958 @Translate("ProductList.SearchResultHeader", "Søgeresultat")
959 </h1>
960
961 <h4 class="h4 lg-m-b-0">
962 @Translate("ProductList.SearchResultText", "Resultater for din søgning"): @searchQuery
963 </h4>
964 }
965
966 @helper RenderParagraphHeader()
967 {
968 <h1 class="h1 lg-m-t-0 tertiary-font">@Dynamicweb.Frontend.PageView.Current().CurrentParagraph.Header</h1>
969
970 if (!String.IsNullOrEmpty(Dynamicweb.Frontend.PageView.Current().CurrentParagraph.Text))
971 {
972 <p>@Dynamicweb.Frontend.PageView.Current().CurrentParagraph.Text</p>
973 }
974 }
975
976
977 @helper RenderGroups(List<Dynamicweb.Ecommerce.Products.Group> breadCrumbGroupList, string currentGroupId)
978 {
979 if (breadCrumbGroupList.Count() > 0)
980 {
981 var ParentGroup = breadCrumbGroupList.LastOrDefault();
982 var baseLink = "/Default.aspx?ID=" + Dynamicweb.Frontend.PageView.Current().ID + "&GroupID=";
983 if (ParentGroup != null)
984 {
985 <section class="product__sub-nav">
986 <p class="xs-m-b-0">
987 @ParentGroup.Name
988 </p>
989
990 <ul>
991 @foreach (var subgroup in ParentGroup.Subgroups)
992 {
993 <li>
994 @if (subgroup.Id == currentGroupId)
995 {
996 <span>@subgroup.Name</span>
997 }
998 else
999 {
1000 bool DisplayGroup = subgroup.Products.Count() > 0 || subgroup.Subgroups.Where(x => x.Products.Count() > 0).Count() > 0;
1001 if (DisplayGroup)
1002 {
1003 <a href="@baseLink@subgroup.Id">@subgroup.Name</a>
1004 }
1005 }
1006 </li>
1007 }
1008 </ul>
1009 </section>
1010 }
1011 }
1012 }
1013
1014 @helper RenderFacets()
1015 {
1016 foreach (LoopItem facetGroup in GetLoop("FacetGroups"))
1017 {
1018 foreach (LoopItem facet in facetGroup.GetLoop("Facets").Where(x => x.GetLoop("FacetOptions").Any()))
1019 {
1020 string facetName = facet.GetString("Facet.Name");
1021 string translatedFacetName = Translate("ProductList.FacetName" + facet.GetString("Facet.Name"), facet.GetString("Facet.Name"));
1022 bool hasOptions = facet.GetLoop("FacetOptions").Any();
1023 string hasOptionsCss = hasOptions ? "xs-p-t-1 xs-p-b-1" : "";
1024 string FacetIsOpen = facet.GetLoop("FacetOptions").Where(x => x.GetBoolean("FacetOption.Selected")).Any() ? "true" : "false";
1025
1026 <section class="bg-white filter" data-bind="defineObservable: { sortDropdown: @FacetIsOpen }">
1027 @if (hasOptions)
1028 {
1029 <button class="filter__toggle xs-p-l-0 xs-p-r-0 clear-button is-flex is-space-between is-flex-align-center width-100" data-bind="click: function() { sortDropdown(!sortDropdown()) }">
1030 <h3 class="h3 xs-m-t-0 xs-m-b-0 tertiary-font font-size-base filterHeader"
1031 data-bind="toggleClassParent: 'active'">
1032 @translatedFacetName
1033 </h3>
1034 <span>
1035 <i class="fa fa-chevron-down"></i>
1036 </span>
1037 </button>
1038 }
1039
1040 <div class="filter__options line-height-base" data-bind="css: { hidden: !sortDropdown() }">
1041 @foreach (LoopItem option in facet.GetLoop("FacetOptions"))
1042 {
1043 var value = option.GetValue("FacetOption.Value");
1044 string label = option.GetString("FacetOption.Label").Replace("\"", """);
1045 if (label.ToUpper() == "TRUE" || label.ToUpper() == "FALSE")
1046 {
1047 label = Translate("ProductList.FacetOption:" + label, "Ja");
1048 }
1049
1050
1051 int count = option.GetInteger("FacetOption.Count");
1052 bool selected = option.GetBoolean("FacetOption.Selected");
1053 label += " (" + count + ")";
1054 <div class="form-group">
1055 <custom-checkbox params="{ label: '@label',
1056 value: '@value',
1057 checked: @(selected.ToString().ToLower()),
1058 name: '@facet.GetString("Facet.QueryParameter")' }" />
1059 </div>
1060 }
1061 </div>
1062 </section>
1063 }
1064 }
1065 }
1066
1067
1068 @helper RenderSorting(string sortOrder)
1069 {
1070 <section class="bg-white filter filter__container"
1071 data-bind="defineObservable: {
1072 sortOrder: '@sortOrder' || 'ASC',
1073 sortDropdown: false }">
1074 <button class="filter__toggle clear-button is-flex is-space-between is-flex-align-center clear-button xs-p-l-0 xs-p-r-0 width-100" data-bind="click: function() { sortDropdown(!sortDropdown()) }">
1075 <p class="h3 xs-m-t-0 xs-m-b-0 tertiary-font font-size-base"
1076 data-bind="toggleClassParent: 'active'">
1077 @Translate("filtersort", "Sortering")
1078 </p>
1079
1080 <span>
1081 <i class="fa fa-chevron-down"></i>
1082 </span>
1083 </button>
1084
1085 <input type="hidden" name="SortBy" value="ProductNameSort" />
1086
1087 <section class="filter__options" data-bind="css: { hidden: !sortDropdown() }">
1088 <div class="form-group">
1089 <custom-radio params="{
1090 label: '@Translate("sortnameaz", "Navn: A - Å")',
1091 value: 'ASC',
1092 checked: sortOrder,
1093 name: 'SortOrder' }" />
1094 </div>
1095
1096 <div class="form-group xs-m-b-0">
1097 <custom-radio params="{
1098 label: '@Translate("sortnameza", "Navn: Å - A")',
1099 value: 'DESC',
1100 checked: sortOrder,
1101 name: 'SortOrder' }" />
1102 </div>
1103 </section>
1104 </section>
1105 }
1106
1107 @helper RenderGroupLevelFilter(IEnumerable<Dynamicweb.Ecommerce.Products.Group> groups, string currentGroupId, string activeGroup, int pageId)
1108 {
1109 var ProductGroups = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(currentGroupId);
1110 bool isTopLevelGroup = ProductGroups.IsTopGroup;
1111 var parentGroup = ProductGroups.PrimaryParentGroupId;
1112
1113 if (isTopLevelGroup)
1114 {
1115 foreach (var group in groups.Where(x => Firstweb.Custom.CustomCode.Frontend.Helpers.EcomGroups.IsFilterGroup(x)))
1116 {
1117 var currentGroup = group.Id.Equals(currentGroupId);
1118 var isCurrentGroup = currentGroup ? "is-active" : "";
1119
1120 <div class="@isCurrentGroup">
1121 <a href="/Default.aspx?Id=@pageId&groupid=@group.Id">@group.Name</a>
1122 </div>
1123
1124 if (currentGroup && group.HasChildGroups)
1125 {
1126 <div class="sub-group">
1127 @foreach (var isSubGroup in group.Subgroups)
1128 {
1129 var setActive = isSubGroup.Id == activeGroup ? "is-active" : "";
1130
1131 <div class="@setActive">
1132 <a href="/Default.aspx?Id=@pageId&groupid=@isSubGroup.Id">@isSubGroup.Name</a>
1133 </div>
1134 }
1135 @*@RenderGroupLevelFilter(group.Subgroups, currentGroupId, (level + 1))*@
1136 </div>
1137 }
1138 }
1139 }
1140 else
1141 {
1142 @RenderGroupLevelFilter(groups, parentGroup, currentGroupId, pageId)
1143 }
1144 }