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_bf151690a7184280b0a04c89c4e4a1be.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
91 string addToCartButtonText = Translate("Add to cart");
92
93
94
95
96
97 if (!product.NeverOutOfstock && totalItemsInStock <= 0)
98
99
100
101
102 {
103 addToCartButtonText = Translate("Ikke på lager");
104 }
105 else if (totalItemsInStock <= 0)
106 {
107 addToCartButtonText = Translate("Bestill");
108 }
109
110 disableAddToCart = isNeverOutOfStock ? "" : disableAddToCart;
111
112 string whenVariantsExist = Model.Item.GetRawValueString("WhenVariantsExist", "hide");
113
114 string flexFill = Model.Item.GetRawValueString("HorizontalAlignment", "") == "full" ? "flex-fill" : "";
115 string fullWidth = Model.Item.GetRawValueString("HorizontalAlignment", "") == "full" ? "w-100" : "";
116 string addToCartIcon = Model.Item.GetRawValueString("Icon", iconPath + "shopping-cart.svg");
117 string checkIcon = Model.Item.GetRawValueString("Icon", iconPath + "check.svg");
118 string addToCartLabel = !addToCartIcon.Contains("_none") ? "<span class=\"icon-2\">" + ReadFile(addToCartIcon) + "</span>" : "";
119 addToCartLabel += !addToCartIcon.Contains("_none") && !Model.Item.GetBoolean("HideButtonText") ? " " : "";
120 addToCartLabel += !Model.Item.GetBoolean("HideButtonText") ? addToCartButtonText : "";
121
122
123 string productId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : "";
124 bool isProductDetailsPage = !string.IsNullOrEmpty(productId);
125 bool isMasterWithVariant = product.VariantInfo.VariantInfo != null && string.IsNullOrEmpty(product.VariantId);
126
127 var deliveryDays = product.ProductFields["P1_Product_Delivery_Days"].Value;
128
129 if (product.VariantInfo.VariantInfo == null || isProductDetailsPage)
130 {
131 string unitId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("UnitId")) ? Dynamicweb.Context.Current.Request.Form.Get("UnitId") : product.DefaultUnitId;
132 if (string.IsNullOrEmpty(unitId) && product?.UnitOptions != null)
133 {
134 if (product.UnitOptions.FirstOrDefault<UnitOptionViewModel>() != null)
135 {
136 unitId = product.UnitOptions.FirstOrDefault<UnitOptionViewModel>().Id;
137 }
138 }
139
140 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\"";
141 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1";
142 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty;
143 disableAddToCart = product.VariantInfo.VariantInfo != null && string.IsNullOrEmpty(product.VariantId) ? "disabled" : disableAddToCart;
144
145 var reserveMode = Dynamicweb.Ecommerce.Frontend.Cart.ProductReserve.Mode;
146
147 if (unitsSelector && product.UnitOptions.Count > 0)
148 {
149 <form method="post" action="/Default.aspx?ID=@(Pageview.Page.ID)&ProductId=@product.Id" id="UnitSelectorForm_@(product.Id)_@(product.VariantId)_@Model.ID">
150 <input type="hidden" name="redirect" value="false">
151 <input type="hidden" name="VariantID" value="@product.VariantId">
152 <input type="hidden" name="UnitID" class="js-unit-id" value="@unitId">
153 </form>
154 }
155
156 <div class="d-grid @horizontalAlign @fullWidth js-input-group item_@Model.Item.SystemName.ToLower()">
157 <form method="post" action="@url" class="@fullWidth" style="z-index: 1">
158 <input type="hidden" name="redirect" value="false">
159 <input type="hidden" name="ProductId" value="@product.Id">
160 <input type="hidden" name="ProductName" value="@product.Name">
161 <input type="hidden" name="ProductVariantName" value="@product.VariantName">
162 <input type="hidden" name="ProductCurrency" value="@Dynamicweb.Ecommerce.Common.Context.Currency.Code">
163 <input type="hidden" name="ProductPrice" value="@PriceViewModelExtensions.ToStringInvariant(product.Price)">
164 <input type="hidden" name="ProductReferer" value="component_ProductAddToCart">
165 <input type="hidden" name="cartcmd" value="add">
166
167 @if (reserveMode == Dynamicweb.Ecommerce.Frontend.Cart.ProductReserveMode.AddToCart)
168 {
169 <input type="hidden" name="GetReservedAmount" value="true">
170 }
171
172 @if (!string.IsNullOrEmpty(product.VariantId))
173 {
174 <input type="hidden" name="VariantId" value="@product.VariantId">
175 }
176
177 @if (!product.NeverOutOfstock)
178 {
179 <input type="hidden" name="Stock" value="@product.StockLevel">
180
181 <template class="js-out-of-stock-notice">
182 <div class="modal-header">
183 <h1 class="modal-title fs-5">@Translate("Stock limit")</h1>
184 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
185 </div>
186 <div class="modal-body">
187 @Translate("There are not enough products in stock. The product might be sold out or discontinued. Please adjust the quantity.")
188 </div>
189 </template>
190 }
191
192 @if (stepQty != "1")
193 {
194 <template class="js-step-quantity-warning">
195 <div class="modal-header">
196 <h1 class="modal-title fs-5">@Translate("The quantity is not valid")</h1>
197 </div>
198 <div class="modal-body">
199 @Translate("Please select a quantity that is dividable by") @stepQty
200 </div>
201 </template>
202 }
203 @if (product.PurchaseMinimumQuantity != 1)
204 {
205 <template class="js-min-quantity-warning">
206 <div class="modal-header">
207 <h1 class="modal-title fs-5">@Translate("The product could not be added to the cart")</h1>
208 </div>
209 <div class="modal-body">
210 @Translate("The quantity is not valid. You must buy at least") @product.PurchaseMinimumQuantity
211 </div>
212 </template>
213 }
214
215 @if (quantitySelector || (!anonymousUser && product.VariantInfo.VariantInfo != null) || (!anonymousUser && favoritesSelector))
216 {
217 <input type="hidden" id="Unit_@(product.Id)_@product.VariantId" name="UnitID" value="@unitId" />
218 }
219
220 <div class="d-flex flex-row w-100">
221 @if (!anonymousUser && favoritesSelector)
222 {
223 @RenderPartial("Components/ToggleFavorite.cshtml", product)
224 }
225
226 @if (!quantitySelector)
227 {
228 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="@valueQty" type="hidden" @disableAddToCart>
229 }
230
231 <div class="input-group input-primary-button-group flex-nowrap@(inputSize)">
232 @if (quantitySelector)
233 {
234 <div class="d-flex me-2" style="border: 1px solid #5555">
235 <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>
236 <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>
237 <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>
238 </div>
239 }
240
241 @if (unitsSelector && product.UnitOptions.Count > 0)
242 {
243 string selectedUnitName = !string.IsNullOrEmpty(unitId) && product?.UnitOptions != null ? unitId : product.UnitOptions.FirstOrDefault<UnitOptionViewModel>().Name;
244
245 foreach (var unitOption in product.UnitOptions)
246 {
247 if (unitOption.Id == unitId)
248 {
249 selectedUnitName = unitOption.Name;
250 }
251 }
252
253 <button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
254 @selectedUnitName
255 </button>
256 <ul class="dropdown-menu swift_unit-field">
257 @foreach (var unitOption in product.UnitOptions)
258 {
259 var selectedUnit = unitOption.Id == unitId ? "selected" : "";
260
261 <li>
262 <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');
263 document.querySelector('#Unit_@(product.Id)_@product.VariantId').value = this.getAttribute('data-value');
264 swift.PageUpdater.Update(document.querySelector('#UnitSelectorForm_@(product.Id)_@(product.VariantId)_@Model.ID'))">
265 <span>@unitOption.Name</span>
266 <span>
267 @if (unitOption.StockLevel > 0)
268 {
269 if (!Model.Item.GetBoolean("HideInventory"))
270 {
271 <span class="small text-success">@unitOption.StockLevel @Translate("In stock")</span>
272 }
273 else
274 {
275 <span class="small text-success">@Translate("In stock")</span>
276 }
277 }
278 else
279 {
280 <span class="small text-danger">@Translate("Out of Stock")</span>
281 }
282 </span>
283 </button>
284 </li>
285 }
286 </ul>
287 }
288
289 <div>
290 <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">
291 @if (!Model.Item.GetBoolean("HideButtonText"))
292 {
293 <span class="text-nowrap d-flex align-items-center justify-content-center gap-2">
294 @addToCartLabel
295 </span>
296
297 }
298 else
299 {
300 @addToCartLabel
301 }
302 </button>
303
304 @if (isProductDetailsPage)
305 {
306
307 <p class="position-absolute top-100 mt-2 pb-2 d-none" id="addedMsg@(product.Id)_@Pageview.CurrentParagraph.ID">@Translate("Lagt i handlekurv")</p>
308 }
309 else
310 {
311 <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>
312
313 }
314 </div>
315
316
317 </div>
318 </div>
319 </form>
320 @if (isProductDetailsPage && !isMasterWithVariant)
321 {
322 //var totalItemsInStock = Proff1Services.StockService.GetStockInfo(product.Number).Sum(stockInfo => stockInfo.ItemsInStock);
323
324
325
326 <div class="stock-status py-2">
327 <span class="stock-label text-decoration-underline">Lagerstatus</span>
328
329 <div class="stock-info">
330
331 @foreach (var stockInfo in Proff1Services.StockService.GetStockInfo(product.Number))
332 {
333 <span>@stockInfo.LocationName: @stockInfo.ItemsInStock</span><br />
334 }
335 </div>
336 </div>
337 <div class="stock-status pt-3">
338 @if (totalItemsInStock <= 0)
339 {
340
341
342 if (Convert.ToInt32(deliveryDays) > 0)
343 {
344 <p class="m-0 small d-flex align-items-center lh-1">
345 <span class="bg-danger me-2 stock__dot"></span>@Translate("Order item - Expected delivery time") @deliveryDays @Translate("days")
346 </p>
347 }
348 else
349 {
350 <p class="m-0 small d-flex align-items-center lh-1">
351 <span class="bg-danger me-2 stock__dot"></span>@Translate("Order item - Expected delivery time unknown, please contact us")
352 </p>
353 }
354
355 }
356 else if (totalItemsInStock <= 4)
357 {
358
359 <p class="m-0 small d-flex align-items-center lh-1">
360 <span class="bg-warning me-2 stock__dot"></span>@Translate("5 In Stock")
361 </p>
362 }
363 else if (totalItemsInStock <= 9)
364 {
365 <p class="m-0 small d-flex align-items-center lh-1">
366 <span class="bg-success me-2 stock__dot"></span>@Translate("5-10 In Stock")
367 </p>
368 }
369 else if (totalItemsInStock <= 99)
370 {
371 <p class="m-0 small d-flex align-items-center lh-1">
372 <span class="bg-success me-2 stock__dot"></span>@Translate("10 In Stock")
373 </p>
374 }
375 else if (totalItemsInStock >= 100)
376 {
377 <p class="m-0 small d-flex align-items-center lh-1">
378 <span class="bg-success me-2 stock__dot"></span>@Translate("100+ In Stock")
379 </p>
380 }
381 </div>
382 }
383 else if (isProductDetailsPage && isMasterWithVariant)
384 {
385 <div class="stock-status pt-3">
386 <p class="m-0 small d-flex align-items-center lh-1">
387 @Translate("Choose a product/variant to see stock status")
388 </p>
389 </div>
390 }
391
392 </div>
393
394
395 }
396 else
397 {
398 string buttonText = Translate("Select");
399
400 string variantSelectorServicePageId = !string.IsNullOrEmpty(Model.Item.GetString("VariantSelectorServicePageId")) ? Model.Item.GetLink("VariantSelectorServicePageId").PageId.ToString() : "";
401 variantSelectorServicePageId = variantSelectorServicePageId != "" ? variantSelectorServicePageId : GetPageIdByNavigationTag("VariantSelectorService").ToString();
402 string link = product.GetProductLink(GetPageIdByNavigationTag("Shop"), false);
403
404 <div class="d-flex @horizontalAlign w-100 item_@Model.Item.SystemName.ToLower()">
405 @if (!anonymousUser && favoritesSelector)
406 {
407 @RenderPartial("Components/ToggleFavorite.cshtml", product)
408 }
409 <form action="/Default.aspx?ID=@variantSelectorServicePageId" data-response-target-element="DynamicModalContent" data-preloader="inline" style="z-index: 1" class="@fullWidth">
410 <input type="hidden" name="ProductID" value="@product.Id">
411 <input type="hidden" name="QuantitySelector" value="@quantitySelector.ToString()">
412 <input type="hidden" name="HideInventory" value="@hideInventory.ToString()">
413 <input type="hidden" name="HideStockState" value="@hideStockState.ToString()">
414 <input type="hidden" name="VariantSelectorServicePage" value="@variantSelectorServicePageId">
415 <input type="hidden" name="ViewType" value="ModalContent">
416 <a href="@link" class="btn btn-primary" title="@Translate("Select")">@buttonText</a>
417 </form>
418 </div>
419 }
420 }
421 else if (Pageview.IsVisualEditorMode)
422 {
423 <div class="alert alert-dark m-0">@Translate("No products available")</div>
424 }
425
426 @{
427 var text = "available online and in store.";
428 var translated = @Translate(text);
429 string metaDescription = $"Vi har {(string.IsNullOrEmpty(productBrand) ? "" : productBrand + " ")}{product.Name} {translated} Proff1 hjelper deg med {lastGroup}.";
430 string metaTitle = $"{(string.IsNullOrEmpty(productBrand) ? "" : productBrand + " ")}{product.Name}";
431 }
432
433 <script>
434
435 function decreaseQuantity(inputId) {
436 const input = document.getElementById(inputId);
437 const currentValue = parseInt(input.value);
438
439 if (currentValue > 1) {
440 input.value = currentValue - 1;
441 }
442 }
443
444 function increaseQuantity(inputId) {
445 const input = document.getElementById(inputId);
446 const currentValue = parseInt(input.value);
447
448 input.value = currentValue + 1;
449 }
450
451 function UpdateCart(productId) {
452
453 }
454
455 function UpdateCart(event) {
456 var buttonId = event.target.id;
457
458 var productId = buttonId.split('_')[0].replace('AddToCartButton', '');
459
460
461 var messageElement = document.getElementById("@addedMessageId");
462
463
464 messageElement.classList.remove('d-none');
465
466 setTimeout(function () {
467 messageElement.classList.add('d-none');
468 }, 1000);
469 };
470
471
472 var addToCartButton = document.getElementById("@addToCartButtonId");
473
474 if (addToCartButton) {
475
476 addToCartButton.addEventListener('click', UpdateCart);
477 }
478 </script>
479
480
481 @if (!string.IsNullOrEmpty(productIdTag))
482 {
483 <!--$$SnippetStart(meta)-->
484 <meta name="description" content="@metaDescription" />
485 <title>@metaTitle</title>
486 <meta property="og:title" content="@metaTitle">
487
488 <!--$$SnippetEnd(meta)-->
489 }
490