Error executing template "Designs/Swift/Components/EcommerceBadge.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, ProductFieldValue pfv) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetProductFieldValues(ProductViewModelSettings settings, Product product) at System.Lazy`1.CreateValue() at System.Lazy`1.LazyInitValue() at CompiledRazorTemplates.Dynamic.RazorEngine_0f3a55a9b5ae4ce291dbeec6780c295d.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Components\EcommerceBadge.cshtml:line 83 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 ViewModelTemplate<ProductViewModel> 2 @using Dynamicweb.Frontend 3 @using Dynamicweb.Content 4 @using Dynamicweb.Rendering 5 @using Dynamicweb.Ecommerce.ProductCatalog 6 7 @{ 8 string sizeCssClass = GetViewParameter("size") != null ? GetViewParameter("size").ToString() : ""; 9 string newBadgeCssClassName = GetViewParameter("newBadgeCssClassName") != null ? GetViewParameterString("newBadgeCssClassName").Trim().ToLower() : ""; 10 bool newBadgeEnabled = newBadgeCssClassName != "" && newBadgeCssClassName != "none" ? true : false; 11 12 List<string> campaignBadgesValues = GetViewParameter("campaignBadgesValues") != null ? GetViewParameterString("campaignBadgesValues").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List<string>(); 13 } 14 15 16 @if (Model.Discount.Price != 0) 17 { 18 string saleBadgeCssClassName = GetViewParameter("saleBadgeCssClassName") != null ? GetViewParameterString("saleBadgeCssClassName").Trim().ToLower() : ""; 19 bool saleBadgeEnabled = saleBadgeCssClassName != "" && saleBadgeCssClassName != "none" ? true : false; 20 21 if (saleBadgeEnabled) 22 { 23 string saleBadgeType = GetViewParameter("saleBadgeType") != null ? GetViewParameterString("saleBadgeType") : "amount"; 24 string title = saleBadgeType == "amount" ? "-" + Model.Discount.PriceFormatted : ""; 25 title = saleBadgeType == "percentage" ? "-" + Math.Round((Model.Discount.Price / Model.PriceBeforeDiscount.Price) * 100) + "%" : title; 26 27 string hideAutoLabel = ""; 28 if (saleBadgeType == "amount" || saleBadgeType == "percentage") 29 { 30 hideAutoLabel = "badge-no-label"; 31 } 32 33 <span class="@sizeCssClass"><span class="badge @hideAutoLabel @(saleBadgeCssClassName) rounded-0">@title</span></span> 34 } 35 } 36 37 @if (newBadgeEnabled) 38 { 39 DateTime createdDate = Model.Created.Value; 40 double newPublicationDays = GetViewParameter("newPublicationDays") != null ? GetViewParameterDouble("newPublicationDays") : 0; 41 42 if ((newPublicationDays == 0) || (createdDate.AddDays(newPublicationDays) > DateTime.Now)) 43 { 44 <span class="@sizeCssClass"><span class="badge @newBadgeCssClassName rounded-0"></span></span> 45 } 46 } 47 48 @if (campaignBadgesValues.Any()) 49 { 50 Dictionary<string, ParagraphInfoViewModel> badgeConfigurations; 51 52 if (Dynamicweb.Context.Current.Items.Contains("badgeConfigurations")) 53 { 54 badgeConfigurations = (Dictionary<string, ParagraphInfoViewModel>)Dynamicweb.Context.Current.Items["badgeConfigurations"]; 55 } 56 else 57 { 58 var badgesPage = Pageview.AreaSettings.GetLink("EcommerceBadgesPage") != null ? Pageview.AreaSettings.GetLink("EcommerceBadgesPage").PageId : 0; 59 var allBadges = badgesPage != 0 ? Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(badgesPage) : null; 60 61 badgeConfigurations = new Dictionary<string, ParagraphInfoViewModel>(); 62 foreach (Paragraph badge in allBadges) 63 { 64 var paragraphviewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreateParagraphInfoViewModel(badge); 65 string cssClassName = paragraphviewModel.Item.GetString("CssClassName").Trim().ToLower(); 66 if (!badgeConfigurations.ContainsKey(cssClassName)) 67 { 68 badgeConfigurations.Add(cssClassName, paragraphviewModel); 69 } 70 } 71 Dynamicweb.Context.Current.Items.Add("badgeConfigurations", badgeConfigurations); 72 } 73 74 int badgesCount = 0; 75 if (badgeConfigurations.Any()) 76 { 77 foreach (string campaign in campaignBadgesValues) 78 { 79 if (!string.IsNullOrEmpty(campaign)) 80 { 81 82 FieldValueViewModel availableCampaignsObject; 83 Model.ProductFields.TryGetValue("Campaign", out availableCampaignsObject); 84 85 if (availableCampaignsObject != null) 86 { 87 string campaignType = string.Empty; 88 89 if (badgeConfigurations.ContainsKey(campaign)) 90 { 91 ParagraphInfoViewModel paragraphviewModel; 92 if (badgeConfigurations.TryGetValue(campaign, out paragraphviewModel)) 93 { 94 campaignType = paragraphviewModel.Item.GetRawValueString("CampaignType"); 95 } 96 } 97 98 List<FieldOptionValueViewModel> availableCampaigns = (List<FieldOptionValueViewModel>)availableCampaignsObject.Value; 99 100 foreach (FieldOptionValueViewModel availableOption in availableCampaigns) 101 { 102 if (campaignType == availableOption.Value) 103 { 104 <span class="@sizeCssClass"><span class="badge @campaign.Trim().ToLower() rounded-0"></span></span> 105 badgesCount++; 106 break; 107 } 108 } 109 } 110 } 111 } 112 } 113 114 if (badgesCount == 0 && Pageview.IsVisualEditorMode) 115 { 116 <span class="@sizeCssClass"><span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span></span> 117 } 118 } 119 else if (Pageview.IsVisualEditorMode) 120 { 121 <span class="@sizeCssClass"><span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span></span> 122 } 123
Error executing template "Designs/Swift/Paragraph/Swift_ProductBadges.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, ProductFieldValue pfv) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetProductFieldValues(ProductViewModelSettings settings, Product product) at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_eb246b8e4a2640dcb2cae07b630e1a3c.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductBadges.cshtml:line 72 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.Frontend 3 @using Dynamicweb.Content 4 @using Dynamicweb.Ecommerce.ProductCatalog 5 6 @{ 7 ProductViewModel product = null; 8 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 9 { 10 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 11 } 12 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 13 { 14 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 15 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 16 17 if (productList?.Products is object) 18 { 19 product = productList.Products[0]; 20 } 21 } 22 } 23 24 @if (product is object) { 25 var badgeParms = new Dictionary<string, object>(); 26 badgeParms.Add("size", "h7"); 27 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 28 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 29 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 30 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 31 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 32 33 string badgeSize = Model.Item.GetRawValueString("BadgeSize", "fs-2"); 34 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 35 horizontalAlign = horizontalAlign == "center" ? "text-center" : horizontalAlign; 36 horizontalAlign = horizontalAlign == "end" ? "text-end" : horizontalAlign; 37 38 Dictionary<string, ParagraphInfoViewModel> badgeConfigurations; 39 List<string> campaignBadgesValues = Model.Item.GetRawValueString("CampaignBadges") != null ? Model.Item.GetRawValueString("CampaignBadges").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List<string>(); 40 41 if (Dynamicweb.Context.Current.Items.Contains("badgeConfigurations")) 42 { 43 badgeConfigurations = (Dictionary<string, ParagraphInfoViewModel>)Dynamicweb.Context.Current.Items["badgeConfigurations"]; 44 } 45 else 46 { 47 var badgesPage = Pageview.AreaSettings.GetLink("EcommerceBadgesPage") != null ? Pageview.AreaSettings.GetLink("EcommerceBadgesPage").PageId : 0; 48 var allBadges = badgesPage != 0 ? Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(badgesPage) : null; 49 50 badgeConfigurations = new Dictionary<string, ParagraphInfoViewModel>(); 51 foreach (Paragraph badge in allBadges) 52 { 53 var paragraphviewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreateParagraphInfoViewModel(badge); 54 string cssClassName = paragraphviewModel.Item.GetString("CssClassName").Trim().ToLower(); 55 if (!badgeConfigurations.ContainsKey(cssClassName)) 56 { 57 badgeConfigurations.Add(cssClassName, paragraphviewModel); 58 } 59 } 60 Dynamicweb.Context.Current.Items.Add("badgeConfigurations", badgeConfigurations); 61 } 62 63 int badgesCount = 0; 64 if (badgeConfigurations.Any()) 65 { 66 foreach (string campaign in campaignBadgesValues) 67 { 68 if (!string.IsNullOrEmpty(campaign)) 69 { 70 71 FieldValueViewModel availableCampaignsObject; 72 product.ProductFields.TryGetValue("Campaign", out availableCampaignsObject); 73 74 if (availableCampaignsObject != null) 75 { 76 string campaignType = string.Empty; 77 78 if (badgeConfigurations.ContainsKey(campaign)) 79 { 80 ParagraphInfoViewModel paragraphviewModel; 81 if (badgeConfigurations.TryGetValue(campaign, out paragraphviewModel)) 82 { 83 campaignType = paragraphviewModel.Item.GetRawValueString("CampaignType"); 84 } 85 } 86 87 List<FieldOptionValueViewModel> availableCampaigns = (List<FieldOptionValueViewModel>)availableCampaignsObject.Value; 88 89 foreach (FieldOptionValueViewModel availableOption in availableCampaigns) 90 { 91 if (campaignType == availableOption.Value) 92 { 93 badgesCount++; 94 break; 95 } 96 } 97 } 98 } 99 } 100 } 101 102 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 103 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 104 DateTime createdDate = product.Created.Value; 105 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 106 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 107 showBadges = (!string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) && badgesCount != 0) ? true : showBadges; 108 109 if (showBadges) 110 { 111 <div class="@badgeSize @horizontalAlign item_@Model.Item.SystemName.ToLower()"> 112 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 113 </div> 114 } 115 else if (Pageview.IsVisualEditorMode) 116 { 117 <span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span> 118 } 119 } 120 else if (Pageview.IsVisualEditorMode) 121 { 122 <span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span> 123 } 124 125
BONDI chair - Turmeric Yellow
Error executing template "/Designs/Swift/Paragraph/Swift_ProductVariantSelector_Custom.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, ProductFieldValue pfv) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetProductFieldValues(ProductViewModelSettings settings, Product product) at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_11e29021130040f29b7bbffac9d1407d.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductVariantSelector_Custom.cshtml:line 88 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 System 3 @using System.Collections.Generic 4 @using Dynamicweb.Ecommerce.ProductCatalog 5 @using Dynamicweb.Core 6 @using System.Web 7 @using System.Globalization 8 @using System.Linq 9 @using System.Text.RegularExpressions 10 11 @* TODO: REFACTURE/UPGRADE TO SWIFT (v1.25.0) *@ 12 13 @functions { 14 15 //Find contrast color (white, black) 16 public static string GetContrastColor(string hexString) 17 { 18 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 19 20 int nThreshold = 105; 21 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + (bg.B * 0.114)); 22 23 string foreColor = (255 - bgDelta < nThreshold) ? "#333" : "#fff"; 24 return foreColor; 25 } 26 27 public bool TryExtractDouble(string input, out double result) 28 { 29 result = 0; 30 if (string.IsNullOrWhiteSpace(input)) 31 return false; 32 33 Match match = Regex.Match(input, @"(\d+[\,\. ])+", RegexOptions.IgnoreCase, 34 TimeSpan.FromMilliseconds(5000)); 35 if (match.Success) 36 { 37 string numberStr = match.Value.Trim(); 38 return double.TryParse(numberStr, NumberStyles.Any, new CultureInfo("en-US").NumberFormat, out result); 39 } 40 41 return false; 42 } 43 44 } 45 46 @{ 47 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false; 48 49 ProductViewModel product = new ProductViewModel(); 50 51 ProductViewModelSettings productSetting = new ProductViewModelSettings 52 { 53 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID, 54 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code, 55 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2, 56 ShopId = Pageview.Area.EcomShopId 57 }; 58 59 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 60 { 61 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 62 } 63 else if (Pageview.Item["DummyProduct"] != null) 64 { 65 string dummyProductId = ""; 66 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 67 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 68 if (productList.Products != null) 69 { 70 foreach (var p in productList.Products) 71 { 72 dummyProductId = p.Id; 73 } 74 75 ProductViewModel dummyProduct = dummyProductId != "" ? ViewModelFactory.CreateView(productSetting, dummyProductId) : new ProductViewModel(); 76 product = dummyProduct; 77 } 78 else 79 { 80 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 81 } 82 } 83 else if (Pageview.Item["DummyProduct"] == null) 84 { 85 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 86 } 87 88 bool isColorVariant = product.ProductFields.ContainsKey("Custom_ColorVariantOnWeb") ? Converter.ToBoolean(product.ProductFields["Custom_ColorVariantOnWeb"].Value) : false; 89 90 IEnumerable<ProductViewModel> relatedProducts = product.GetRelatedProducts(); 91 relatedProducts = Smartpage.EvaSolo.Assortment.Helpers.RelatedProducts.FilterOutNonAvailableRelatedProducts(relatedProducts); 92 string[] variantId = { }; 93 94 if (product?.VariantId != null) 95 { 96 variantId = product.VariantId.Split('.'); 97 } 98 99 if (relatedProducts.Any()) 100 { 101 relatedProducts = relatedProducts.Prepend(product); 102 103 bool hideVariantInfoOnProduct = Converter.ToBoolean(Pageview.AreaSettings.GetItem("CustomSettings").GetRawValueString("HideVariantInfoOnProduct_Custom")); 104 105 if (!hideVariantInfoOnProduct) 106 { 107 <div> 108 @if (isColorVariant) 109 { 110 string productFieldCustomColor = product.ProductFields.ContainsKey("Custom_Color") ? Converter.ToString(product.ProductFields["Custom_Color"].Value) : null; 111 <span>@Translate("Custom:Variant.Color.Info", "Farve"): <b>@productFieldCustomColor</b></span> 112 } 113 else 114 { 115 string productFieldCustomSize = product.ProductFields.ContainsKey("Custom_Size") ? Converter.ToString(product.ProductFields["Custom_Size"].Value) : null; 116 <span>@Translate("Custom:Variant.Size.Info", "Størrelse"): <b>@productFieldCustomSize</b></span> 117 } 118 </div> 119 } 120 121 <div class="p-0 mt-2"> @* container overflow-hidden*@ 122 @if (isColorVariant && Model.Item.GetRawValueString("Custom_ColorVariantLayout", "Slider") == "slider") 123 { 124 @RenderRelatedProductSliders(relatedProducts, product) 125 } 126 else 127 { 128 @RenderRelatedProducts(relatedProducts, product, isColorVariant) 129 } 130 </div> 131 } 132 133 if (product.VariantInfo.VariantInfo != null && !Model.Item.GetBoolean("HideVariantSelector")) 134 { 135 int groupNumber = 1; 136 137 <form class="js-variant-selector" data-combinations="@string.Join(",", product.VariantCombinations())"> 138 <input type="hidden" name="variantid"/> 139 140 @foreach (var variantGroup in product.VariantGroups()) 141 { 142 VariantGroupViewModel group = variantGroup; 143 144 <h3 class="h6">@group.Name</h3> 145 <div class="d-flex gap-2 flex-wrap js-variant-group" data-group-id="@groupNumber"> 146 @foreach (var option in group.Options) 147 { 148 string active = variantId.Contains(option.Id) ? "active" : ""; 149 150 if (!string.IsNullOrEmpty(option.Color)) 151 { 152 string contrastColor = GetContrastColor(option.Color); 153 <button type="button" 154 class="btn colorbox rounded-circle d-inline-block variant-option border js-variant-option @active" 155 style="background-color: @option.Color; --variantoption-check-color: @contrastColor" 156 onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" 157 id="@(product.Id)_@(option.Id)_@Pageview.CurrentParagraph.ID"></button> 158 } 159 else if (!string.IsNullOrEmpty(option.Color) && !string.IsNullOrEmpty(option.Image.Value)) 160 { 161 <button type="button" 162 class="btn p-0 d-inline-block variant-option border js-variant-option @active" 163 onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"> 164 <img 165 src="/Admin/Public/GetImage.ashx?image=@(option.Image.Value)&width=42&Format=WebP&Quality=70" /> 166 </button> 167 } 168 else 169 { 170 <button type="button" 171 class="btn btn-secondary d-inline-block variant-option js-variant-option @active" 172 onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"> 173 @option.Name 174 </button> 175 } 176 } 177 </div> 178 179 groupNumber++; 180 } 181 </form> 182 } 183 } 184 185 186 @helper RenderRelatedProducts(IEnumerable<ProductViewModel> relatedProducts, ProductViewModel product, bool isColorVariant) 187 { 188 int variantsToShow = 100; 189 int counter = 1; 190 bool showMoreButton = true; 191 192 if (isColorVariant == false) 193 { 194 relatedProducts = relatedProducts.OrderBy(rp => 195 { 196 double size = double.MaxValue; // default if parse fails 197 if (rp.ProductFields.TryGetValue("Custom_Size", out var sizeFieldValue) && 198 TryExtractDouble(sizeFieldValue?.Value?.ToString(), out var parsed)) 199 { 200 size = parsed; 201 } 202 203 return size; 204 }); 205 } 206 207 <div class="js-related-products-wrapper"> 208 <div class="related-products-container js-related-products-container"> 209 @if (showMoreButton) 210 { 211 <button class="p-2 js-show-all btn-show-all text-center"> 212 <span>+</span><span class="js-hidden-variants-count"></span> 213 </button> 214 } 215 @foreach (ProductViewModel relatedProduct in relatedProducts) 216 { 217 bool isActive = product.Id == relatedProduct.Id; 218 @RenderRelatedProduct(relatedProduct, isActive, (counter > variantsToShow), isColorVariant) 219 counter++; 220 } 221 </div> 222 </div> 223 } 224 225 @helper RenderRelatedProduct(ProductViewModel relatedProduct, bool isActive, bool isHidden, bool isColorVariant = true) 226 { 227 var productListPageId = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ProductListPage")) ? Model.Item.GetInt32("ProductListPage") : GetPageIdByNavigationTag("Shop"); 228 var relatedProductLink = relatedProduct.GetProductLink(productListPageId); 229 isHidden = isColorVariant ? isHidden : false; 230 string aCssClassesByType = isColorVariant ? string.Empty : "text-nowrap w-auto"; 231 232 <div class="related-product @(isActive ? "active" : "") @(aCssClassesByType) js-related-product"> 233 @if (isColorVariant) 234 { 235 var relatedProductFieldCustomColor = relatedProduct.ProductFields.ContainsKey("Custom_Color") ? Converter.ToString(relatedProduct.ProductFields["Custom_Color"].Value) : null; 236 var relatedProductImage = relatedProduct.DefaultImage.Value.StartsWith("/Files/") ? $"/Admin/Public/GetImage.ashx?image={relatedProduct.DefaultImage.Value}&width=180&format=webp" : relatedProduct.DefaultImage.Value; 237 238 <a href="@(relatedProductLink)" title="@HttpUtility.HtmlAttributeEncode(relatedProductFieldCustomColor ?? relatedProduct.Name)"> 239 <img src="@(relatedProductImage)" class="p-0 p-lg-1 w-100 h-100" style="object-fit:contain;" loading="lazy" decoding="async" alt="@HttpUtility.HtmlAttributeEncode(relatedProductFieldCustomColor ?? relatedProduct.Name)" /> 240 </a> 241 } 242 else 243 { 244 string relatedProductFieldCustomSize = relatedProduct.ProductFields.ContainsKey("Custom_Size") ? Converter.ToString(relatedProduct.ProductFields["Custom_Size"].Value) : null; 245 246 <a href="@(relatedProductLink)" class="d-block py-2 px-3 small text-center text-decoration-none" title="@HttpUtility.HtmlAttributeEncode(relatedProductFieldCustomSize ?? relatedProduct.Name)">@(relatedProductFieldCustomSize ?? relatedProduct.Name)</a> 247 } 248 </div> 249 } 250 251 @helper RenderRelatedProductSliders(IEnumerable<ProductViewModel> relatedProducts, ProductViewModel product) //NOTE: Only support color variants 252 { 253 <div class="swiffy-slider slider-item-show4 slider-item-show5-sm slider-item-show7-md slider-item-show4-lg slider-item-show5-xl slider-item-show7-xxl slider-item-snapstart slider-item-reveal slider-nav-square-small slider-indicators-hide js-swiffyslider" data-slider-nav-autoplay-interval="2500"> 254 <div class="slider-container"> 255 @foreach (ProductViewModel relatedProduct in relatedProducts) 256 { 257 @RenderRelatedProductSlider(relatedProduct, product) 258 } 259 </div> 260 </div> 261 } 262 263 @helper RenderRelatedProductSlider(ProductViewModel relatedProduct, ProductViewModel product) //NOTE: Only support color variants 264 { 265 var productListPageId = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ProductListPage")) ? Model.Item.GetInt32("ProductListPage") : GetPageIdByNavigationTag("Shop"); 266 var relatedProductLink = relatedProduct.GetProductLink(productListPageId); 267 268 var relatedProductFieldCustomColor = relatedProduct.ProductFields.ContainsKey("Custom_Color") ? Converter.ToString(relatedProduct.ProductFields["Custom_Color"].Value) : null; 269 var relatedProductImage = relatedProduct.DefaultImage.Value.StartsWith("/Files/") ? $"/Admin/Public/GetImage.ashx?image={relatedProduct.DefaultImage.Value}&width=180&format=webp" : relatedProduct.DefaultImage.Value; 270 271 <div class="related-product @(relatedProduct.Id == product.Id ? "active" : "")"> 272 <a href="@(relatedProductLink)" title="@HttpUtility.HtmlAttributeEncode(relatedProductFieldCustomColor ?? relatedProduct.Name)"> 273 <img src="@(relatedProductImage)" class="p-0 p-lg-1 w-100 h-100" style="object-fit:contain;" loading="lazy" decoding="async" alt="@HttpUtility.HtmlAttributeEncode(relatedProductFieldCustomColor ?? relatedProduct.Name)" /> 274 </a> 275 </div> 276 } 277 278 <script> 279 function setVariantEnvironment() { 280 const container = document.querySelector('.js-related-products-wrapper'); 281 const innerContainer = document.querySelector('.js-related-products-container'); 282 if (container !== null) { 283 const items = container.querySelectorAll(".js-related-product"); 284 const btnShowAll = document.querySelector('.js-show-all'); 285 let hiddenCount = 0; 286 let firstRowTopPos = null; 287 innerContainer.classList.remove('flex-nowrap'); 288 289 btnShowAll.classList.remove('order-1'); 290 items.forEach(item => { 291 item.classList.remove('order-0', 'order-2', 'hidden'); 292 }); 293 294 items.forEach(item => { 295 const itemTop = item.getBoundingClientRect().top; 296 if (firstRowTopPos === null) { 297 firstRowTopPos = itemTop; 298 } 299 if (itemTop !== firstRowTopPos) { 300 item.classList.add('hidden'); 301 hiddenCount++; 302 } else { 303 item.classList.add('order-0'); 304 } 305 }); 306 307 if (hiddenCount === 1) { 308 innerContainer.classList.add('flex-nowrap'); 309 btnShowAll.classList.add('d-none'); 310 items.forEach(item => { 311 item.classList.remove('hidden'); 312 item.classList.add('order-0'); 313 }); 314 } else if (hiddenCount > 1) { 315 btnShowAll.classList.remove('d-none', 'order-0'); 316 btnShowAll.classList.add('order-1'); 317 btnShowAll.querySelector('.js-hidden-variants-count').textContent = hiddenCount; 318 } else { 319 btnShowAll.classList.add('d-none'); 320 } 321 } 322 } 323 324 window.addEventListener('DOMContentLoaded', () => { 325 setVariantEnvironment(); 326 327 }); 328 window.addEventListener("resize", () => { 329 setVariantEnvironment(); 330 }); 331 332 </script> 333
Error executing template "/Designs/Swift/Paragraph/Swift_ProductSpecification.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, ProductFieldValue pfv) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetProductFieldValues(ProductViewModelSettings settings, Product product) at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_98a2241f47c243efa721e1c482cd72df.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductSpecification.cshtml:line 109 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 4 @* STANDARD TEMPLATE IS DEPRECATED IN SWIFT (1.25.0) *@ 5 6 @{ 7 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false; 8 9 ProductViewModel product = new ProductViewModel(); 10 11 ProductViewModelSettings productSetting = new ProductViewModelSettings 12 { 13 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID, 14 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code, 15 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2, 16 ShopId = Pageview.Area.EcomShopId 17 }; 18 19 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 20 { 21 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 22 } 23 else if (Pageview.Item["DummyProduct"] != null) 24 { 25 26 string dummyProductId = ""; 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 if (productList.Products != null) 30 { 31 foreach (var p in productList.Products) { dummyProductId = p.Id; } 32 ProductViewModel dummyProduct = dummyProductId != "" ? ViewModelFactory.CreateView(productSetting, dummyProductId) : new ProductViewModel(); 33 product = dummyProduct; 34 } 35 else 36 { 37 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 38 } 39 } 40 else if (Pageview.Item["DummyProduct"] == null) 41 { 42 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 43 } 44 } 45 46 @if (product?.Id != null) 47 { 48 IEnumerable<string> selectedDisplayGroupIds = Model.Item.GetRawValueString("DisplayGroups").Split(',').ToList(); 49 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 50 51 foreach (var selection in selectedDisplayGroupIds) 52 { 53 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 54 { 55 if (selection == group.Id) 56 { 57 int fieldsWithNoValueOrZero = 0; 58 59 foreach (var field in group.Fields) 60 { 61 if (string.IsNullOrEmpty(field.Value.Value.ToString())) 62 { 63 fieldsWithNoValueOrZero++; 64 } 65 } 66 67 if (fieldsWithNoValueOrZero != group.Fields.Count) 68 { 69 displayGroups.Add(group); 70 } 71 } 72 } 73 } 74 75 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 76 77 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 78 79 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 80 81 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 82 83 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 84 contentPadding = contentPadding == "none" ? string.Empty : contentPadding; 85 contentPadding = contentPadding == "small" ? " p-2 p-md-3" : contentPadding; 86 contentPadding = contentPadding == "large" ? " p-4 p-md-5" : contentPadding; 87 88 string layout = Model.Item.GetRawValueString("Layout", "list"); 89 string size = Model.Item.GetRawValueString("Size", "full"); 90 string gaps = size == "full" ? " gap-4" : " gap-2"; 91 92 93 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 94 { 95 product.ProductFields.Clear(); 96 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 97 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 98 showProductFields = true; 99 } 100 101 if (layout == "commas") 102 { 103 gaps = size == "full" ? " gap-4" : " gap-2"; 104 105 } 106 107 <div class="h-100@(gaps)@(theme)@(contentPadding) item_@Model.Item.SystemName.ToLower()"> 108 <div class="grid"> 109 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) 110 { 111 if (!hideTitle) 112 { 113 <h2 class="g-col-12 @titleFontSize">@Model.Item.GetString("Title")</h2> 114 } 115 } 116 117 @if (displayGroups.Count != 0) 118 { 119 if (layout != "accordion") 120 { 121 foreach (var group in displayGroups) 122 { 123 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 124 125 if (!hideHeader) 126 { 127 <h4 class="g-col-12 h4 mb-0">@group.Name</h4> 128 } 129 130 { @RenderFieldsFromList(group.Fields, layout) } 131 132 } 133 } 134 else 135 { 136 <div class="g-col-12"> 137 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 138 @foreach (var group in displayGroups) 139 { 140 <div class="accordion-item"> 141 <h2 class="accordion-header" id="SpecificationHeading_@group.Id"> 142 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Id"> 143 @group.Name 144 </button> 145 </h2> 146 <div id="SpecificationItem_@group.Id" class="accordion-collapse collapse" aria-labelledby="SpecificationHeading_@group.Id" data-bs-parent="#Specifications_@Model.ID"> 147 <div class="accordion-body"> 148 @{ @RenderFieldsFromList(group.Fields, "list") } 149 </div> 150 </div> 151 </div> 152 } 153 </div> 154 </div> 155 } 156 } 157 158 @if (product.ProductFields != null && showProductFields) 159 { 160 if (product.ProductFields.Count > 0) 161 { 162 if (layout != "accordion") 163 { 164 {@RenderFieldsFromList(product.ProductFields, layout) } 165 } 166 else 167 { 168 <div class="g-col-12"> 169 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 170 <div class="accordion-item"> 171 <h2 class="accordion-header" id="SpecificationHeading_@Model.ID"> 172 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@Model.ID" aria-expanded="false" aria-controls="SpecificationItem_@Model.ID"> 173 @Translate("Specifications") 174 </button> 175 </h2> 176 <div id="SpecificationItem_@Model.ID" class="accordion-collapse" aria-labelledby="SpecificationHeading_@Model.ID" data-bs-parent="#Specifications_@Model.ID"> 177 <div class="accordion-body"> 178 @{ @RenderFieldsFromList(product.ProductFields, "List") } 179 </div> 180 </div> 181 </div> 182 </div> 183 </div> 184 } 185 } 186 } 187 188 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 189 { 190 if (product.ProductCategories.Count > 0) 191 { 192 if (layout != "accordion") 193 { 194 foreach (var group in product.ProductCategories) 195 { 196 CategoryFieldViewModel category = group.Value; 197 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 198 199 if (!hideHeader) 200 { 201 <h4 class="g-col-12 h4 mb-0">@group.Value.Name</h4> 202 } 203 204 { @RenderFieldsFromList(category.Fields, layout) } 205 } 206 } 207 else 208 { 209 <div class="g-col-12"> 210 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 211 @foreach (var group in product.ProductCategories) 212 { 213 CategoryFieldViewModel category = group.Value; 214 215 <div class="accordion-item"> 216 <h2 class="accordion-header" id="SpecificationHeading_@group.Value.Id"> 217 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Value.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Value.Id"> 218 @group.Value.Name 219 </button> 220 </h2> 221 <div id="SpecificationItem_@group.Value.Id" class="accordion-collapse" aria-labelledby="SpecificationHeading_@group.Value.Id" data-bs-parent="#Specifications_@Model.ID"> 222 <div class="accordion-body"> 223 @{ @RenderFieldsFromList(category.Fields, "list") } 224 </div> 225 </div> 226 </div> 227 } 228 </div> 229 </div> 230 } 231 } 232 } 233 </div> 234 </div> 235 } 236 else if (Pageview.IsVisualEditorMode) 237 { 238 <div class="alert alert-warning m-0">@Translate("No products available")</div> 239 } 240 241 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) 242 { 243 string size = Model.Item.GetRawValueString("Size", "full"); 244 string gaps = size != "full" ? " gap-1" : string.Empty; 245 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 246 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 247 248 if (layout == "columns") 249 { 250 <div class="g-col-12"> 251 <div class="grid@(gaps)"> 252 @foreach (var field in fields) 253 { 254 {@RenderField(field.Value, layout)} 255 } 256 </div> 257 </div> 258 } 259 if (layout == "list") 260 { 261 <div class="g-col-12"> 262 <dl class="grid@(gaps)"> 263 @foreach (var field in fields) 264 { 265 {@RenderField(field.Value, layout)} 266 } 267 </dl> 268 </div> 269 } 270 if (layout == "table") 271 { 272 string tableSize = size == "full" ? "" : " table-sm"; 273 <div class="g-col-12"> 274 <table class="table table-striped@(tableSize)"> 275 @foreach (var field in fields) 276 { 277 {@RenderField(field.Value, layout)} 278 } 279 </table> 280 </div> 281 } 282 if (layout == "bullets") 283 { 284 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 285 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 286 <div class="g-col-12"> 287 <ul class="@listSize" @listStyle> 288 @foreach (var field in fields) 289 { 290 {@RenderField(field.Value, layout)} 291 } 292 </ul> 293 </div> 294 } 295 if (layout == "commas") 296 { 297 List<string> featuresList = new List<string>(); 298 299 foreach (var field in fields) 300 { 301 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 302 303 if (field.Value?.Value != null) 304 { 305 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 306 { 307 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 308 309 //Hack to support field type providers with a single value 310 if (values.FirstOrDefault() != null) 311 { 312 firstListItemValue = values.FirstOrDefault().Value; 313 } 314 } 315 } 316 317 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.Value.ToString() != "0" && field.Value.Value.ToString() != "0.0")) 318 { 319 if (field.Value.Value is object && !string.IsNullOrEmpty(field.Value.Value.ToString())) 320 { 321 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 322 { 323 List<string> options = new List<string>(); 324 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 325 { 326 if (!string.IsNullOrWhiteSpace(option.Value)) 327 { 328 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 329 { 330 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 331 options.Add(colorSpan); 332 } 333 else if (!string.IsNullOrEmpty(option.Value)) 334 { 335 options.Add(option.Name); 336 } 337 } 338 } 339 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 340 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 341 { 342 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 343 } 344 345 if (!string.IsNullOrEmpty(optionsString)) 346 { 347 if (!hideFieldLabels) 348 { 349 featuresList.Add(field.Value.Name + ": " + optionsString); 350 } 351 else 352 { 353 featuresList.Add(optionsString); 354 } 355 } 356 } 357 else 358 { 359 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 360 { 361 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 362 { 363 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 364 365 if (!hideFieldLabels) 366 { 367 featuresList.Add(field.Value.Name + ": " + colorSpan); 368 } 369 else 370 { 371 featuresList.Add(colorSpan); 372 } 373 } 374 else 375 { 376 if (!hideFieldLabels) 377 { 378 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 379 } 380 else 381 { 382 featuresList.Add(field.Value.Value.ToString()); 383 } 384 } 385 } 386 } 387 } 388 } 389 } 390 391 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 392 393 <div class="g-col-12 opacity-75 fs-7">@featuresString</div> 394 } 395 } 396 397 @helper RenderField(FieldValueViewModel field, string layout) 398 { 399 string size = Model.Item.GetRawValueString("Size", "full"); 400 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 401 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 402 bool noValues = false; 403 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 404 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 405 406 if (!string.IsNullOrEmpty(fieldValue)) 407 { 408 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 409 { 410 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 411 noValues = values.Count > 0 ? false : true; 412 413 //Hack to support field type providers with a single value 414 if (values.FirstOrDefault() != null) 415 { 416 firstListItemValue = values.FirstOrDefault().Value; 417 } 418 } 419 } 420 421 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 422 { 423 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.ToString() != "0" && field.Value.ToString() != "0.0")) 424 { 425 if (layout == "columns") 426 { 427 428 <div class="grid g-col-6 g-col-lg-4 gap-1"> 429 @if (!hideFieldLabels) 430 { 431 <dt class="g-col-12 g-col-lg-4">@field.Name</dt> 432 } 433 <dd class="g-col-12 g-col-lg-8 mb-0 text-break"> 434 @{ @RenderFieldValue(field) } 435 </dd> 436 </div> 437 } 438 if (layout == "list") 439 { 440 if (!hideFieldLabels) 441 { 442 <dt class="g-col-4">@field.Name</dt> 443 } 444 <dd class="g-col-8 mb-0 text-break"> 445 @{ @RenderFieldValue(field) } 446 </dd> 447 } 448 if (layout == "table") 449 { 450 <tr> 451 @if (!hideFieldLabels) 452 { 453 <th class="w-25 w-lg-50" scope="row">@field.Name</th> 454 } 455 <td class="text-break"> 456 @{ @RenderFieldValue(field) } 457 </td> 458 </tr> 459 } 460 if (layout == "bullets") 461 { 462 <li> 463 @if (!hideFieldLabels) 464 { 465 <strong>@field.Name</strong> 466 } 467 <span> 468 @{ @RenderFieldValue(field) } 469 </span> 470 </li> 471 } 472 } 473 } 474 } 475 476 @helper RenderFieldValue(FieldValueViewModel field) 477 { 478 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 479 480 bool isLink = field?.Type == "Link"; 481 bool isColor = false; 482 bool isBrandName = field?.SystemName == "Brand_name"; 483 484 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 485 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 486 487 488 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 489 { 490 int valueCount = 0; 491 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 492 int totalValues = values.Count; 493 494 foreach (FieldOptionValueViewModel option in values) 495 { 496 if (!string.IsNullOrEmpty(option.Value)) 497 { 498 if (option.Value.Substring(0, 1) == "#") 499 { 500 isColor = true; 501 } 502 } 503 504 if (!isColor) 505 { 506 @option.Name 507 } 508 else 509 { 510 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 511 } 512 513 if (valueCount != totalValues && valueCount < (totalValues - 1)) 514 { 515 if (isColor) 516 { 517 <text> </text> 518 } 519 else 520 { 521 <text>, </text> 522 } 523 } 524 valueCount++; 525 } 526 } 527 else 528 { 529 if (fieldValue.Substring(0, 1) == "#") 530 { 531 isColor = true; 532 } 533 534 if (!isColor) 535 { 536 if (isLink) 537 { 538 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 539 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 540 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 541 542 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 543 } 544 else if (isBrandName) 545 { 546 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 547 <span itemprop="name">@fieldValue</span> 548 </span> 549 } 550 else 551 { 552 @fieldValue 553 } 554 555 } 556 else 557 { 558 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 559 } 560 } 561 } 562
Error executing template "/Designs/Swift/Paragraph/Swift_ProductPrice_Custom.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, ProductFieldValue pfv) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetProductFieldValues(ProductViewModelSettings settings, Product product) at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_1fb0d18a1de944f3a468232b7643f0eb.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductPrice_Custom.cshtml:line 65 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.Configuration @*//CUSTOM*@ 3 @using Dynamicweb.Core.Encoders @*//CUSTOM*@ 4 @using Dynamicweb.Ecommerce.ProductCatalog 5 @using System.Globalization 6 @using System.IO @*//CUSTOM*@ 7 8 @* CUSTOMIZED STANDARD SWIFT (v1.25.0) TEMPLATE *@ 9 10 @{ 11 ProductViewModel product = null; 12 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 13 { 14 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 15 } 16 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 17 { 18 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 19 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 20 21 if (productList?.Products is object) 22 { 23 product = productList.Products[0]; 24 } 25 } 26 27 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 28 bool anonymousUser = Pageview.User == null; 29 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsWebServiceConnectionAvailable"]); 30 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && isErpConnectionDown; 31 32 bool productIsDiscontinued = product is object && product.Discontinued; 33 bool doNotShowPriceIfProductIsDiscontinued = Model.Item.GetBoolean("DoNotShowPriceIfProductIsDiscontinued"); 34 var isDiscontinued = productIsDiscontinued && doNotShowPriceIfProductIsDiscontinued; 35 } 36 37 @if (product is object && !hidePrice && !isDiscontinued) 38 { 39 bool showInformativePrice = Model.Item.GetBoolean("ShowInformativePrice"); 40 string unitId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("UnitId")) ? Dynamicweb.Context.Current.Request.Form.Get("UnitId") : string.Empty; 41 42 string priceFontSize = Model.Item.GetRawValueString("PriceSize", "h6 justify-content-lg-start"); //CUSTOM 43 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 44 string layout = Model.Item.GetRawValueString("Layout", "horizontal"); 45 string textAlign = horizontalAlign == "center" ? "text-center" : string.Empty; 46 textAlign = horizontalAlign == "end" ? "text-end" : textAlign; 47 48 horizontalAlign = horizontalAlign == "center" && layout == "horizontal" ? "justify-content-center" : horizontalAlign; 49 horizontalAlign = horizontalAlign == "end" && layout == "horizontal" ? "justify-content-end" : horizontalAlign; 50 horizontalAlign = horizontalAlign == "center" && layout == "vertical" ? "align-items-center" : horizontalAlign; 51 horizontalAlign = horizontalAlign == "end" && layout == "vertical" ? "align-items-end" : horizontalAlign; 52 53 string flexDirection = layout == "horizontal" ? string.Empty : "flex-column"; 54 string flexGap = layout == "horizontal" ? "gap-3" : string.Empty; 55 string order = layout == "horizontal" ? string.Empty : "order-2"; 56 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? "theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 57 theme = GetViewParameter("theme") != null ? GetViewParameterString("theme") : theme; 58 59 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 60 contentPadding = contentPadding == "none" ? "p-0" : contentPadding; 61 contentPadding = contentPadding == "small" ? "p-1 px-md-2 py-md-1" : contentPadding; 62 contentPadding = contentPadding == "large" ? "p-2 px-md-3 py-md-2" : contentPadding; 63 64 //CUSTOM 65 Dictionary<string, FieldValueViewModel> productFields = product.ProductFields; 66 var discountText = ""; 67 bool discountDiscontinued = false; 68 bool discountOnSale = false; 69 70 if (productFields.TryGetValue("Custom_Discontinued", out FieldValueViewModel discontinued)) 71 { 72 var firstValue = (discontinued.Value as List<FieldOptionValueViewModel>).FirstOrDefault()?.Value; 73 74 if (!string.IsNullOrWhiteSpace(firstValue)) 75 { 76 bool.TryParse(firstValue, out discountDiscontinued); 77 } 78 } 79 80 if (productFields.TryGetValue("Custom_OnSale", out FieldValueViewModel onsale)) 81 { 82 var firstValue = (onsale.Value as List<FieldOptionValueViewModel>).FirstOrDefault()?.Value; 83 84 if (!string.IsNullOrWhiteSpace(firstValue)) 85 { 86 bool.TryParse(firstValue, out discountOnSale); 87 } 88 } 89 90 if (discountDiscontinued && discountOnSale) 91 { 92 discountText = Translate("Outlet - tilbuddet gælder så længe lager haves"); 93 } 94 else 95 { 96 var discountInfo = Smartpage.EvaSolo.CampaignPrices.Helpers.DiscountHelper.GetDiscountInfo(product); 97 if (discountInfo != null) 98 { 99 discountText = string.Format(Translate(Model.Item.GetRawValueString("Custom_DiscountText", "Tilbuddet gælder {0} - {1}")), $"‌{discountInfo.ValidFromFormatted}‌", $"‌{discountInfo.ValidToFormatted}‌"); 100 } 101 } 102 string discountType = Model.Item.GetRawValueString("Custom_DiscountType", "none"); 103 string discountTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Custom_DiscountTheme")) ? "theme " + Model.Item.GetRawValueString("Custom_DiscountTheme").Replace(" ", "").Trim().ToLower() : string.Empty; 104 string discountIconColor = Model.Item.GetString("Custom_DiscountIconColor", "text-inherit"); 105 string discountIconSize = Model.Item.GetRawValueString("Custom_DiscountIconSize", "2"); 106 string discountImageSrc = !string.IsNullOrEmpty(Model.Item.GetString("Custom_DiscountImage")) ? Model.Item.GetFile("Custom_DiscountImage").Path : string.Empty; 107 string discountImagePath = discountImageSrc != string.Empty ? discountImageSrc : Model.Item.GetRawValueString("Custom_DiscountIcon", string.Empty); 108 discountImagePath = Path.GetExtension(discountImagePath).ToLower() != ".svg" ? "/Admin/Public/GetImage.ashx?image=" + discountImagePath + "&height=" + discountIconSize + "&width=" + discountIconSize + "&Crop=0&format=webp" : discountImagePath; 109 string discountImgAltText = Model.Item.GetRawValueString("FeatureAltText", string.Empty); 110 //--CUSTOM 111 112 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower(); 113 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat); 114 115 string priceMin = ""; 116 string priceMax = ""; 117 118 string liveInfoClass = ""; 119 string productInfoFeed = ""; 120 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsLazyLoadingForProductInfoEnabled"]); 121 if (isLazyLoadingForProductInfoEnabled) 122 { 123 if (Dynamicweb.Context.Current.Items.Contains("ProductInfoFeed")) 124 { 125 productInfoFeed = Dynamicweb.Context.Current.Items["ProductInfoFeed"]?.ToString(); 126 if (!string.IsNullOrEmpty(productInfoFeed)) 127 { 128 productInfoFeed = $"data-product-info-feed=\"{productInfoFeed}\""; 129 } 130 } 131 liveInfoClass = "js-live-info"; 132 } 133 134 <div class="@textAlign @liveInfoClass item_@Model.Item.SystemName.ToLower()" data-product-id="@product.Id" data-variant-id="@product.VariantId" @productInfoFeed> 135 @if (showInformativePrice && product.PriceInformative.Price != 0) 136 { 137 <div class="opacity-50"> 138 <span>@Translate("RRP") </span> 139 <span class="text-decoration-line-through text-price">@product.PriceInformative.PriceFormatted</span> 140 </div> 141 } 142 <div class="@priceFontSize m-0 d-flex flex-wrap @flexDirection @flexGap @horizontalAlign" style="row-gap: 0 !important" itemprop="offers" itemscope itemtype="https://schema.org/Offer"> 143 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span> 144 145 @*//CUSTOM*@ 146 @if (showPricesWithVat == "false" && !neverShowVat) 147 { 148 if (isLazyLoadingForProductInfoEnabled && !Pageview.IsVisualEditorMode) 149 { 150 <span class="text-price js-text-price"> 151 <span class="spinner-border" role="status"></span> 152 </span> 153 } 154 else 155 { 156 string price = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).Price.PriceWithoutVatFormatted : product.Price.PriceWithoutVatFormatted; 157 158 if (product?.VariantInfo?.VariantInfo != null) 159 { 160 priceMin = product?.VariantInfo?.PriceMin?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithoutVatFormatted : ""; 161 priceMax = product?.VariantInfo?.PriceMax?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithoutVatFormatted : ""; 162 } 163 if (priceMin != priceMax) 164 { 165 price = priceMin + " - " + priceMax; 166 } 167 168 <span class="@theme"> 169 <span class="text-price">@price</span> 170 </span> 171 } 172 } 173 else 174 { 175 if (isLazyLoadingForProductInfoEnabled && !Pageview.IsVisualEditorMode) 176 { 177 <span class="text-price js-text-price"> 178 <span class="spinner-border" role="status"></span> 179 </span> 180 } 181 else 182 { 183 string price = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).Price.PriceFormatted : product.Price.PriceFormatted; 184 185 if (product?.VariantInfo?.VariantInfo != null) 186 { 187 priceMin = product?.VariantInfo?.PriceMin?.PriceFormatted != null ? product.VariantInfo.PriceMin.PriceFormatted : ""; 188 priceMax = product?.VariantInfo?.PriceMax?.PriceFormatted != null ? product.VariantInfo.PriceMax.PriceFormatted : ""; 189 } 190 if (priceMin != priceMax) 191 { 192 price = priceMin + " - " + priceMax; 193 } 194 195 <span class="@theme"> 196 <span class="text-price">@price</span> 197 </span> 198 } 199 } 200 201 @if (showPricesWithVat == "false" && !neverShowVat) 202 { 203 if (isLazyLoadingForProductInfoEnabled && !Pageview.IsVisualEditorMode) 204 { 205 <span itemprop="price" content="" class="d-none"></span> 206 <span class="text-decoration-line-through js-text-decoration-line-through opacity-75 me-3 text-price js-text-price d-none" data-show-if="LiveProductInfo.product.Price.Price != LiveProductInfo.product.PriceBeforeDiscount.Price"></span> 207 } 208 else 209 { 210 string beforePrice = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).PriceBeforeDiscount.PriceWithoutVatFormatted : product.PriceBeforeDiscount.PriceWithoutVatFormatted; 211 212 <span itemprop="price" content="@product.Price.PriceWithoutVat.ToString(CultureInfo.InvariantCulture)" class="d-none"></span> 213 214 if (product.Price.Price != product.PriceBeforeDiscount.Price) 215 { 216 <span class="opacity-75 @(order)"> 217 <span class="fs-7 text-price text-decoration-line-through">@beforePrice</span> 218 </span> 219 220 if (Model.Item.GetBoolean("Custom_ShowDiscountSavings")) 221 { 222 var currency = Dynamicweb.Ecommerce.Common.Context.Currency; 223 var priceInfo = new Dynamicweb.Ecommerce.Prices.PriceInfo(currency) 224 { 225 PriceWithoutVAT = (product.PriceBeforeDiscount.PriceWithoutVat - product.Price.PriceWithoutVat) 226 }; 227 228 <span class="d-none d-sm-inline opacity-75 @(order)"> 229 <span class="fs-7 text-price">@string.Format(Translate("Spar {0}"), priceInfo.PriceWithoutVATFormatted)</span> 230 </span> 231 } 232 } 233 } 234 } 235 else 236 { 237 if (isLazyLoadingForProductInfoEnabled && !Pageview.IsVisualEditorMode) 238 { 239 <span itemprop="price" content="" class="d-none"></span> 240 <span class="text-decoration-line-through js-text-decoration-line-through opacity-75 me-3 text-price js-text-price d-none" data-show-if="LiveProductInfo.product.Price.Price < LiveProductInfo.product.PriceBeforeDiscount.Price"></span> 241 } 242 else 243 { 244 string beforePrice = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).PriceBeforeDiscount.PriceFormatted : product.PriceBeforeDiscount.PriceFormatted; 245 246 <span itemprop="price" content="@product.Price.Price.ToString(CultureInfo.InvariantCulture)" class="d-none"></span> 247 248 if (product.Price.Price < product.PriceBeforeDiscount.Price) 249 { 250 <span class="opacity-75 @(order)"> 251 <span class="fs-7 text-price text-decoration-line-through">@beforePrice</span> 252 </span> 253 254 if (Model.Item.GetBoolean("Custom_ShowDiscountSavings")) 255 { 256 var currency = Dynamicweb.Ecommerce.Common.Context.Currency; 257 var priceInfo = new Dynamicweb.Ecommerce.Prices.PriceInfo(currency) 258 { 259 PriceWithVAT = (product.PriceBeforeDiscount.Price - product.Price.Price) 260 }; 261 262 <span class="d-none d-sm-inline opacity-75 @(order)"> 263 <span class="fs-7 text-price">@string.Format(Translate("Spar {0}"), priceInfo.PriceFormatted)</span> 264 </span> 265 } 266 } 267 } 268 } 269 @*//--CUSTOM*@ 270 271 @*//CUSTOM*@ 272 @if (discountType == "icon-tooltip" && product.Price.Price != product.PriceBeforeDiscount.Price && discountText != null) 273 { 274 if ((!string.IsNullOrEmpty(Model.Item.GetString("Custom_DiscountImage")) || !discountImagePath.ToLower().Contains("none")) && discountImagePath != string.Empty) 275 { 276 <span data-bs-toggle="tooltip" data-bs-custom-class="@(discountTheme)" data-bs-html="true" data-bs-title="@HtmlEncoder.HtmlAttributeEncode(discountText)" data-bs-custom-prevent-event="click" data-bs-custom-click-close-delay="2000"> 277 @if (Path.GetExtension(discountImagePath).ToLower() == ".svg") 278 { 279 <span class="icon-auto @(discountIconColor)" style="vertical-align:text-top;height:@(discountIconSize)px;width:@(discountIconSize)px;">@ReadFile(discountImagePath)</span> 280 } 281 else 282 { 283 <img loading="lazy" src="@(discountImagePath)" alt="@HtmlEncoder.HtmlAttributeEncode(discountImgAltText)" title="@HtmlEncoder.HtmlAttributeEncode(discountImgAltText)" style="height:@(discountIconSize)px;width:@(discountIconSize)px;"> 284 } 285 </span> 286 } 287 } 288 @*//--CUSTOM*@ 289 290 @* Stock state for Schema.org, start *@ 291 @{ 292 Uri url = Dynamicweb.Context.Current.Request.Url; 293 } 294 295 <link itemprop="url" href="@url"> 296 297 @{ 298 bool IsNeverOutOfStock = product.NeverOutOfstock; 299 } 300 301 @if (IsNeverOutOfStock) 302 { 303 <span itemprop="availability" class="d-none">@Translate("Available in stock")</span> 304 } 305 else 306 { 307 if (product.StockLevel > 0) 308 { 309 <span itemprop="availability" class="d-none">InStock</span> 310 } 311 else 312 { 313 <span itemprop="availability" class="d-none">OutOfStock</span> 314 } 315 } 316 @* Stock state for Schema.org, stop *@ 317 318 </div> 319 320 @if (showPricesWithVat == "false" && !neverShowVat) 321 { 322 if (isLazyLoadingForProductInfoEnabled && !Pageview.IsVisualEditorMode) 323 { 324 <small class="opacity-85 fst-normal js-text-price-with-vat d-none" data-suffix="@Translate("Incl. VAT")"></small> 325 } 326 else 327 { 328 string price = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).Price.PriceWithVatFormatted : product.Price.PriceWithVatFormatted; 329 330 if (product?.VariantInfo?.VariantInfo != null) 331 { 332 priceMin = product?.VariantInfo?.PriceMin?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithVatFormatted : ""; 333 priceMax = product?.VariantInfo?.PriceMax?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithVatFormatted : ""; 334 } 335 if (priceMin != priceMax) 336 { 337 price = priceMin + " - " + priceMax; 338 } 339 <small class="opacity-85 fst-normal">@price @Translate("Incl. VAT")</small> 340 } 341 } 342 343 @*//CUSTOM*@ 344 @if (discountType == "inline" && product.Price.Price != product.PriceBeforeDiscount.Price && !string.IsNullOrEmpty(discountText)) 345 { 346 var discountFontSize = priceFontSize.Contains("h6") ? priceFontSize.Replace("h6", "small") : "small"; 347 348 <div class="@(discountFontSize) mt-1 d-flex flex-wrap @(flexDirection) @(horizontalAlign)"> 349 @discountText 350 </div> 351 } 352 @*//--CUSTOM*@ 353 354 </div> 355 } 356 else if (Pageview.IsVisualEditorMode) 357 { 358 <div class="alert alert-dark m-0" role="alert"> 359 <span>@Translate("No products available")</span> 360 </div> 361 } 362
Error executing template "Designs/Swift/Paragraph/Swift_ProductBadges.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, ProductFieldValue pfv) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetProductFieldValues(ProductViewModelSettings settings, Product product) at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_eb246b8e4a2640dcb2cae07b630e1a3c.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductBadges.cshtml:line 72 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.Frontend 3 @using Dynamicweb.Content 4 @using Dynamicweb.Ecommerce.ProductCatalog 5 6 @{ 7 ProductViewModel product = null; 8 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 9 { 10 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 11 } 12 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 13 { 14 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 15 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 16 17 if (productList?.Products is object) 18 { 19 product = productList.Products[0]; 20 } 21 } 22 } 23 24 @if (product is object) { 25 var badgeParms = new Dictionary<string, object>(); 26 badgeParms.Add("size", "h7"); 27 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 28 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 29 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 30 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 31 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 32 33 string badgeSize = Model.Item.GetRawValueString("BadgeSize", "fs-2"); 34 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 35 horizontalAlign = horizontalAlign == "center" ? "text-center" : horizontalAlign; 36 horizontalAlign = horizontalAlign == "end" ? "text-end" : horizontalAlign; 37 38 Dictionary<string, ParagraphInfoViewModel> badgeConfigurations; 39 List<string> campaignBadgesValues = Model.Item.GetRawValueString("CampaignBadges") != null ? Model.Item.GetRawValueString("CampaignBadges").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List<string>(); 40 41 if (Dynamicweb.Context.Current.Items.Contains("badgeConfigurations")) 42 { 43 badgeConfigurations = (Dictionary<string, ParagraphInfoViewModel>)Dynamicweb.Context.Current.Items["badgeConfigurations"]; 44 } 45 else 46 { 47 var badgesPage = Pageview.AreaSettings.GetLink("EcommerceBadgesPage") != null ? Pageview.AreaSettings.GetLink("EcommerceBadgesPage").PageId : 0; 48 var allBadges = badgesPage != 0 ? Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(badgesPage) : null; 49 50 badgeConfigurations = new Dictionary<string, ParagraphInfoViewModel>(); 51 foreach (Paragraph badge in allBadges) 52 { 53 var paragraphviewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreateParagraphInfoViewModel(badge); 54 string cssClassName = paragraphviewModel.Item.GetString("CssClassName").Trim().ToLower(); 55 if (!badgeConfigurations.ContainsKey(cssClassName)) 56 { 57 badgeConfigurations.Add(cssClassName, paragraphviewModel); 58 } 59 } 60 Dynamicweb.Context.Current.Items.Add("badgeConfigurations", badgeConfigurations); 61 } 62 63 int badgesCount = 0; 64 if (badgeConfigurations.Any()) 65 { 66 foreach (string campaign in campaignBadgesValues) 67 { 68 if (!string.IsNullOrEmpty(campaign)) 69 { 70 71 FieldValueViewModel availableCampaignsObject; 72 product.ProductFields.TryGetValue("Campaign", out availableCampaignsObject); 73 74 if (availableCampaignsObject != null) 75 { 76 string campaignType = string.Empty; 77 78 if (badgeConfigurations.ContainsKey(campaign)) 79 { 80 ParagraphInfoViewModel paragraphviewModel; 81 if (badgeConfigurations.TryGetValue(campaign, out paragraphviewModel)) 82 { 83 campaignType = paragraphviewModel.Item.GetRawValueString("CampaignType"); 84 } 85 } 86 87 List<FieldOptionValueViewModel> availableCampaigns = (List<FieldOptionValueViewModel>)availableCampaignsObject.Value; 88 89 foreach (FieldOptionValueViewModel availableOption in availableCampaigns) 90 { 91 if (campaignType == availableOption.Value) 92 { 93 badgesCount++; 94 break; 95 } 96 } 97 } 98 } 99 } 100 } 101 102 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 103 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 104 DateTime createdDate = product.Created.Value; 105 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 106 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 107 showBadges = (!string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) && badgesCount != 0) ? true : showBadges; 108 109 if (showBadges) 110 { 111 <div class="@badgeSize @horizontalAlign item_@Model.Item.SystemName.ToLower()"> 112 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 113 </div> 114 } 115 else if (Pageview.IsVisualEditorMode) 116 { 117 <span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span> 118 } 119 } 120 else if (Pageview.IsVisualEditorMode) 121 { 122 <span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span> 123 } 124 125
Error executing template "/Designs/Swift/Paragraph/Swift_ProductAddToCart_Custom.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, ProductFieldValue pfv) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetProductFieldValues(ProductViewModelSettings settings, Product product) at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_16e62a50651b4ef390981754c62d1ae8.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductAddToCart_Custom.cshtml:line 55 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 System 3 @using Dynamicweb.Ecommerce.ProductCatalog 4 @using Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites 5 @using Dynamicweb.Ecommerce.Products.FieldDisplayGroups 6 @using Dynamicweb.Frontend 7 @using Dynamicweb.Core 8 @using Dynamicweb.Core.Encoders 9 @using System.Drawing 10 @using System.Web 11 @using Dynamicweb.Environment 12 @using System.Globalization 13 @using Custom.EvaSolo.Tracking.Extensions @*//CUSTOM*@ 14 15 @* TODO: REFACTURE/UPGRADE TO SWIFT (v1.25.0) *@ 16 17 @{ 18 ProductViewModel product = null; 19 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 20 { 21 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 22 } 23 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 24 { 25 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 26 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 27 28 if (productList?.Products is object) 29 { 30 product = productList.Products[0]; 31 } 32 } 33 34 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 35 bool anonymousUser = Pageview.User == null; 36 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsWebServiceConnectionAvailable"]); 37 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHideAddToCart") && isErpConnectionDown; 38 hideAddToCart = Pageview.IsVisualEditorMode ? false : hideAddToCart; 39 } 40 41 @if (product is object && !hideAddToCart) 42 { 43 bool quantitySelector = !string.IsNullOrEmpty(Model.Item.GetString("ShowQuantitySelector")) ? Model.Item.GetBoolean("ShowQuantitySelector") : false; 44 45 string iconPath = "/Files/icons/"; 46 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService")); 47 if (!url.Contains("LayoutTemplate")) 48 { 49 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml"; 50 } 51 52 bool stockLevelZeroOrless = product.StockLevel <= 0; 53 bool isDiscontinued = product.Discontinued; 54 bool IsNeverOutOfStock = product.NeverOutOfstock; 55 bool plytixIsNotForSale = product.ProductFields.ContainsKey("Custom_NotForSale") ? Converter.ToBoolean(product.ProductFields["Custom_NotForSale"].Value) : false; 56 57 bool isCartDisabled = stockLevelZeroOrless || isDiscontinued; 58 isCartDisabled = IsNeverOutOfStock ? false : isCartDisabled; 59 string disableAddToCart = isCartDisabled ? "disabled" : ""; 60 61 double stepAmount = product.PurchaseQuantityStep ?? 1; 62 stepAmount = stepAmount > 1 ? stepAmount : 1; 63 string stepQty = stepAmount.ToString(); 64 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\""; 65 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty; 66 string qtyValidCheck = stepQty != "1" ? "onkeyup=\"swift.Cart.QuantityValidate(event)\"" : ""; 67 string onChangeEvent = !IsNeverOutOfStock ? $"onChange=\"UpdateQuantity(this, '{product.StockLevel}', '{stepAmount}')\"" : ""; 68 69 DateTime launchDate = product.ProductFields.ContainsKey("Custom_LaunchDate") ? Converter.ToDateTime(product.ProductFields["Custom_LaunchDate"].Value) : DateTime.MinValue; 70 DateTime currentDate = DateTime.Today; 71 72 string addToCartIcon = Model.Item.GetRawValueString("Icon", iconPath + "shopping-cart.svg"); 73 string addToCartLabel = !addToCartIcon.Contains("_none") && !isCartDisabled ? $"<span class=\"icon-2\">{ReadFile(addToCartIcon)}</span>" : ""; 74 addToCartLabel += !addToCartIcon.Contains("_none") && !Model.Item.GetBoolean("HideButtonText") ? " " : ""; 75 addToCartLabel += !Model.Item.GetBoolean("HideButtonText") ? (isCartDisabled ? Translate("Sold out") : $"<span class=\"d-none d-md-inline\">{Translate("Add to cart")}</span><span class=\"d-inline d-md-none\">{Translate("Add")}</span>") : ""; 76 77 bool hideButtonSoldOut = !string.IsNullOrEmpty(Model.Item.GetString("Custom_HideButtonSoldOut")) ? Model.Item.GetBoolean("Custom_HideButtonSoldOut") : false; 78 79 if (currentDate < launchDate) 80 { 81 <p class="mb-1 mt-2">@Translate("Available from") @launchDate.ToLocalTime().ToLongDateString()</p> 82 } 83 else if (!(isCartDisabled && hideButtonSoldOut)) 84 { 85 <div class="d-flex flex-row flex-nowrap gap-2 order-2 order-lg-4 item_@Model.Item.SystemName.ToLower()"> 86 <form method="post" action="@url" class="flex-fill"> 87 <input type="hidden" name="redirect" value="false"> 88 <input type="hidden" name="ProductId" value="@product.Id"> 89 @*//CUSTOM*@ 90 <input type="hidden" name="ProductName" value="@HtmlEncoder.HtmlAttributeEncode(product.GetTrackingName() ?? product.Name)"> 91 <input type="hidden" name="ProductCurrency" value="@product.Price.CurrencyCode"> 92 <input type="hidden" name="ProductPrice" value="@product.Price.Price.ToString("0.00", System.Globalization.CultureInfo.InvariantCulture)"> 93 <input type="hidden" name="ProductDiscount" value="@product.Discount.Price.ToString("0.00", System.Globalization.CultureInfo.InvariantCulture)"> 94 @*//--CUSTOM*@ 95 @* CUSTOM - used for frontend failsafe quantity validation in _cart.ts *@ 96 <input type="hidden" name="ProductIsNeverOutOfStock" value="@IsNeverOutOfStock.ToString()"> 97 <input type="hidden" name="ProductStock" value="@product.StockLevel"> 98 @* CUSTOM END *@ 99 <input type="hidden" name="ProductReferer" value="product_details_info"> 100 <input type="hidden" name="cartcmd" value="add"> 101 102 @if (!string.IsNullOrEmpty(product.VariantId)) 103 { 104 <input type="hidden" name="VariantId" value="@product.VariantId"> 105 } 106 107 @if (!plytixIsNotForSale) 108 { 109 if (!quantitySelector || isCartDisabled) 110 { 111 <input id="Quantity_@product.Id" name="Quantity" value="@valueQty" type="hidden"> 112 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary w-100 js-add-to-cart-button @disableAddToCart" @disableAddToCart title="@HtmlEncoder.HtmlAttributeEncode(isCartDisabled ? Translate("Sold out") : Translate("Add to cart"))" id="AddToCartButton@(product.Id)_@Pageview.CurrentParagraph.ID">@addToCartLabel</button> 113 } 114 else 115 { 116 <div class="input-group input-primary-button-group js-input-group d-flex flex-row"> 117 <label for="Quantity_@(product.Id)" class="visually-hidden">@Translate("Quantity")</label> 118 <input id="Quantity_@product.Id" name="Quantity" value="@valueQty" step="@stepQty" @minQty @onChangeEvent class="form-control" style="max-width: 96px; min-width:64px;" type="number" onkeydown="swift.Cart.UpdateOnEnterKey(event)"> 119 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button @disableAddToCart" @disableAddToCart title="@HtmlEncoder.HtmlAttributeEncode(Translate("Add to cart"))" id="AddToCartButton@(product.Id)_@Pageview.CurrentParagraph.ID">@addToCartLabel</button> 120 @* CUSTOM - Validate stock level in quantity-input, mimicking behavior on OrderLineItem in Cart. 121 NOTE: Below is copied from standard Cart.cshtml template *@ 122 @if (!IsNeverOutOfStock) 123 { 124 <script> 125 function debounce(func, wait, immediate) { 126 var timeout; 127 return function () { 128 var context = this, args = arguments; 129 var later = function () { 130 timeout = null; 131 if (!immediate) func.apply(context, args); 132 }; 133 var callNow = immediate && !timeout; 134 clearTimeout(timeout); 135 timeout = setTimeout(later, wait); 136 if (callNow) func.apply(context, args); 137 }; 138 }; 139 140 // NOTE: 'step' param is custom 141 var UpdateQuantity = debounce(function (input, stock, step) { 142 var inputValue = parseFloat(input.value); 143 var stock = parseFloat(stock); 144 var step = parseFloat(step); 145 146 if (inputValue <= stock) { 147 input.classList.remove("is-invalid"); 148 input.closest(".js-input-group").querySelector(".js-not-enough-stock").classList.add("d-none"); 149 } else { 150 var validQuantity = Math.floor(stock / step) * step; 151 if (validQuantity === 0) { 152 validQuantity = step; 153 } 154 input.value = validQuantity; 155 input.classList.add("is-invalid"); 156 input.closest(".js-input-group").querySelector(".js-not-enough-stock").classList.remove("d-none"); 157 } 158 }, 300); 159 </script> 160 <div class="invalid-feedback js-not-enough-stock d-none w-100"> 161 @Translate("We do not have enough products in stock") 162 </div> 163 } 164 </div> 165 } 166 167 if (stepQty != "1") 168 { 169 <div class="invalid-feedback d-none"> 170 @Translate("Please select a quantity that is dividable by") @stepQty 171 </div> 172 } 173 } 174 </form> 175 </div> 176 } 177 } 178 else if (Pageview.IsVisualEditorMode) 179 { 180 <div class="alert alert-dark m-0">@Translate("No products available")</div> 181 } 182
![]()
![]()
![]()
![]()
![]()
In stock
Error executing template "/Designs/Swift/Paragraph/Swift_ProductSpecification_Custom.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, ProductFieldValue pfv) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetProductFieldValues(ProductViewModelSettings settings, Product product) at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_f0211c8aceb14a2580502254331340f9.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductSpecification_Custom.cshtml:line 89 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.Core @*//CUSTOM*@ 3 @using Dynamicweb.Ecommerce.ProductCatalog 4 5 @* CUSTOM TEMPLATE SUPPORTED BY SWIFT (v1.20.0) - NOTE: THIS TEMPLATE IS NOT SUPPORTED IN DW10 *@ 6 @* STANDARD TEMPLATE IS DEPRECATED IN SWIFT (1.25.0) *@ 7 8 @{ 9 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false; 10 11 ProductViewModel product = new ProductViewModel(); 12 13 ProductViewModelSettings productSetting = new ProductViewModelSettings 14 { 15 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID, 16 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code, 17 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2, 18 ShopId = Pageview.Area.EcomShopId 19 }; 20 21 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 22 { 23 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 24 } 25 else if (Pageview.Item["DummyProduct"] != null) 26 { 27 28 string dummyProductId = ""; 29 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 30 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 31 if (productList.Products != null) 32 { 33 foreach (var p in productList.Products) { dummyProductId = p.Id; } 34 ProductViewModel dummyProduct = dummyProductId != "" ? ViewModelFactory.CreateView(productSetting, dummyProductId) : new ProductViewModel(); 35 product = dummyProduct; 36 } 37 else 38 { 39 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 40 } 41 } 42 else if (Pageview.Item["DummyProduct"] == null) 43 { 44 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 45 } 46 } 47 48 @if (product?.Id != null) 49 { 50 IEnumerable<string> selectedDisplayGroupIds = Model.Item.GetRawValueString("DisplayGroups").Split(',').ToList(); 51 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 52 53 foreach (var selection in selectedDisplayGroupIds) 54 { 55 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 56 { 57 if (selection == group.Id) 58 { 59 displayGroups.Add(group); 60 } 61 } 62 } 63 64 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 65 66 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 67 68 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 69 70 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 71 72 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 73 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding; 74 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding; 75 76 string layout = Model.Item.GetRawValueString("Layout", "list"); 77 string size = Model.Item.GetRawValueString("Size", "full"); 78 79 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 80 { 81 product.ProductFields.Clear(); 82 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 83 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 84 showProductFields = true; 85 } 86 87 <div class="@(theme) h-100 item_@Model.Item.SystemName.ToLower()" id="specifications"> 88 <div class="@contentPadding"> 89 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) 90 { 91 if (!hideTitle) 92 { 93 <div class="text-start pb-2 pb-lg-4"> 94 <h2 class="@titleFontSize">@Model.Item.GetString("Title")</h2> 95 </div> 96 } 97 } 98 99 @if (displayGroups.Count != 0) 100 { 101 <div class="accordion-specifications-container col-12 col-lg-10 mx-auto"> 102 <div class="accordion accordion-flush" id="accordionSpecifications"> 103 104 @*//CUSTOM*@ 105 @if (product.LongDescription.IsNotNullOrEmpty()) 106 { 107 <div class="accordion-item"> 108 <div class="accordion-header" id="specifications-heading-longdescription"> 109 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#specifications-collapse-longdescription" aria-expanded="false" aria-controls="specifications-collapse-longdescription"> 110 <h4 class="h4 mb-0">@Translate("Custom:ProductSpecification.Description.Heading", "Beskrivelse")</h4> 111 </button> 112 </div> 113 <div id="specifications-collapse-longdescription" class="accordion-collapse collapse small show" aria-labelledby="specifications-heading-longdescription" data-bs-parent="#accordionSpecifications"> 114 <div class="grid"> 115 <div class="g-col-12 g-col-lg-8 mb-3 js-custom-ellipsis-readmore custom-ellipsis-readmore" data-ellipsis-readmore="5"> 116 <div class="custom-ellipsis-readmore__content">@product.LongDescription</div> 117 <div class="custom-ellipsis-readmore__readmore" onclick="this.parentNode.classList.add('show');"><u>@Translate("Custom:ProductSpecification.Description.ReadMore", "Læs mere")</u></div> 118 </div> 119 </div> 120 </div> 121 </div> 122 } 123 @*//--CUSTOM*@ 124 125 @*//CUSTOM*@ 126 @if (product.ProductCategories != null) 127 { 128 var productCategoryGroups = product.ProductCategories.Values 129 .SelectMany(category => category.Fields?.Where(i => i.Key == "Custom_DesignerArticles" || i.Key == "Custom_CaseArticles") ?? Enumerable.Empty<KeyValuePair<string, FieldValueViewModel>>()) 130 .GroupBy(i => i.Key) 131 .Select(g => new 132 { 133 Key = g.Key, 134 PageIds = g.SelectMany(j => j.Value.ToString().Split(',')).Select(j => int.TryParse(j, out int k) ? k : (int?)null).Where(j => j.HasValue).Select(j => j.Value).ToArray() 135 }) 136 .Where(g => g.PageIds.Any()) 137 .ToDictionary( 138 g => g.Key, 139 g => Dynamicweb.Content.Services.Pages.GetPages(g.PageIds).Select(p => Dynamicweb.Content.Services.Pages.GetPageOrLanguage(p.ID, Pageview.Area.ID)).Where(p => p != null && p.ItemType == "Swift_Article").ToList() 140 ); 141 142 foreach (var productCategoryGroup in productCategoryGroups) 143 { 144 if (productCategoryGroup.Value.Any()) 145 { 146 string groupId = productCategoryGroup.Key.Replace("_", "").ToLower(); 147 string groupKey = productCategoryGroup.Key.Replace("_", ""); 148 string groupName = productCategoryGroup.Key.Replace("Custom_", ""); 149 150 <div class="accordion-item"> 151 <div class="accordion-header" id="specifications-heading-@(groupId)"> 152 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#specifications-collapse-@(groupId)" aria-expanded="false" aria-controls="specifications-collapse-@(groupId)"> 153 <h4 class="h4 mb-0">@Translate($"Custom:ProductSpecification.{groupKey}.Heading", groupName)</h4> 154 </button> 155 </div> 156 <div id="specifications-collapse-@(groupId)" class="accordion-collapse collapse small" aria-labelledby="specifications-heading-@(groupId)" data-bs-parent="#accordionSpecifications"> 157 <div class="mb-4"> 158 @foreach (Dynamicweb.Content.Page page in productCategoryGroup.Value) 159 { 160 <div class="grid mb-3"> 161 <div class="g-col-12 g-col-lg-5 g-col-xl-4 g-col-xxl-3"> 162 @if (page.Item.TryGetValue("CoverImage", out object coverImage)) 163 { 164 var coverImageUri = new Uri("http://dummy.com" + coverImage.ToString()); 165 var coverImagePathParams = System.Web.HttpUtility.ParseQueryString(coverImageUri.Query); 166 167 <figure class="overflow-hidden m-0 mx-auto ratio" style="--bs-aspect-ratio: 75%"> 168 @RenderPartial("Components/Image.cshtml", 169 new Dynamicweb.Frontend.FileViewModel 170 { 171 Path = System.Web.HttpUtility.UrlDecode(coverImageUri.AbsolutePath), 172 FocalX = Converter.ToInt32(coverImagePathParams["X"]), 173 FocalY = Converter.ToInt32(coverImagePathParams["Y"]) 174 }, 175 new Dictionary<string, object> 176 { 177 { "loading", "lazy" }, 178 { "alt", Converter.ToString(page.Item["Title"]) } 179 }) 180 </figure> 181 } 182 </div> 183 <div class="g-col-12 g-col-lg-7 g-col-xl-4 g-col-xxl-3"> 184 <div class="d-flex flex-column gap-2"> 185 @if (page.Item.TryGetValue("Title", out object title)) 186 { 187 <h2 class="h6 text-inherit opacity-100 mw-75ch m-0">@title</h2> 188 } 189 @if (page.Item.TryGetValue("Summary", out object summary)) 190 { 191 <div class="text-inherit opacity-100 mw-75ch"> 192 <p class="m-0">@summary</p> 193 </div> 194 } 195 <div class="d-flex flex-wrap gap-3"> 196 <a href="Default.aspx?ID=@(page.ID)" class="link">@Translate($"Custom:ProductSpecification.{groupKey}.ReadMore", "Read more »")</a> 197 </div> 198 </div> 199 </div> 200 </div> 201 } 202 </div> 203 </div> 204 </div> 205 } 206 } 207 } 208 @*//--CUSTOM*@ 209 210 @foreach (var group in displayGroups) 211 { 212 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 213 string groupId = group.Id; 214 string buttonCollapsedState = Model.Item.GetBoolean("OpenDetailsAccordion") ? "" : "collapsed"; 215 string accordionShow = Model.Item.GetBoolean("OpenDetailsAccordion") ? "show" : ""; 216 217 @*//CUSTOM*@ 218 if (product.ProductType == Dynamicweb.Ecommerce.Products.ProductType.Bom && group.Id == "Product_details") 219 { 220 var apiProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, product.VariantId, product.LanguageId, false); 221 var productNumbers = new List<string>(); 222 223 foreach (Dynamicweb.Ecommerce.Products.ProductItem item in apiProduct.Items) 224 { 225 foreach (Dynamicweb.Ecommerce.Products.Product productitem in item.Products) 226 { 227 productNumbers.Add(productitem.Number); 228 } 229 } 230 if (productNumbers.Any()) 231 { 232 string commaSeparatedNumbers = string.Join(", ", productNumbers); 233 FieldValueViewModel productNumberInBOM = new FieldValueViewModel(); 234 productNumberInBOM.Name = Translate("Custom:ProductSpecification.ProductNumbersInBOM", "Product numbers in BOM"); 235 productNumberInBOM.Value = commaSeparatedNumbers; 236 productNumberInBOM.Type = "Text"; 237 productNumberInBOM.SystemName = "ProductNumbersInBOM"; 238 group.Fields.Add("Product numbers in BOM", productNumberInBOM); 239 } 240 } 241 @*//--CUSTOM*@ 242 243 <div class="accordion-item"> 244 <div class="accordion-header" id="specifications-heading-@groupId"> 245 <button class="accordion-button @buttonCollapsedState" type="button" data-bs-toggle="collapse" data-bs-target="#specifications-collapse-@groupId" aria-expanded="false" aria-controls="specifications-collapse-@groupId"> 246 @if (!hideHeader) 247 { 248 <h4 class="h4 mb-0">@group.Name</h4> 249 } 250 </button> 251 </div> 252 <div id="specifications-collapse-@groupId" class="accordion-collapse collapse small @accordionShow" aria-labelledby="specifications-heading-@groupId" data-bs-parent="#accordionSpecifications"> 253 <div>@RenderFieldsFromList(group.Fields, layout)</div> 254 </div> 255 </div> 256 } 257 258 @if (!string.IsNullOrEmpty(Pageview.AreaSettings.GetItem("CustomSettings").GetString("FreightAndDeliveryText"))) 259 { 260 <div class="accordion-item"> 261 <div class="accordion-header" id="specifications-heading-DeliveryInfo"> 262 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#specifications-collapse-DeliveryInfo" aria-expanded="false" aria-controls="specifications-collapse-DeliveryInfo"> 263 <h4 class="h4 mb-0">@Pageview.AreaSettings.GetItem("CustomSettings").GetString("FreightAndDeliveryHeading")</h4> 264 </button> 265 </div> 266 <div id="specifications-collapse-DeliveryInfo" class="accordion-collapse collapse small" aria-labelledby="specifications-heading-DeliveryInfo" data-bs-parent="#accordionSpecifications"> 267 <div class="mb-4">@Pageview.AreaSettings.GetItem("CustomSettings").GetString("FreightAndDeliveryText")</div> 268 </div> 269 </div> 270 } 271 272 </div> 273 </div> 274 } 275 276 @if (product.ProductFields != null && showProductFields) 277 { 278 if (product.ProductFields.Count > 0) 279 { 280 @RenderFieldsFromList(product.ProductFields, layout); 281 } 282 } 283 284 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 285 { 286 if (product.ProductCategories.Count > 0) 287 { 288 foreach (var group in product.ProductCategories) 289 { 290 CategoryFieldViewModel category = group.Value; 291 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 292 293 if (!hideHeader) 294 { 295 <h4 class="h4 mb-4">@group.Value.Name</h4> 296 } 297 298 @RenderFieldsFromList(category.Fields, layout); 299 } 300 } 301 } 302 </div> 303 </div> 304 } 305 else if (Pageview.IsVisualEditorMode) 306 { 307 <div class="alert alert-warning m-0">@Translate("No products available")</div> 308 } 309 310 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) 311 { 312 string size = Model.Item.GetRawValueString("Size", "full"); 313 string extraMargin = size == "full" ? "mb-3" : ""; 314 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 315 316 <div class="@extraMargin"> 317 @if (layout == "columns") 318 { 319 string gaps = size == "full" ? "gap-0" : "gap-2"; 320 321 <div class="grid @gaps"> 322 @foreach (var field in fields) 323 { 324 @RenderField(field.Value, layout) 325 } 326 </div> 327 } 328 @if (layout == "list") 329 { 330 <dl class="grid gap-0"> 331 @foreach (var field in fields) 332 { 333 @RenderField(field.Value, layout) 334 } 335 </dl> 336 } 337 @if (layout == "table") 338 { 339 string tableSize = size == "full" ? "" : "table-sm"; 340 341 <table class="table table-striped @tableSize"> 342 @foreach (var field in fields) 343 { 344 @RenderField(field.Value, layout) 345 } 346 </table> 347 } 348 @if (layout == "bullets") 349 { 350 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 351 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 352 353 <ul class="@listSize" @listStyle> 354 @foreach (var field in fields) 355 { 356 @RenderField(field.Value, layout) 357 } 358 </ul> 359 } 360 @if (layout == "commas") 361 { 362 List<string> featuresList = new List<string>(); 363 364 foreach (var field in fields) 365 { 366 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 367 { 368 List<string> options = new List<string>(); 369 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 370 { 371 if (!string.IsNullOrWhiteSpace(option.Value)) 372 { 373 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 374 { 375 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 376 options.Add(colorSpan); 377 } 378 else if (!string.IsNullOrEmpty(option.Value)) 379 { 380 options.Add(option.Name); 381 } 382 } 383 } 384 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 385 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 386 { 387 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 388 } 389 390 if (!hideFieldLabels) 391 { 392 featuresList.Add(field.Value.Name + ": " + optionsString); 393 } 394 else 395 { 396 featuresList.Add(optionsString); 397 } 398 } 399 else 400 { 401 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 402 { 403 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 404 { 405 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 406 407 if (!hideFieldLabels) 408 { 409 featuresList.Add(field.Value.Name + ": " + colorSpan); 410 } 411 else 412 { 413 featuresList.Add(colorSpan); 414 } 415 } 416 else 417 { 418 if (!hideFieldLabels) 419 { 420 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 421 } 422 else 423 { 424 featuresList.Add(field.Value.Value.ToString()); 425 } 426 } 427 } 428 } 429 } 430 431 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 432 433 <div class="opacity-75 fs-7">@featuresString</div> 434 } 435 </div> 436 } 437 438 @helper RenderField(FieldValueViewModel field, string layout) 439 { 440 string size = Model.Item.GetRawValueString("Size", "full"); 441 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 442 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 443 bool noValues = false; 444 445 if (!string.IsNullOrEmpty(fieldValue)) 446 { 447 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 448 { 449 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 450 noValues = values.Count > 0 ? false : true; 451 } 452 } 453 454 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 455 { 456 if (layout == "columns") 457 { 458 <div class="grid g-col-6 g-col-lg-4"> 459 @if (!hideFieldLabels) 460 { 461 <dt class="g-col-4 py-2 fw-bold">@field.Name</dt> 462 } 463 <dd class="g-col-8 py-2 mb-0">@RenderFieldValue(field)</dd> 464 </div> 465 } 466 if (layout == "list") 467 { 468 string extraPadding = size == "full" ? "py-2" : ""; 469 470 if (!hideFieldLabels) 471 { 472 <dt class="g-col-4 @extraPadding fw-bold">@field.Name</dt> 473 } 474 <dd class="g-col-8 @extraPadding mb-0"> 475 @RenderFieldValue(field) 476 </dd> 477 } 478 if (layout == "table") 479 { 480 <tr> 481 @if (!hideFieldLabels) 482 { 483 <th class="fw-bold" scope="row">@field.Name</th> 484 } 485 <td>@RenderFieldValue(field)</td> 486 </tr> 487 } 488 if (layout == "bullets") 489 { 490 <li> 491 @if (!hideFieldLabels) 492 { 493 <strong>@field.Name</strong> 494 } 495 <span>@RenderFieldValue(field)</span> 496 </li> 497 } 498 } 499 } 500 501 @helper RenderFieldValue(FieldValueViewModel field) 502 { 503 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 504 505 bool isLink = field?.Type == "Link"; 506 bool isColor = false; 507 bool isBrandName = field?.SystemName == "Brand_name"; 508 509 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 510 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 511 512 513 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 514 { 515 int valueCount = 0; 516 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 517 int totalValues = values.Count; 518 519 foreach (FieldOptionValueViewModel option in values) 520 { 521 if (option.Value.Substring(0, 1) == "#") 522 { 523 isColor = true; 524 } 525 526 if (!isColor) 527 { 528 @option.Name 529 } 530 else 531 { 532 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 533 } 534 535 if (valueCount != totalValues && valueCount < (totalValues - 1)) 536 { 537 if (isColor) 538 { 539 <text> </text> 540 } 541 else 542 { 543 <text>, </text> 544 } 545 } 546 valueCount++; 547 } 548 } 549 else 550 { 551 if (fieldValue.Substring(0, 1) == "#") 552 { 553 isColor = true; 554 } 555 556 if (!isColor) 557 { 558 if (isLink) 559 { 560 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 561 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 562 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 563 564 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 565 } 566 else if (isBrandName) 567 { 568 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 569 <span itemprop="name">@fieldValue</span> 570 </span> 571 } 572 else 573 { 574 //CUSTOM 575 if (!new string[] { "ProductNumber", "ProductEAN" }.Contains(field.SystemName)) 576 { 577 @Translate("Custom:FacetOption." + fieldValue, fieldValue) 578 } 579 else 580 { 581 @fieldValue 582 } 583 //--CUSTOM 584 } 585 } 586 else 587 { 588 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 589 } 590 } 591 } 592