Error executing template "Designs/Swift/Paragraph/Swift_ProductAddToCart.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
at CompiledRazorTemplates.Dynamic.RazorEngine_b7850274d3984bd6945d7859628d47d5.Execute() in D:\dynamicweb.net\Solutions\Degree\proff1.cloud.dynamicweb-cms.com\files\Templates\Designs\Swift\Paragraph\Swift_ProductAddToCart.cshtml:line 42
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 Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel>
2 @using Dynamicweb.Ecommerce.ProductCatalog
3 @using Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites
4 @using Proff1.Service
5 @using System.Text.Json
6 @using System.Linq
7
8
9 @{
10 ProductViewModel product = null;
11 List<Dynamicweb.Ecommerce.ProductCatalog.GroupInfoViewModel> productGroup = null;
12 string lastGroup = null;
13 string productIdTag = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : "";
14 var productService = new Dynamicweb.Ecommerce.Products.ProductService();
15 var regularProduct = productService.GetProductById(productIdTag, "", true);
16 var productBrand = regularProduct?.ProductFieldValues.GetProductFieldValue("TK_Brand").Value.ToString();
17
18
19 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
20 {
21 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
22 productGroup = product.GroupPaths[0];
23 lastGroup = productGroup.Last().Name;
24 }
25 else if (Pageview.Item["DummyProduct"] != null)
26 {
27 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page);
28 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel();
29
30 if (productList?.Products is object)
31 {
32 product = productList.Products[0];
33 }
34 }
35
36 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", "");
37 bool anonymousUser = Pageview.User == null;
38 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsWebServiceConnectionAvailable"]);
39 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHideAddToCart") && isErpConnectionDown;
40 hideAddToCart = Pageview.IsVisualEditorMode ? false : hideAddToCart;
41
42 string addedMessageId = $"addedMsg{product.Id}_{Pageview.CurrentParagraph.ID}";
43 string addToCartButtonId = $"AddToCartButton{product.Id}_{Pageview.CurrentParagraph.ID}";
44 }
45
46
47 @if (product is object && !hideAddToCart)
48 {
49 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", "");
50 horizontalAlign = horizontalAlign == "center" ? "justify-content-center" : horizontalAlign;
51 horizontalAlign = horizontalAlign == "end" ? "justify-content-end" : horizontalAlign;
52 horizontalAlign = horizontalAlign == "full" ? "" : horizontalAlign;
53
54 bool favoritesSelector = !string.IsNullOrEmpty(Model.Item.GetString("ShowAddToFavorites")) ? Model.Item.GetBoolean("ShowAddToFavorites") : false;
55 bool quantitySelector = !string.IsNullOrEmpty(Model.Item.GetString("ShowQuantitySelector")) ? Model.Item.GetBoolean("ShowQuantitySelector") : false;
56 bool unitsSelector = !string.IsNullOrEmpty(Model.Item.GetString("ShowUnitsSelector")) ? Model.Item.GetBoolean("ShowUnitsSelector") : false;
57 bool hideInventory = !string.IsNullOrEmpty(Model.Item.GetString("HideInventory")) ? Model.Item.GetBoolean("HideInventory") : false;
58 bool hideStockState = !string.IsNullOrEmpty(Model.Item.GetString("HideStockState")) ? Model.Item.GetBoolean("HideStockState") : false;
59
60 string buttonSize = Model.Item.GetRawValueString("ButtonSize", "regular");
61 string inputSize = string.Empty;
62
63 switch (buttonSize)
64 {
65 case "small":
66 inputSize = " input-group-sm";
67 buttonSize = " btn-sm";
68 break;
69 case "regular":
70 buttonSize = string.Empty;
71 break;
72 case "large":
73 inputSize = " input-group-lg";
74 buttonSize = " btn-lg";
75 break;
76 }
77
78 string iconPath = "/Files/icons/";
79 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService"));
80 if (!url.Contains("LayoutTemplate"))
81 {
82 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml";
83 }
84
85
86 bool isNeverOutOfStock = product.NeverOutOfstock;
87 var totalItemsInStock = Proff1Services.StockService.GetStockInfo(product.Number).Sum(stockInfo => stockInfo.ItemsInStock);
88 string disableAddToCart = (totalItemsInStock <= 0) ? "disabled" : "";
89
90 string addToCartButtonText = Translate("Add to cart");
91
92 if (!product.NeverOutOfstock && totalItemsInStock <= 0)
93 {
94 addToCartButtonText = Translate("Ikke på lager");
95 }
96 else if (totalItemsInStock <= 0)
97 {
98 addToCartButtonText = Translate("Bestill");
99 }
100
101 disableAddToCart = isNeverOutOfStock ? "" : disableAddToCart;
102
103 string whenVariantsExist = Model.Item.GetRawValueString("WhenVariantsExist", "hide");
104
105 string flexFill = Model.Item.GetRawValueString("HorizontalAlignment", "") == "full" ? "flex-fill" : "";
106 string fullWidth = Model.Item.GetRawValueString("HorizontalAlignment", "") == "full" ? "w-100" : "";
107 string addToCartIcon = Model.Item.GetRawValueString("Icon", iconPath + "shopping-cart.svg");
108 string checkIcon = Model.Item.GetRawValueString("Icon", iconPath + "check.svg");
109 string addToCartLabel = !addToCartIcon.Contains("_none") ? "<span class=\"icon-2\">" + ReadFile(addToCartIcon) + "</span>" : "";
110 addToCartLabel += !addToCartIcon.Contains("_none") && !Model.Item.GetBoolean("HideButtonText") ? " " : "";
111 addToCartLabel += !Model.Item.GetBoolean("HideButtonText") ? addToCartButtonText : "";
112
113
114 string productId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : "";
115 bool isProductDetailsPage = !string.IsNullOrEmpty(productId);
116 bool isMasterWithVariant = product.VariantInfo.VariantInfo != null && string.IsNullOrEmpty(product.VariantId);
117
118 var deliveryDays = product.ProductFields["P1_Product_Delivery_Days"].Value;
119
120 if (product.VariantInfo.VariantInfo == null || isProductDetailsPage)
121 {
122 string unitId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("UnitId")) ? Dynamicweb.Context.Current.Request.Form.Get("UnitId") : product.DefaultUnitId;
123 if (string.IsNullOrEmpty(unitId) && product?.UnitOptions != null)
124 {
125 if (product.UnitOptions.FirstOrDefault<UnitOptionViewModel>() != null)
126 {
127 unitId = product.UnitOptions.FirstOrDefault<UnitOptionViewModel>().Id;
128 }
129 }
130
131 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\"";
132 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1";
133 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty;
134 disableAddToCart = product.VariantInfo.VariantInfo != null && string.IsNullOrEmpty(product.VariantId) ? "disabled" : disableAddToCart;
135
136 var reserveMode = Dynamicweb.Ecommerce.Frontend.Cart.ProductReserve.Mode;
137
138 if (unitsSelector && product.UnitOptions.Count > 0)
139 {
140 <form method="post" action="/Default.aspx?ID=@(Pageview.Page.ID)&ProductId=@product.Id" id="UnitSelectorForm_@(product.Id)_@(product.VariantId)_@Model.ID">
141 <input type="hidden" name="redirect" value="false">
142 <input type="hidden" name="VariantID" value="@product.VariantId">
143 <input type="hidden" name="UnitID" class="js-unit-id" value="@unitId">
144 </form>
145 }
146
147 <div class="d-grid @horizontalAlign @fullWidth js-input-group item_@Model.Item.SystemName.ToLower()">
148 <form method="post" action="@url" class="@fullWidth" style="z-index: 1">
149 <input type="hidden" name="redirect" value="false">
150 <input type="hidden" name="ProductId" value="@product.Id">
151 <input type="hidden" name="ProductName" value="@product.Name">
152 <input type="hidden" name="ProductVariantName" value="@product.VariantName">
153 <input type="hidden" name="ProductCurrency" value="@Dynamicweb.Ecommerce.Common.Context.Currency.Code">
154 <input type="hidden" name="ProductPrice" value="@PriceViewModelExtensions.ToStringInvariant(product.Price)">
155 <input type="hidden" name="ProductReferer" value="component_ProductAddToCart">
156 <input type="hidden" name="cartcmd" value="add">
157
158 @if (reserveMode == Dynamicweb.Ecommerce.Frontend.Cart.ProductReserveMode.AddToCart)
159 {
160 <input type="hidden" name="GetReservedAmount" value="true">
161 }
162
163 @if (!string.IsNullOrEmpty(product.VariantId))
164 {
165 <input type="hidden" name="VariantId" value="@product.VariantId">
166 }
167
168 @if (!product.NeverOutOfstock)
169 {
170 <input type="hidden" name="Stock" value="@product.StockLevel">
171
172 <template class="js-out-of-stock-notice">
173 <div class="modal-header">
174 <h1 class="modal-title fs-5">@Translate("Stock limit")</h1>
175 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
176 </div>
177 <div class="modal-body">
178 @Translate("There are not enough products in stock. The product might be sold out or discontinued. Please adjust the quantity.")
179 </div>
180 </template>
181 }
182
183 @if (stepQty != "1")
184 {
185 <template class="js-step-quantity-warning">
186 <div class="modal-header">
187 <h1 class="modal-title fs-5">@Translate("The quantity is not valid")</h1>
188 </div>
189 <div class="modal-body">
190 @Translate("Please select a quantity that is dividable by") @stepQty
191 </div>
192 </template>
193 }
194 @if (product.PurchaseMinimumQuantity != 1)
195 {
196 <template class="js-min-quantity-warning">
197 <div class="modal-header">
198 <h1 class="modal-title fs-5">@Translate("The product could not be added to the cart")</h1>
199 </div>
200 <div class="modal-body">
201 @Translate("The quantity is not valid. You must buy at least") @product.PurchaseMinimumQuantity
202 </div>
203 </template>
204 }
205
206 @if (quantitySelector || (!anonymousUser && product.VariantInfo.VariantInfo != null) || (!anonymousUser && favoritesSelector))
207 {
208 <input type="hidden" id="Unit_@(product.Id)_@product.VariantId" name="UnitID" value="@unitId" />
209 }
210
211 <div class="d-flex flex-row w-100">
212 @if (!anonymousUser && favoritesSelector)
213 {
214 @RenderPartial("Components/ToggleFavorite.cshtml", product)
215 }
216
217 @if (!quantitySelector)
218 {
219 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="@valueQty" type="hidden" @disableAddToCart>
220 }
221
222 <div class="input-group input-primary-button-group flex-nowrap@(inputSize)">
223 @if (quantitySelector)
224 {
225 <div class="d-flex me-2" style="border: 1px solid #5555">
226 <button type="button" class="btn btn-stepper fs-6 fw-normal rounded-0" onclick="decreaseQuantity('Quantity_@(product.Id)_@product.VariantId')" style="border-right: 1px solid #5555">-</button>
227 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="@valueQty" step="@stepQty" @minQty class="form-control swift_quantity-field text-center border-white" style="max-width: 20px; z-index: 1" type="number" onchange="swift.Cart.UpdateOnEnterKey(event)" onkeyup="swift.Cart.UpdateOnEnterKey(event)" @disableAddToCart>
228 <button type="button" class="btn btn-stepper fs-6 fw-normal m-r-5 rounded-0" onclick="increaseQuantity('Quantity_@(product.Id)_@product.VariantId')" style="border-left: 1px solid #5555">+</button>
229 </div>
230 }
231
232 @if (unitsSelector && product.UnitOptions.Count > 0)
233 {
234 string selectedUnitName = !string.IsNullOrEmpty(unitId) && product?.UnitOptions != null ? unitId : product.UnitOptions.FirstOrDefault<UnitOptionViewModel>().Name;
235
236 foreach (var unitOption in product.UnitOptions)
237 {
238 if (unitOption.Id == unitId)
239 {
240 selectedUnitName = unitOption.Name;
241 }
242 }
243
244 <button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
245 @selectedUnitName
246 </button>
247 <ul class="dropdown-menu swift_unit-field">
248 @foreach (var unitOption in product.UnitOptions)
249 {
250 var selectedUnit = unitOption.Id == unitId ? "selected" : "";
251
252 <li>
253 <button type="button" class="btn dropdown-item" data-value="@unitOption.Id" onclick="document.querySelector('#UnitSelectorForm_@(product.Id)_@(product.VariantId)_@Model.ID').querySelector('.js-unit-id').value = this.getAttribute('data-value');
254 document.querySelector('#Unit_@(product.Id)_@product.VariantId').value = this.getAttribute('data-value');
255 swift.PageUpdater.Update(document.querySelector('#UnitSelectorForm_@(product.Id)_@(product.VariantId)_@Model.ID'))">
256 <span>@unitOption.Name</span>
257 <span>
258 @if (unitOption.StockLevel > 0)
259 {
260 if (!Model.Item.GetBoolean("HideInventory"))
261 {
262 <span class="small text-success">@unitOption.StockLevel @Translate("In stock")</span>
263 }
264 else
265 {
266 <span class="small text-success">@Translate("In stock")</span>
267 }
268 }
269 else
270 {
271 <span class="small text-danger">@Translate("Out of Stock")</span>
272 }
273 </span>
274 </button>
275 </li>
276 }
277 </ul>
278 }
279
280 <div>
281 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary @(buttonSize) @flexFill js-add-to-cart-button rounded " style="white-space: nowrap; font-size: 0.9rem;" @disableAddToCart title="@Translate("Add to cart")" id="@addToCartButtonId">
282 @if (!Model.Item.GetBoolean("HideButtonText"))
283 {
284 <span class="text-nowrap d-flex align-items-center justify-content-center gap-2">
285 @addToCartLabel
286 </span>
287
288 }
289 else
290 {
291 @addToCartLabel
292 }
293 </button>
294
295 @if (isProductDetailsPage)
296 {
297
298 <p class="position-absolute top-100 mt-2 pb-2 d-none" id="addedMsg@(product.Id)_@Pageview.CurrentParagraph.ID">@Translate("Lagt i handlekurv")</p>
299 }
300 else
301 {
302 <p class="position-absolute top-100 end-0 mt-2 pb-2 d-none" id="addedMsg@(product.Id)_@Pageview.CurrentParagraph.ID">@Translate("Lagt i handlekurv")</p>
303
304 }
305 </div>
306
307
308 </div>
309 </div>
310 </form>
311 @if (isProductDetailsPage && !isMasterWithVariant)
312 {
313 //var totalItemsInStock = Proff1Services.StockService.GetStockInfo(product.Number).Sum(stockInfo => stockInfo.ItemsInStock);
314
315
316
317 <div class="stock-status py-2">
318 <span class="stock-label text-decoration-underline">Lagerstatus</span>
319
320 <div class="stock-info">
321
322 @foreach (var stockInfo in Proff1Services.StockService.GetStockInfo(product.Number))
323 {
324 <span>@stockInfo.LocationName: @stockInfo.ItemsInStock</span><br />
325 }
326 </div>
327 </div>
328 <div class="stock-status pt-3">
329 @if (totalItemsInStock <= 0)
330 {
331
332
333 if (Convert.ToInt32(deliveryDays) > 0)
334 {
335 <p class="m-0 small d-flex align-items-center lh-1">
336 <span class="bg-danger me-2 stock__dot"></span>@Translate("Order item - Expected delivery time") @deliveryDays @Translate("days")
337 </p>
338 }
339 else
340 {
341 <p class="m-0 small d-flex align-items-center lh-1">
342 <span class="bg-danger me-2 stock__dot"></span>@Translate("Order item - Expected delivery time unknown, please contact us")
343 </p>
344 }
345
346 }
347 else if (totalItemsInStock <= 4)
348 {
349
350 <p class="m-0 small d-flex align-items-center lh-1">
351 <span class="bg-warning me-2 stock__dot"></span>@Translate("5 In Stock")
352 </p>
353 }
354 else if (totalItemsInStock <= 9)
355 {
356 <p class="m-0 small d-flex align-items-center lh-1">
357 <span class="bg-success me-2 stock__dot"></span>@Translate("5-10 In Stock")
358 </p>
359 }
360 else if (totalItemsInStock <= 99)
361 {
362 <p class="m-0 small d-flex align-items-center lh-1">
363 <span class="bg-success me-2 stock__dot"></span>@Translate("10 In Stock")
364 </p>
365 }
366 else if (totalItemsInStock >= 100)
367 {
368 <p class="m-0 small d-flex align-items-center lh-1">
369 <span class="bg-success me-2 stock__dot"></span>@Translate("100+ In Stock")
370 </p>
371 }
372 </div>
373 }
374 else if (isProductDetailsPage && isMasterWithVariant)
375 {
376 <div class="stock-status pt-3">
377 <p class="m-0 small d-flex align-items-center lh-1">
378 @Translate("Choose a product/variant to see stock status")
379 </p>
380 </div>
381 }
382
383 </div>
384
385
386 }
387 else
388 {
389 string buttonText = Translate("Select");
390
391 string variantSelectorServicePageId = !string.IsNullOrEmpty(Model.Item.GetString("VariantSelectorServicePageId")) ? Model.Item.GetLink("VariantSelectorServicePageId").PageId.ToString() : "";
392 variantSelectorServicePageId = variantSelectorServicePageId != "" ? variantSelectorServicePageId : GetPageIdByNavigationTag("VariantSelectorService").ToString();
393 string link = product.GetProductLink(GetPageIdByNavigationTag("Shop"), false);
394
395 <div class="d-flex @horizontalAlign w-100 item_@Model.Item.SystemName.ToLower()">
396 @if (!anonymousUser && favoritesSelector)
397 {
398 @RenderPartial("Components/ToggleFavorite.cshtml", product)
399 }
400 <form action="/Default.aspx?ID=@variantSelectorServicePageId" data-response-target-element="DynamicModalContent" data-preloader="inline" style="z-index: 1" class="@fullWidth">
401 <input type="hidden" name="ProductID" value="@product.Id">
402 <input type="hidden" name="QuantitySelector" value="@quantitySelector.ToString()">
403 <input type="hidden" name="HideInventory" value="@hideInventory.ToString()">
404 <input type="hidden" name="HideStockState" value="@hideStockState.ToString()">
405 <input type="hidden" name="VariantSelectorServicePage" value="@variantSelectorServicePageId">
406 <input type="hidden" name="ViewType" value="ModalContent">
407 <a href="@link" class="btn btn-primary" title="@Translate("Select")">@buttonText</a>
408 </form>
409 </div>
410 }
411 }
412 else if (Pageview.IsVisualEditorMode)
413 {
414 <div class="alert alert-dark m-0">@Translate("No products available")</div>
415 }
416
417 @{
418 var text = "available online and in store.";
419 var translated = @Translate(text);
420 string metaDescription = $"Vi har {(string.IsNullOrEmpty(productBrand) ? "" : productBrand + " ")}{product.Name} {translated} Proff1 hjelper deg med {lastGroup}.";
421 string metaTitle = $"{(string.IsNullOrEmpty(productBrand) ? "" : productBrand + " ")}{product.Name}";
422 }
423
424 <script>
425
426 function decreaseQuantity(inputId) {
427 const input = document.getElementById(inputId);
428 const currentValue = parseInt(input.value);
429
430 if (currentValue > 1) {
431 input.value = currentValue - 1;
432 }
433 }
434
435 function increaseQuantity(inputId) {
436 const input = document.getElementById(inputId);
437 const currentValue = parseInt(input.value);
438
439 input.value = currentValue + 1;
440 }
441
442 function UpdateCart(productId) {
443
444 }
445
446 function UpdateCart(event) {
447 var buttonId = event.target.id;
448
449 var productId = buttonId.split('_')[0].replace('AddToCartButton', '');
450
451
452 var messageElement = document.getElementById("@addedMessageId");
453
454
455 messageElement.classList.remove('d-none');
456
457 setTimeout(function () {
458 messageElement.classList.add('d-none');
459 }, 1000);
460 };
461
462
463 var addToCartButton = document.getElementById("@addToCartButtonId");
464
465 if (addToCartButton) {
466
467 addToCartButton.addEventListener('click', UpdateCart);
468 }
469 </script>
470
471
472 @if (!string.IsNullOrEmpty(productIdTag))
473 {
474 <!--$$SnippetStart(meta)-->
475 <meta name="description" content="@metaDescription" />
476 <title>@metaTitle</title>
477 <meta property="og:title" content="@metaTitle">
478
479 <!--$$SnippetEnd(meta)-->
480 }
481