Personlig indretning med Christina Dueholm
Med sans for detaljen og en forkærlighed for tidløst design blander hun nyt og gammelt, funktion og æstetik, og skaber rum, der både inspirerer og omfavner hverdagen.
Error executing template "/Designs/Swift/Paragraph/Swift_ProductHeader_Custom_v2.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_a54ea8a4f1074c649f86f0e8463ffd4c.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductHeader_Custom_v2.cshtml:line 41 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template) at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using Dynamicweb.Core @* CUSTOM *@ 4 5 @* CUSTOMIZED STANDARD SWIFT (v1.25.0) TEMPLATE *@ 6 7 @{ 8 ProductViewModel product = null; 9 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 10 { 11 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 12 } 13 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 14 { 15 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 16 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 17 18 if (productList?.Products is object) 19 { 20 product = productList.Products[0]; 21 } 22 } 23 } 24 25 @if (product is object) 26 { 27 string titleFontSize = Model.Item.GetRawValueString("FontSize", "fs-6"); 28 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 29 horizontalAlign = horizontalAlign == "center" ? "text-center" : horizontalAlign; 30 horizontalAlign = horizontalAlign == "end" ? "text-end" : horizontalAlign; 31 32 string headingLevel = Model.Item.GetString("HeadingLevel", "h2"); 33 string headingLevelStart = $"<{headingLevel} class=\"{titleFontSize} {horizontalAlign} m-0 item_{Model.Item.SystemName.ToLower()}\" itemprop=\"name\">"; 34 string headingLevelStop = $"</{headingLevel}>"; 35 36 // CUSTOM 37 string brandLogo = Model.Item.GetString("Custom_BrandLogo"); 38 string brandLogoKey = Model.Item.GetString("Custom_BrandLogoKey"); 39 string brandLogoAltText = Model.Item.GetString("Custom_BrandAltText"); 40 int brandLogoWidth = Model.Item.GetInt32("Custom_BrandLogoWidth") > 0 ? Model.Item.GetInt32("Custom_BrandLogoWidth") : 70; 41 string productBrand = product.ProductFields.ContainsKey("Custom_Brand") ? Converter.ToString(product.ProductFields["Custom_Brand"].Value) : ""; 42 bool enableBrandLogo = !string.IsNullOrEmpty(brandLogo) && !string.IsNullOrEmpty(brandLogoKey) && brandLogoKey == productBrand; 43 44 if (enableBrandLogo) 45 { 46 <img src="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(brandLogo)" 47 alt="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(brandLogoAltText)" 48 width="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(brandLogoWidth.ToString())" /> 49 } 50 // CUSTOM END 51 52 @headingLevelStart 53 @product.Name 54 @headingLevelStop 55 } 56 else if (Pageview.IsVisualEditorMode) 57 { 58 <div class="alert alert-dark m-0">@Translate("No products available")</div> 59 } 60
Error executing template "Designs/Swift/Paragraph/Swift_ProductBadges_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_fe4e63c166214874a0bcb86da4f14f88.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductBadges_Custom.cshtml:line 27 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 System.Linq 5 @using Dynamicweb.Frontend 6 @using Dynamicweb.Content 7 @using Dynamicweb.Core 8 @using Dynamicweb.Ecommerce.ProductCatalog 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 DateTime launchDate = product.ProductFields.ContainsKey("Custom_LaunchDate") ? Converter.ToDateTime(product.ProductFields["Custom_LaunchDate"].Value) : DateTime.MinValue; 28 DateTime currentDate = DateTime.Today; 29 bool showComingSoonBadge = currentDate < launchDate && string.Equals( Model.Item.GetRawValueString("NewBadgeDesign"), "comingsoon", StringComparison.InvariantCultureIgnoreCase ); 30 } 31 32 @if (product is object) 33 { 34 var badgeParms = new Dictionary<string, object>(); 35 badgeParms.Add("size", "h7"); 36 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 37 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 38 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 39 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 40 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 41 42 string badgeSize = Model.Item.GetRawValueString("BadgeSize", "fs-2"); 43 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 44 horizontalAlign = horizontalAlign == "center" ? "text-center" : horizontalAlign; 45 horizontalAlign = horizontalAlign == "end" ? "text-end" : horizontalAlign; 46 47 Dictionary<string, ParagraphInfoViewModel> badgeConfigurations; 48 List<string> campaignBadgesValues = Model.Item.GetRawValueString("CampaignBadges") != null ? Model.Item.GetRawValueString("CampaignBadges").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List<string>(); 49 50 if (Dynamicweb.Context.Current.Items.Contains("badgeConfigurations")) 51 { 52 badgeConfigurations = (Dictionary<string, ParagraphInfoViewModel>)Dynamicweb.Context.Current.Items["badgeConfigurations"]; 53 } 54 else 55 { 56 var badgesPage = Pageview.AreaSettings.GetLink("EcommerceBadgesPage") != null ? Pageview.AreaSettings.GetLink("EcommerceBadgesPage").PageId : 0; 57 var allBadges = badgesPage != 0 ? Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(badgesPage) : null; 58 59 badgeConfigurations = new Dictionary<string, ParagraphInfoViewModel>(); 60 61 if ( allBadges != null ) 62 { 63 foreach ( Paragraph badge in allBadges ) 64 { 65 var paragraphviewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreateParagraphInfoViewModel( badge ); 66 string cssClassName = paragraphviewModel.Item.GetString( "CssClassName" )?.Trim().ToLower() ?? string.Empty;; 67 if ( !badgeConfigurations.ContainsKey( cssClassName ) ) 68 { 69 badgeConfigurations.Add( cssClassName, paragraphviewModel ); 70 } 71 } 72 } 73 74 Dynamicweb.Context.Current.Items.Add("badgeConfigurations", badgeConfigurations); 75 } 76 77 int badgesCount = 0; 78 if (badgeConfigurations.Any()) 79 { 80 foreach (string campaign in campaignBadgesValues) 81 { 82 if (!string.IsNullOrEmpty(campaign)) 83 { 84 FieldValueViewModel availableCampaignsObject; 85 product.ProductFields.TryGetValue("Campaign", out availableCampaignsObject); 86 87 if (availableCampaignsObject != null) 88 { 89 string campaignType = string.Empty; 90 91 if (badgeConfigurations.ContainsKey(campaign)) 92 { 93 ParagraphInfoViewModel paragraphviewModel; 94 if (badgeConfigurations.TryGetValue(campaign, out paragraphviewModel)) 95 { 96 campaignType = paragraphviewModel.Item.GetRawValueString("CampaignType"); 97 } 98 } 99 100 List<FieldOptionValueViewModel> availableCampaigns = (List<FieldOptionValueViewModel>)availableCampaignsObject.Value; 101 102 foreach (FieldOptionValueViewModel availableOption in availableCampaigns) 103 { 104 if (campaignType == availableOption.Value) 105 { 106 badgesCount++; 107 break; 108 } 109 } 110 } 111 } 112 } 113 } 114 115 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 116 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 117 DateTime createdDate = product.Created.Value; 118 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 119 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 120 showBadges = (!string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) && badgesCount != 0) || showComingSoonBadge || showBadges; 121 122 if (showBadges) 123 { 124 <div class="@badgeSize @horizontalAlign item_@Model.Item.SystemName.ToLower()"> 125 @RenderPartial("Components/EcommerceBadge_Custom.cshtml", product, badgeParms) @*//CUSTOM*@ 126 </div> 127 } 128 else if (Pageview.IsVisualEditorMode) 129 { 130 <span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span> 131 } 132 } 133 else if (Pageview.IsVisualEditorMode) 134 { 135 <span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span> 136 } 137 138
Error executing template "/Designs/Swift/Paragraph/Swift_Custom_ProductFacts.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_1a53976adc1341c7bf928b5d5d9b625c.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_Custom_ProductFacts.cshtml:line 90 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 System.Linq 5 @using Dynamicweb.Ecommerce.ProductCatalog 6 7 @* CUSTOM TEMPLATE SUPPORTED BY SWIFT (v1.25.0) - NOTE: THIS TEMPLATE IS NOT SUPPORTED IN DW10 *@ 8 9 @{ 10 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false; 11 12 ProductViewModel product = new ProductViewModel(); 13 14 ProductViewModelSettings productSetting = new ProductViewModelSettings 15 { 16 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID, 17 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code, 18 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2, 19 ShopId = Pageview.Area.EcomShopId 20 }; 21 22 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 23 { 24 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 25 } 26 else if (Pageview.Item["DummyProduct"] != null) 27 { 28 29 string dummyProductId = ""; 30 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 31 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 32 if (productList.Products != null) 33 { 34 foreach (var p in productList.Products) { dummyProductId = p.Id; } 35 ProductViewModel dummyProduct = dummyProductId != "" ? ViewModelFactory.CreateView(productSetting, dummyProductId) : new ProductViewModel(); 36 product = dummyProduct; 37 } 38 else 39 { 40 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 41 } 42 } 43 else if (Pageview.Item["DummyProduct"] == null) 44 { 45 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 46 } 47 } 48 49 @if (product?.Id != null) 50 { 51 IEnumerable<string> selectedDisplayGroupIds = Model.Item.GetRawValueString("DisplayGroups").Split(',').ToList(); 52 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 53 54 foreach (var selection in selectedDisplayGroupIds) 55 { 56 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 57 { 58 if (selection == group.Id) 59 { 60 displayGroups.Add(group); 61 } 62 } 63 } 64 65 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 66 67 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 68 69 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 70 71 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 72 73 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 74 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding; 75 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding; 76 77 string layout = Model.Item.GetRawValueString("Layout", "list"); 78 string size = Model.Item.GetRawValueString("Size", "full"); 79 80 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 81 { 82 product.ProductFields.Clear(); 83 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 84 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 85 showProductFields = true; 86 } 87 88 <div class="@(theme) h-100 item_@Model.Item.SystemName.ToLower()" id="specifications"> 89 <div class="@contentPadding"> 90 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) 91 { 92 if (!hideTitle) 93 { 94 <div class="text-start pb-2 pb-lg-4"> 95 <h2 class="@titleFontSize">@Model.Item.GetString("Title")</h2> 96 </div> 97 } 98 } 99 100 @if (displayGroups.Count != 0) 101 { 102 foreach (var group in displayGroups) 103 { 104 <div class="order-5 order-lg-0"> 105 <dl class="grid gap-0"> 106 @foreach (var field in group.Fields) 107 { 108 @RenderField(field.Value, layout) 109 } 110 </dl> 111 </div> 112 } 113 } 114 115 @if (product.ProductFields != null && showProductFields) 116 { 117 if (product.ProductFields.Count > 0) 118 { 119 @RenderFieldsFromList(product.ProductFields, layout); 120 } 121 } 122 123 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 124 { 125 if (product.ProductCategories.Count > 0) 126 { 127 foreach (var group in product.ProductCategories) 128 { 129 CategoryFieldViewModel category = group.Value; 130 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 131 132 if (!hideHeader) 133 { 134 <h4 class="h4 mb-4">@group.Value.Name</h4> 135 } 136 137 @RenderFieldsFromList(category.Fields, layout); 138 } 139 } 140 } 141 </div> 142 </div> 143 } 144 else if (Pageview.IsVisualEditorMode) 145 { 146 <div class="alert alert-warning m-0">@Translate("No products available")</div> 147 } 148 149 150 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) 151 { 152 string size = Model.Item.GetRawValueString("Size", "full"); 153 string extraMargin = size == "full" ? "mb-3" : ""; 154 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 155 156 <div class="@extraMargin"> 157 @if (layout == "columns") 158 { 159 string gaps = size == "full" ? "gap-0" : "gap-2"; 160 161 <div class="grid @gaps"> 162 @foreach (var field in fields) 163 { 164 @RenderField(field.Value, layout) 165 } 166 </div> 167 } 168 @if (layout == "list") 169 { 170 <dl class="grid gap-0"> 171 @foreach (var field in fields) 172 { 173 @RenderField(field.Value, layout) 174 } 175 </dl> 176 } 177 @if (layout == "table") 178 { 179 string tableSize = size == "full" ? "" : "table-sm"; 180 181 <table class="table table-striped @tableSize"> 182 @foreach (var field in fields) 183 { 184 @RenderField(field.Value, layout) 185 } 186 </table> 187 } 188 @if (layout == "bullets") 189 { 190 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 191 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 192 193 <ul class="@listSize" @listStyle> 194 @foreach (var field in fields) 195 { 196 @RenderField(field.Value, layout) 197 } 198 </ul> 199 } 200 @if (layout == "commas") 201 { 202 List<string> featuresList = new List<string>(); 203 204 foreach (var field in fields) 205 { 206 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 207 { 208 List<string> options = new List<string>(); 209 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 210 { 211 if (!string.IsNullOrWhiteSpace(option.Value)) 212 { 213 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 214 { 215 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 216 options.Add(colorSpan); 217 } 218 else if (!string.IsNullOrEmpty(option.Value)) 219 { 220 options.Add(option.Name); 221 } 222 } 223 } 224 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 225 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 226 { 227 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 228 } 229 230 if (!hideFieldLabels) 231 { 232 featuresList.Add(field.Value.Name + ": " + optionsString); 233 } 234 else 235 { 236 featuresList.Add(optionsString); 237 } 238 } 239 else 240 { 241 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 242 { 243 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 244 { 245 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 246 247 if (!hideFieldLabels) 248 { 249 featuresList.Add(field.Value.Name + ": " + colorSpan); 250 } 251 else 252 { 253 featuresList.Add(colorSpan); 254 } 255 } 256 else 257 { 258 if (!hideFieldLabels) 259 { 260 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 261 } 262 else 263 { 264 featuresList.Add(field.Value.Value.ToString()); 265 } 266 } 267 } 268 } 269 } 270 271 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 272 273 <div class="opacity-75 fs-7">@featuresString</div> 274 } 275 </div> 276 } 277 278 @helper RenderField(FieldValueViewModel field, string layout) 279 { 280 string size = Model.Item.GetRawValueString("Size", "full"); 281 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 282 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 283 bool noValues = false; 284 285 if (!string.IsNullOrEmpty(fieldValue)) 286 { 287 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 288 { 289 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 290 noValues = values.Count > 0 ? false : true; 291 } 292 } 293 294 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 295 { 296 if (layout == "columns") 297 { 298 <div class="grid g-col-6 g-col-lg-4"> 299 @if (!hideFieldLabels) 300 { 301 <dt class="g-col-4 py-2 fw-bold">@field.Name</dt> 302 } 303 <dd class="g-col-8 py-2 mb-0">@RenderFieldValue(field)</dd> 304 </div> 305 } 306 if (layout == "list") 307 { 308 string extraPadding = size == "full" ? "py-2" : ""; 309 310 if (!hideFieldLabels) 311 { 312 <dt class="g-col-4 @extraPadding fw-bold">@field.Name</dt> 313 } 314 <dd class="g-col-8 @extraPadding mb-0"> 315 @RenderFieldValue(field) 316 </dd> 317 } 318 if (layout == "table") 319 { 320 <tr> 321 @if (!hideFieldLabels) 322 { 323 <th class="fw-bold" scope="row">@field.Name</th> 324 } 325 <td>@RenderFieldValue(field)</td> 326 </tr> 327 } 328 if (layout == "bullets") 329 { 330 <dt class="g-col-12 g-col-sm-4 g-col-lg-12 fw-bold m-0">@field.Name</dt> 331 <dd class="g-col-12 g-col-sm-8 g-col-lg-12 mb-3"> 332 @RenderFieldValue(field) 333 </dd> 334 } 335 } 336 } 337 338 @helper RenderFieldValue(FieldValueViewModel field) 339 { 340 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 341 342 bool isLink = field?.Type == "Link"; 343 bool isColor = false; 344 bool isBrandName = field?.SystemName == "Brand_name"; 345 346 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 347 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 348 349 350 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 351 { 352 int valueCount = 0; 353 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 354 int totalValues = values.Count; 355 356 foreach (FieldOptionValueViewModel option in values) 357 { 358 if (option.Value.Substring(0, 1) == "#") 359 { 360 isColor = true; 361 } 362 363 if (!isColor) 364 { 365 @option.Name 366 } 367 else 368 { 369 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 370 } 371 372 if (valueCount != totalValues && valueCount < (totalValues - 1)) 373 { 374 if (isColor) 375 { 376 <text> </text> 377 } 378 else 379 { 380 <text>, </text> 381 } 382 } 383 valueCount++; 384 } 385 } 386 else 387 { 388 if (fieldValue.Substring(0, 1) == "#") 389 { 390 isColor = true; 391 } 392 393 if (!isColor) 394 { 395 if (isLink) 396 { 397 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 398 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 399 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 400 401 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 402 } 403 else if (isBrandName) 404 { 405 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 406 <span itemprop="name">@fieldValue</span> 407 </span> 408 } 409 else 410 { 411 @fieldValue 412 } 413 414 } 415 else 416 { 417 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 418 } 419 } 420 } 421
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_ProductBadges_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_fe4e63c166214874a0bcb86da4f14f88.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductBadges_Custom.cshtml:line 27 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 System.Linq 5 @using Dynamicweb.Frontend 6 @using Dynamicweb.Content 7 @using Dynamicweb.Core 8 @using Dynamicweb.Ecommerce.ProductCatalog 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 DateTime launchDate = product.ProductFields.ContainsKey("Custom_LaunchDate") ? Converter.ToDateTime(product.ProductFields["Custom_LaunchDate"].Value) : DateTime.MinValue; 28 DateTime currentDate = DateTime.Today; 29 bool showComingSoonBadge = currentDate < launchDate && string.Equals( Model.Item.GetRawValueString("NewBadgeDesign"), "comingsoon", StringComparison.InvariantCultureIgnoreCase ); 30 } 31 32 @if (product is object) 33 { 34 var badgeParms = new Dictionary<string, object>(); 35 badgeParms.Add("size", "h7"); 36 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 37 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 38 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 39 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 40 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 41 42 string badgeSize = Model.Item.GetRawValueString("BadgeSize", "fs-2"); 43 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 44 horizontalAlign = horizontalAlign == "center" ? "text-center" : horizontalAlign; 45 horizontalAlign = horizontalAlign == "end" ? "text-end" : horizontalAlign; 46 47 Dictionary<string, ParagraphInfoViewModel> badgeConfigurations; 48 List<string> campaignBadgesValues = Model.Item.GetRawValueString("CampaignBadges") != null ? Model.Item.GetRawValueString("CampaignBadges").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List<string>(); 49 50 if (Dynamicweb.Context.Current.Items.Contains("badgeConfigurations")) 51 { 52 badgeConfigurations = (Dictionary<string, ParagraphInfoViewModel>)Dynamicweb.Context.Current.Items["badgeConfigurations"]; 53 } 54 else 55 { 56 var badgesPage = Pageview.AreaSettings.GetLink("EcommerceBadgesPage") != null ? Pageview.AreaSettings.GetLink("EcommerceBadgesPage").PageId : 0; 57 var allBadges = badgesPage != 0 ? Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(badgesPage) : null; 58 59 badgeConfigurations = new Dictionary<string, ParagraphInfoViewModel>(); 60 61 if ( allBadges != null ) 62 { 63 foreach ( Paragraph badge in allBadges ) 64 { 65 var paragraphviewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreateParagraphInfoViewModel( badge ); 66 string cssClassName = paragraphviewModel.Item.GetString( "CssClassName" )?.Trim().ToLower() ?? string.Empty;; 67 if ( !badgeConfigurations.ContainsKey( cssClassName ) ) 68 { 69 badgeConfigurations.Add( cssClassName, paragraphviewModel ); 70 } 71 } 72 } 73 74 Dynamicweb.Context.Current.Items.Add("badgeConfigurations", badgeConfigurations); 75 } 76 77 int badgesCount = 0; 78 if (badgeConfigurations.Any()) 79 { 80 foreach (string campaign in campaignBadgesValues) 81 { 82 if (!string.IsNullOrEmpty(campaign)) 83 { 84 FieldValueViewModel availableCampaignsObject; 85 product.ProductFields.TryGetValue("Campaign", out availableCampaignsObject); 86 87 if (availableCampaignsObject != null) 88 { 89 string campaignType = string.Empty; 90 91 if (badgeConfigurations.ContainsKey(campaign)) 92 { 93 ParagraphInfoViewModel paragraphviewModel; 94 if (badgeConfigurations.TryGetValue(campaign, out paragraphviewModel)) 95 { 96 campaignType = paragraphviewModel.Item.GetRawValueString("CampaignType"); 97 } 98 } 99 100 List<FieldOptionValueViewModel> availableCampaigns = (List<FieldOptionValueViewModel>)availableCampaignsObject.Value; 101 102 foreach (FieldOptionValueViewModel availableOption in availableCampaigns) 103 { 104 if (campaignType == availableOption.Value) 105 { 106 badgesCount++; 107 break; 108 } 109 } 110 } 111 } 112 } 113 } 114 115 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 116 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 117 DateTime createdDate = product.Created.Value; 118 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 119 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 120 showBadges = (!string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) && badgesCount != 0) || showComingSoonBadge || showBadges; 121 122 if (showBadges) 123 { 124 <div class="@badgeSize @horizontalAlign item_@Model.Item.SystemName.ToLower()"> 125 @RenderPartial("Components/EcommerceBadge_Custom.cshtml", product, badgeParms) @*//CUSTOM*@ 126 </div> 127 } 128 else if (Pageview.IsVisualEditorMode) 129 { 130 <span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span> 131 } 132 } 133 else if (Pageview.IsVisualEditorMode) 134 { 135 <span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span> 136 } 137 138
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_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_fe4e63c166214874a0bcb86da4f14f88.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_ProductBadges_Custom.cshtml:line 27 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 System.Linq 5 @using Dynamicweb.Frontend 6 @using Dynamicweb.Content 7 @using Dynamicweb.Core 8 @using Dynamicweb.Ecommerce.ProductCatalog 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 DateTime launchDate = product.ProductFields.ContainsKey("Custom_LaunchDate") ? Converter.ToDateTime(product.ProductFields["Custom_LaunchDate"].Value) : DateTime.MinValue; 28 DateTime currentDate = DateTime.Today; 29 bool showComingSoonBadge = currentDate < launchDate && string.Equals( Model.Item.GetRawValueString("NewBadgeDesign"), "comingsoon", StringComparison.InvariantCultureIgnoreCase ); 30 } 31 32 @if (product is object) 33 { 34 var badgeParms = new Dictionary<string, object>(); 35 badgeParms.Add("size", "h7"); 36 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 37 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 38 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 39 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 40 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 41 42 string badgeSize = Model.Item.GetRawValueString("BadgeSize", "fs-2"); 43 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 44 horizontalAlign = horizontalAlign == "center" ? "text-center" : horizontalAlign; 45 horizontalAlign = horizontalAlign == "end" ? "text-end" : horizontalAlign; 46 47 Dictionary<string, ParagraphInfoViewModel> badgeConfigurations; 48 List<string> campaignBadgesValues = Model.Item.GetRawValueString("CampaignBadges") != null ? Model.Item.GetRawValueString("CampaignBadges").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List<string>(); 49 50 if (Dynamicweb.Context.Current.Items.Contains("badgeConfigurations")) 51 { 52 badgeConfigurations = (Dictionary<string, ParagraphInfoViewModel>)Dynamicweb.Context.Current.Items["badgeConfigurations"]; 53 } 54 else 55 { 56 var badgesPage = Pageview.AreaSettings.GetLink("EcommerceBadgesPage") != null ? Pageview.AreaSettings.GetLink("EcommerceBadgesPage").PageId : 0; 57 var allBadges = badgesPage != 0 ? Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(badgesPage) : null; 58 59 badgeConfigurations = new Dictionary<string, ParagraphInfoViewModel>(); 60 61 if ( allBadges != null ) 62 { 63 foreach ( Paragraph badge in allBadges ) 64 { 65 var paragraphviewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreateParagraphInfoViewModel( badge ); 66 string cssClassName = paragraphviewModel.Item.GetString( "CssClassName" )?.Trim().ToLower() ?? string.Empty;; 67 if ( !badgeConfigurations.ContainsKey( cssClassName ) ) 68 { 69 badgeConfigurations.Add( cssClassName, paragraphviewModel ); 70 } 71 } 72 } 73 74 Dynamicweb.Context.Current.Items.Add("badgeConfigurations", badgeConfigurations); 75 } 76 77 int badgesCount = 0; 78 if (badgeConfigurations.Any()) 79 { 80 foreach (string campaign in campaignBadgesValues) 81 { 82 if (!string.IsNullOrEmpty(campaign)) 83 { 84 FieldValueViewModel availableCampaignsObject; 85 product.ProductFields.TryGetValue("Campaign", out availableCampaignsObject); 86 87 if (availableCampaignsObject != null) 88 { 89 string campaignType = string.Empty; 90 91 if (badgeConfigurations.ContainsKey(campaign)) 92 { 93 ParagraphInfoViewModel paragraphviewModel; 94 if (badgeConfigurations.TryGetValue(campaign, out paragraphviewModel)) 95 { 96 campaignType = paragraphviewModel.Item.GetRawValueString("CampaignType"); 97 } 98 } 99 100 List<FieldOptionValueViewModel> availableCampaigns = (List<FieldOptionValueViewModel>)availableCampaignsObject.Value; 101 102 foreach (FieldOptionValueViewModel availableOption in availableCampaigns) 103 { 104 if (campaignType == availableOption.Value) 105 { 106 badgesCount++; 107 break; 108 } 109 } 110 } 111 } 112 } 113 } 114 115 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 116 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 117 DateTime createdDate = product.Created.Value; 118 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 119 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 120 showBadges = (!string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) && badgesCount != 0) || showComingSoonBadge || showBadges; 121 122 if (showBadges) 123 { 124 <div class="@badgeSize @horizontalAlign item_@Model.Item.SystemName.ToLower()"> 125 @RenderPartial("Components/EcommerceBadge_Custom.cshtml", product, badgeParms) @*//CUSTOM*@ 126 </div> 127 } 128 else if (Pageview.IsVisualEditorMode) 129 { 130 <span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span> 131 } 132 } 133 else if (Pageview.IsVisualEditorMode) 134 { 135 <span class="badge bg-success text-light rounded-0">@Translate("Badge example")</span> 136 } 137 138
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
Error executing template "Designs/Swift/Paragraph/Swift_BackInStockNotification_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_bd2da2e1f84b497481c5a93d146ce59f.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_BackInStockNotification_Custom.cshtml:line 48 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 @*//CUSTOM*@ 3 @using System.Linq 4 @using Dynamicweb.Ecommerce 5 @using Dynamicweb.Ecommerce.ProductCatalog 6 @using Dynamicweb.Ecommerce.Products 7 @using Dynamicweb.Ecommerce.Stocks 8 @using Dynamicweb.Core @*//CUSTOM*@ 9 10 @* CUSTOMIZED STANDARD SWIFT (v1.25.0) TEMPLATE *@ 11 12 @functions 13 { 14 private static bool BackInStockRegisteredForUser(ProductViewModel product, string unitId = "", long stocklocationId = 0) 15 { 16 if (!Dynamicweb.Security.UserManagement.User.IsExtranetUserLoggedIn()) return false; 17 18 Product productObject = Services.Products.GetProductById(product.Id, product.VariantId, product.LanguageId); 19 StockLocation stockLocation = Services.StockService.GetStockLocation(stocklocationId); 20 double unitStock = productObject.GetUnitStock(stockLocation, unitId); 21 return unitStock <= 0d && ProductBackInStockNotification.BackInStockNotificationExists(productObject, unitId); 22 } 23 } 24 25 @{ 26 ProductViewModel product = null; 27 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 28 { 29 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 30 } 31 else if (Pageview.Page.Item["DummyProduct"] != null) 32 { 33 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 34 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 35 36 if (productList?.Products is object) 37 { 38 product = productList.Products[0]; 39 } 40 } 41 } 42 43 @if ((product is object)) 44 { 45 bool productInStock = product.StockLevel > 0 || product.NeverOutOfstock; 46 47 //CUSTOM 48 DateTime launchDate = product.ProductFields.ContainsKey("Custom_LaunchDate") ? Converter.ToDateTime(product.ProductFields["Custom_LaunchDate"].Value) : DateTime.MinValue; 49 DateTime currentDate = DateTime.Today; 50 bool beforeLaunchDate = currentDate < launchDate; 51 //--CUSTOM 52 53 if (!productInStock || beforeLaunchDate) //CUSTOM 54 { 55 string notifiedMessage = Model.Item.GetString("NotifiedMessage"); 56 string notifiedMessageId = $"NotifiedMessage_item_{Model.Item.SystemName.ToLower()}_{product.Id}_{product.VariantId.Replace(".", "_")}"; 57 58 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 59 horizontalAlign = horizontalAlign == "center" ? "justify-content-center" : horizontalAlign; 60 horizontalAlign = horizontalAlign == "end" ? "justify-content-end" : horizontalAlign; 61 horizontalAlign = horizontalAlign == "full" ? "" : horizontalAlign; 62 63 string flexFill = Model.Item.GetRawValueString("HorizontalAlignment", "") == "full" ? "flex-fill" : ""; 64 string fullWidth = Model.Item.GetRawValueString("HorizontalAlignment", "") == "full" ? "w-100" : ""; 65 66 bool notificationRegisteredForUser = BackInStockRegisteredForUser(product); 67 68 <div class="d-flex flex-row w-100 @horizontalAlign @fullWidth item_@Model.Item.SystemName.ToLower()"> 69 <div class="@horizontalAlign @fullWidth @(notificationRegisteredForUser ? "" : "d-none")" id="@notifiedMessageId"> 70 @notifiedMessage 71 </div> 72 73 @if (!notificationRegisteredForUser) 74 { 75 76 string notifyIcon = Model.Item.GetString("Icon"); 77 string notifyLabel = !notifyIcon.Contains("_none") ? "<span class=\"icon-2\">" + ReadFile(notifyIcon) + "</span>" : ""; 78 notifyLabel += " " + Translate("Notify me when available"); 79 80 string buttonSize = Model.Item.GetRawValueString("ButtonSize", "regular"); 81 string inputSize = string.Empty; 82 83 switch (buttonSize) 84 { 85 case "small": 86 inputSize = " input-group-sm"; 87 buttonSize = " btn-sm"; 88 break; 89 case "regular": 90 buttonSize = string.Empty; 91 break; 92 case "large": 93 inputSize = " input-group-lg"; 94 buttonSize = " btn-lg"; 95 break; 96 } 97 98 string modalId = $"modal_item_{Model.Item.SystemName.ToLower()}_{product.Id}_{product.VariantId.Replace(".", "_")}"; 99 string formId = $"NotificationForm_item_{Model.Item.SystemName.ToLower()}_{product.Id}_{product.VariantId.Replace(".", "_")}"; 100 string notificationButtonId = $"NotificationButton_item_{Model.Item.SystemName.ToLower()}_{product.Id}_{product.VariantId.Replace(".", "_")}"; 101 string notificationOnClick = !Pageview.IsVisualEditorMode ? $"swift.BackInStockNotification.SubmitNotification('{formId}', '{modalId}', '{notifiedMessageId}', '{notificationButtonId}')" : ""; 102 103 string productPage = $"Default.aspx?ID={GetPageIdByNavigationTag("ProductDetailPage")}"; 104 105 <div class="d-flex @horizontalAlign @fullWidth js-input-group"> 106 <div class="input-group input-primary-button-group flex-nowrap@(inputSize)"> 107 <button type="button" class="btn btn-primary @(buttonSize) @flexFill" id="@notificationButtonId" data-bs-toggle="modal" data-bs-target="#@modalId"> 108 @notifyLabel @*//CUSTOM*@ 109 </button> 110 </div> 111 </div> 112 113 <div class="modal fade" id="@modalId" tabindex="-1" aria-labelledby="label_@modalId" aria-hidden="true"> 114 <div class="modal-dialog modal-dialog-centered"> 115 <div class="modal-content"> 116 <div class="modal-header"> 117 <h5 class="modal-title" id="label_@modalId">@Translate("Back in Stock")</h5> 118 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("Close"))"></button> @*//CUSTOM*@ 119 </div> 120 <div class="modal-body"> 121 <form name="@product.Id" id="@formId" method="post" action="@productPage"> 122 <input type="hidden" name="ProductID" value="@product.Id" /> 123 <input type="hidden" name="VariantID" value="@product.VariantId" /> 124 <input type="hidden" name="LanguageID" value="@product.LanguageId" /> 125 <input type="hidden" name="CartCmd" value="createnotificationforthisproduct" /> 126 <div class="m-2"> 127 @Translate("Send me an email when the product is in stock.") 128 </div> 129 <div class="form-floating m-2"> 130 <input class="form-control" type="text" id="NotificationEmail" value="@(Pageview.User != null ? Pageview.User.Email : "")" name="NotificationEmail" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("Email"))" required="required" aria-required="true" /> @*//CUSTOM*@ 131 <label for="NotificationEmail" class="form-label">@Translate("Email")</label> 132 </div> 133 </form> 134 </div> 135 <div class="modal-footer"> 136 <button type="button" class="btn btn-primary" onclick="@notificationOnClick">@Translate("Submit")</button> 137 </div> 138 </div> 139 </div> 140 </div> 141 } 142 </div> 143 } 144 } 145 else if (Pageview.IsVisualEditorMode) 146 { 147 <div class="alert alert-dark m-0">@Translate("Back in stock notification will be shown here")</div> 148 } 149
![]()
![]()
![]()
![]()
![]()
Error executing template "/Designs/Swift/Paragraph/Swift_Custom_ProductDeliveryInfo.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_fe16e453f9944c27ae3beb8384847c04.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_Custom_ProductDeliveryInfo.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 Dynamicweb.Ecommerce.ProductCatalog 3 @using Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites 4 @using Dynamicweb.Ecommerce.Products.FieldDisplayGroups 5 @using Dynamicweb.Frontend 6 @using Dynamicweb.Core 7 @using System.Drawing 8 @using System.Web 9 @using Dynamicweb.Environment 10 @using System.Globalization 11 12 @* CUSTOM TEMPLATE SUPPORTED BY SWIFT (v1.25.0) *@ 13 14 @{ 15 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false; 16 17 ProductViewModel product = new ProductViewModel(); 18 19 ProductViewModelSettings productSetting = new ProductViewModelSettings 20 { 21 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID, 22 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code, 23 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2, 24 ShopId = Pageview.Area.EcomShopId 25 }; 26 27 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 28 { 29 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 30 } 31 else if (Pageview.Item["DummyProduct"] != null) 32 { 33 34 string dummyProductId = ""; 35 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 36 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 37 if (productList.Products != null) 38 { 39 foreach (var p in productList.Products) { dummyProductId = p.Id; } 40 ProductViewModel dummyProduct = dummyProductId != "" ? ViewModelFactory.CreateView(productSetting, dummyProductId) : new ProductViewModel(); 41 product = dummyProduct; 42 } 43 else 44 { 45 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 46 } 47 } 48 else if (Pageview.Item["DummyProduct"] == null) 49 { 50 product = ViewModelFactory.CreateView(productSetting, Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(1, Dynamicweb.Ecommerce.Common.Context.LanguageID, false).FirstOrDefault().Id); 51 } 52 53 if (product is object) 54 { 55 bool requiresCustomCarrier = product.ProductFields.ContainsKey("Custom_Carrier") ? Converter.ToBoolean(product.ProductFields["Custom_Carrier"].Value) : false; 56 var isNotForSaleText = Pageview.AreaSettings.GetItem("CustomSettings").GetString("Custom_NotForSaleRichTxt"); 57 bool plytixIsNotForSale = product.ProductFields.ContainsKey("Custom_NotForSale") ? Converter.ToBoolean(product.ProductFields["Custom_NotForSale"].Value) : false; 58 59 if (!plytixIsNotForSale) 60 { 61 <div class="order-3 small mb-3 mb-lg-0"> 62 <ul class="list-unstyled"> 63 <li><span class="icon-2">@ReadFile("/Files/Templates/Designs/Swift/Assets/icons/check.svg")</span> <span class="ms-2">@Translate("Free delivery")</span></li> 64 <li><span class="icon-2">@ReadFile("/Files/Templates/Designs/Swift/Assets/icons/check.svg")</span> <span class="ms-2">@Translate("Delivery time: 1-3 business days")</span></li> 65 @if (requiresCustomCarrier) 66 { 67 <li class="mt-3"><span><strong>@Translate("This product requires a carrier")</strong></span></li> 68 } 69 </ul> 70 </div> 71 } 72 else 73 { 74 <div class="order-3 small mb-3 mb-lg-0"> 75 <div>@isNotForSaleText</div> 76 </div> 77 } 78 } 79 } 80
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
Tag os i dit Instagram opslag for at blive vist i vores Eva Solo Community.
Brug et af følgende tags: @evasolo_official, #evasolo, #evatrio eller #evasolofurniture.
Error executing template "Designs/Swift/Paragraph/Swift_RelatedProducts_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_690b0413c1064d38b404af0256a03660.Execute() in E:\Solutions\Eva Solo\Files\Templates\Designs\Swift\Paragraph\Swift_RelatedProducts_Custom.cshtml:line 153 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 System.Linq 5 @using Dynamicweb 6 @using Dynamicweb.Core 7 @using Dynamicweb.Core.Encoders 8 @using Dynamicweb.Environment 9 @using Dynamicweb.Ecommerce.ProductCatalog 10 @using Dynamicweb.Ecommerce.Products 11 @using Dynamicweb.Frontend 12 @using Custom.EvaSolo.Ecommerce.Helpers 13 @using Smartpage.EvaSolo.Clerk.Helpers 14 15 @* CUSTOMIZED STANDARD SWIFT (v1.25.0) TEMPLATE *@ 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 title = Model?.Item?.GetRawValueString("Title", Translate("Products")); 35 string campaignValues = Model.Item.GetRawValueString("CampaignBadges", string.Empty); 36 37 //Styling 38 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "h3"); 39 string subtitleFontSize = Model.Item.GetRawValueString("SubtitleFontSize", "fs-5"); 40 string buttonStyle = Model.Item.GetRawValueString("ButtonStyle", ""); 41 buttonStyle = buttonStyle == "primary" ? " btn-primary" : buttonStyle; 42 buttonStyle = buttonStyle == "secondary" ? " btn-secondary" : buttonStyle; 43 buttonStyle = buttonStyle == "link" ? " btn-link" : buttonStyle; 44 string maxWidth = Model.Item.GetRawValueString("TextReadability", ""); 45 maxWidth = maxWidth == "max-width-on" ? " mw-75ch" : maxWidth; 46 maxWidth = maxWidth == "max-width-off" ? "" : maxWidth; 47 48 string generalTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("GeneralTheme")) ? " theme " + Model.Item.GetRawValueString("GeneralTheme").Replace(" ", "").Trim().ToLower() : ""; 49 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 50 string imageTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; 51 52 //Link generation 53 string pageId = !string.IsNullOrEmpty(Model.Item.GetRawValueString("ProductSliderServicePage")) ? Model.Item.GetLink("ProductSliderServicePage").PageId.ToString() : ""; 54 if (string.IsNullOrEmpty(pageId)) 55 { 56 pageId = GetPageIdByNavigationTag("ProductSliderService").ToString(); 57 } 58 59 string url = "/Default.aspx?ID=" + pageId; 60 if (!url.Contains("LayoutTemplate", StringComparison.OrdinalIgnoreCase)) 61 { 62 url += url.Contains("?") ? "&LayoutTemplate=Designs/Swift/Swift_PageClean.cshtml" : "?LayoutTemplate=Designs/Swift/Swift_PageClean.cshtml"; 63 } 64 65 if (Pageview.IsVisualEditorMode) 66 { 67 url += "&VisualEdit=True"; 68 } 69 70 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsLazyLoadingForProductInfoEnabled"]); 71 if (isLazyLoadingForProductInfoEnabled) 72 { 73 url += "&getproductinfo=true"; 74 } 75 76 //Source type 77 string sourceType = Model.Item.GetRawValueString("RelationType", "trending"); 78 IList<string> relateFromGroupIds = new List<string> { }; 79 IList<string> relateFromProductVariantIds = new List<string> { }; 80 IList<string> relateFromProductIds = new List<string> { }; 81 bool hasVariants = false; 82 83 //--- VARIANTS --- 84 if (sourceType == "variants" && Model.Item.GetValue<ProductListViewModel>("ProductsToRelateToVariants") is ProductListViewModel productsToRelateToVariants) 85 { 86 foreach (var productSelection in productsToRelateToVariants.Products) 87 { 88 relateFromProductIds.Add(productSelection.Id); 89 } 90 } 91 92 //--- MOST SOLD --- 93 if (sourceType == "most-sold" && Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToMostSold") is IList<ProductGroupViewModel> groupsToRelateToMostSold) 94 { 95 foreach (var fromGroup in groupsToRelateToMostSold) 96 { 97 relateFromGroupIds.Add(fromGroup.Id); 98 } 99 } 100 101 //--- TRENDING --- 102 if (sourceType == "trending" && Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToTrending") is IList<ProductGroupViewModel> groupsToRelateToTrending) 103 { 104 foreach (var fromGroup in groupsToRelateToTrending) 105 { 106 relateFromGroupIds.Add(fromGroup.Id); 107 } 108 } 109 110 //--- LATEST --- 111 if (sourceType == "latest" && Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToLatest") is IList<ProductGroupViewModel> groupsToRelateToLatest) 112 { 113 foreach (var fromGroup in groupsToRelateToLatest) 114 { 115 relateFromGroupIds.Add(fromGroup.Id); 116 } 117 } 118 119 //--- FREQUENTLY BOUGHT --- 120 if (sourceType == "frequently" && Model.Item.GetValue<ProductListViewModel>("ProductsToRelateTo") is ProductListViewModel productsToRelateTo) 121 { 122 foreach (var fromProduct in productsToRelateTo.Products) 123 { 124 relateFromProductIds.Add(fromProduct.Id); 125 } 126 } 127 128 //--- SELECTED PRODUCTS --- 129 if ((sourceType == "selected" || sourceType == "frequently") && Model.Item.GetValue<ProductListViewModel>("Products") is ProductListViewModel products) 130 { 131 hasVariants = products.Products.Any(p => !string.IsNullOrEmpty(p.VariantId)); 132 foreach (var productSelection in products.Products) 133 { 134 if (hasVariants) 135 { 136 if (!string.IsNullOrEmpty(productSelection.VariantId)) 137 { 138 relateFromProductVariantIds.Add($"{productSelection.Id} {productSelection.VariantId}"); 139 } 140 else 141 { 142 relateFromProductVariantIds.Add($"{productSelection.Id}"); 143 } 144 } 145 146 relateFromProductIds.Add($"{productSelection.Id}"); 147 } 148 } 149 150 //--- UPSELL PRODUCTS --- 151 if (sourceType == "upsell-products") 152 { 153 string upSell = product.ProductFields.ContainsKey("Custom_UpSell") ? Converter.ToString(product.ProductFields["Custom_UpSell"].Value) : string.Empty; 154 List<Product> upSellProducts = GetActiveUpSellProducts(upSell); 155 relateFromProductIds = upSellProducts != null ? upSellProducts.Select(p => p.Id).ToList() : new List<string>(); 156 } 157 158 //--- RELATED PRODUCTS --- 159 if (sourceType == "related-products" && Model.Item.GetValue<ProductListViewModel>("ProductsToRelateTo2") is ProductListViewModel selectedRelationProduct) 160 { 161 if (selectedRelationProduct.Products.Any()) 162 { 163 product = selectedRelationProduct.Products.FirstOrDefault(); 164 } 165 166 if (product?.RelatedGroups != null) 167 { 168 foreach (var group in product.RelatedGroups) 169 { 170 foreach (var relatedProduct in group.Products) 171 { 172 if (!string.IsNullOrEmpty(relatedProduct.VariantId)) 173 { 174 relateFromProductVariantIds.Add($"{relatedProduct.ProductId} {relatedProduct.VariantId}"); 175 } 176 else 177 { 178 relateFromProductVariantIds.Add($"{relatedProduct.ProductId}"); 179 } 180 } 181 } 182 } 183 } 184 185 //Create group id collection and products id collection strings 186 string groupIds = product is object ? product.PrimaryOrDefaultGroup.Id : string.Join(",", relateFromGroupIds); 187 string productVariantIds = relateFromProductVariantIds.Count > 0 ? string.Join(",", relateFromProductVariantIds) : ""; 188 string productIds = product is object && relateFromProductIds.Count == 0 ? product.Id : string.Join(",", relateFromProductIds); 189 //Set the parameters to the url 190 string linkParameters = ""; 191 linkParameters += sourceType != "related-products" && sourceType != "frequently" && sourceType != "selected" ? "&GroupId=" + groupIds : ""; 192 linkParameters += !string.IsNullOrEmpty(productIds) && sourceType != "most-sold" && sourceType != "trending" && sourceType != "latest" && sourceType != "frequently" && sourceType != "related-products" ? "&MainProductId=" + productIds : ""; 193 linkParameters += !string.IsNullOrEmpty(productVariantIds) && sourceType == "related-products" ? "&ProductVariantId=" + productVariantIds : ""; 194 linkParameters += sourceType == "variants" ? "&IsVariant=true" : ""; 195 linkParameters += sourceType == "latest" ? "&SortBy=Created" : ""; 196 linkParameters += sourceType == "most-sold" ? "&SortBy=OrderCount" : ""; 197 linkParameters += sourceType == "trending" ? "&SortBy=OrderCountGrowth" : ""; 198 linkParameters += !string.IsNullOrEmpty(productIds) && sourceType == "frequently" ? $"&BoughtWithProductIds=[{productIds}]" : ""; 199 var productListPageId = GetPageIdByNavigationTag("Shop"); 200 string link = "/Default.aspx?ID=" + productListPageId + linkParameters; 201 202 // Slider settings (documentation: swiffyslider.com/configuration) 203 string navigationStyle = $"{Model.Item.GetRawValueString("NavigationStyle", "slider-nav-round")}"; 204 string navigationPlacement = $"{Model.Item.GetRawValueString("NavigationPlacement", "slider-nav-on-slides")}"; 205 string indicatorStyle = $"{Model.Item.GetRawValueString("IndicatorStyle", "slider-indicators-hidden")}"; 206 string revealSlides = Model.Item.GetRawValueString("RevealSlides", "no-reveal") == "reveal" ? "slider-item-reveal" : string.Empty; 207 string navigationAlwaysVisible = (Model.Item.GetBoolean("NavigationAlwaysVisible")) ? "slider-nav-visible" : string.Empty; 208 string navigationVisibleOnTouch = (Model.Item.GetBoolean("NavigationVisibleOnTouch")) ? "slider-nav-touch" : string.Empty; 209 string navigationShowScrollbar = (Model.Item.GetBoolean("NavigationShowScrollbar")) ? "slider-nav-scrollbar" : string.Empty; 210 string navigationSmall = (Model.Item.GetBoolean("NavigationSmall")) ? "slider-nav-sm" : string.Empty; 211 string navigationInvertColors = (Model.Item.GetBoolean("NavigationInvertColors")) ? "slider-nav-dark" : string.Empty; 212 string navigationSlideEntirePage = (Model.Item.GetBoolean("NavigationSlideEntirePage")) ? "slider-nav-page" : string.Empty; 213 string navigationNoLoop = (Model.Item.GetBoolean("NavigationNoLoop")) ? "slider-nav-noloop" : string.Empty; 214 string indicatorsOutsideSlider = (Model.Item.GetBoolean("IndicatorsOutsideSlider") && indicatorStyle != string.Empty) ? "slider-indicators-outside" : string.Empty; 215 string indicatorsHighlightActive = (Model.Item.GetBoolean("IndicatorsHighlightActive")) ? "slider-indicators-highlight" : string.Empty; 216 string indicatorsInvertColors = (Model.Item.GetBoolean("IndicatorsInvertedColors")) ? "slider-indicators-dark" : string.Empty; 217 string indicatorsVisibleOnSmallDevices = (Model.Item.GetBoolean("IndicatorsVisibleOnSmallDevices")) ? "slider-indicators-sm" : string.Empty; 218 219 bool productsFound = true; 220 if (sourceType != "clerk" && string.IsNullOrEmpty(groupIds) && string.IsNullOrEmpty(productIds) && string.IsNullOrEmpty(productVariantIds)) //CUSTOM 221 { 222 if (Pageview.IsVisualEditorMode && product != null) //CUSTOM 223 { 224 productIds = product.Id; 225 sourceType = "selected"; 226 } 227 else 228 { 229 productsFound = false; 230 } 231 } 232 else if (sourceType == "upsell-products") 233 { 234 productsFound = relateFromProductIds.Count > 0; 235 } 236 } 237 238 @*//CUSTOM*@ 239 @if (Pageview.IsVisualEditorMode == true && sourceType == "clerk" && PageView.Current().AreaSettings.GetItem("CustomSettings").GetRawValueString("ClerkPublicKey_Custom").IsNullOrEmpty()) 240 { 241 <div class="alert alert-danger" role="alert"> 242 <span>@Translate("Product slider: The Clerk integration requires a public key in the website settings")</span> 243 </div> 244 } 245 @*//--CUSTOM*@ 246 247 @*Container element for the request*@ 248 @if (productsFound) 249 { 250 <form method="post" action="@url" id="RelatedProductsForm_@Model.ID" data-response-target-element="RelatedProducts_@Model.ID" data-preloader="inline" data-update-url="false" class="item_@Model.Item.SystemName.ToLower()"> 251 <input type="hidden" name="ModelID" value="@Model.ID"> 252 <input type="hidden" name="SourceType" value="@sourceType"> 253 254 @*--- SLIDER SETTINGS ---*@ 255 <input type="hidden" name="NavigationStyle" value="@navigationStyle"> 256 <input type="hidden" name="NavigationPlacement" value="@navigationPlacement"> 257 <input type="hidden" name="IndicatorStyle" value="@indicatorStyle"> 258 <input type="hidden" name="RevealSlides" value="@revealSlides"> 259 <input type="hidden" name="NavigationAlwaysVisible" value="@(navigationAlwaysVisible)"> 260 <input type="hidden" name="NavigationVisibleOnTouch" value="@(navigationVisibleOnTouch)"> 261 <input type="hidden" name="NavigationShowScrollbar" value="@(navigationShowScrollbar)"> 262 <input type="hidden" name="NavigationSmall" value="@(navigationSmall)"> 263 <input type="hidden" name="NavigationInvertColors" value="@(navigationInvertColors)"> 264 <input type="hidden" name="NavigationNoLoop" value="@(navigationNoLoop)"> 265 <input type="hidden" name="NavigationSlideEntirePage" value="@(navigationSlideEntirePage)"> 266 <input type="hidden" name="IndicatorsOutsideSlider" value="@(indicatorsOutsideSlider)"> 267 <input type="hidden" name="IndicatorsHighlightActive" value="@(indicatorsHighlightActive)"> 268 <input type="hidden" name="IndicatorsInvertColors" value="@(indicatorsInvertColors)"> 269 <input type="hidden" name="IndicatorsVisibleOnSmallDevices" value="@(indicatorsVisibleOnSmallDevices)"> 270 271 @*--- VARIANTS ---*@ 272 @if (sourceType == "variants") 273 { 274 <input type="hidden" name="isVariant" value="true"> 275 <input type="hidden" name="MainProductID" id="MainProductID_@Model.ID" value="@productIds"> 276 } 277 278 @*--- MOST SOLD ---*@ 279 @if (sourceType == "most-sold") 280 { 281 <input type="hidden" name="SortBy" value="OrderCount"> 282 if (groupIds != "") 283 { 284 <input type="hidden" name="GroupId" value="@groupIds"> 285 } 286 } 287 288 @*--- TRENDING ---*@ 289 @if (sourceType == "trending") 290 { 291 <input type="hidden" name="SortBy" value="OrderCountGrowth"> 292 if (groupIds != "") 293 { 294 <input type="hidden" name="GroupId" value="@groupIds"> 295 } 296 } 297 298 @*--- FREQUENTLY BOUGHT ---*@ 299 @if (sourceType == "frequently" && !string.IsNullOrEmpty(productIds)) 300 { 301 <input type="hidden" name="BoughtWithProductIds" value="[@productIds]"> 302 } 303 @if (sourceType != "frequently" && hasVariants) 304 { 305 <input type="hidden" name="ProductVariantId" value="@productVariantIds"> 306 } 307 308 @*--- LATEST ---*@ 309 @if (sourceType == "latest") 310 { 311 <input type="hidden" name="SortBy" value="Created"> 312 <input type="hidden" name="GroupId" value="@groupIds"> 313 } 314 315 @*--- SELECTED PRODUCTS ---*@ 316 @if (sourceType == "selected" && !string.IsNullOrEmpty(productIds) && !hasVariants) 317 { 318 <input type="hidden" name="MainProductId" id="MainProductID_@Model.ID" value="@productIds"> 319 } 320 @if (sourceType == "selected" && hasVariants) 321 { 322 <input type="hidden" name="ProductVariantId" value="@productVariantIds"> 323 } 324 325 @*--- UPSELL PRODUCTS ---*@ 326 @if (sourceType == "upsell-products" && !string.IsNullOrEmpty(productIds) && !hasVariants) 327 { 328 <input type="hidden" name="MainProductId" id="MainProductID_@Model.ID" value="@productIds"> 329 } 330 @if (sourceType == "upsell-products" && hasVariants) 331 { 332 <input type="hidden" name="ProductVariantId" value="@productVariantIds"> 333 } 334 335 @*--- RELATED PRODUCTS ---*@ 336 @if (sourceType == "related-products") 337 { 338 <input type="hidden" name="ProductVariantId" id="MainProductID_@Model.ID" value="@productVariantIds"> 339 } 340 341 @*//CUSTOM*@ 342 @*--- CLERK ---*@ 343 @if (sourceType == "clerk") 344 { 345 // Doc.: https://docs.clerk.io/reference/recommendations-popular 346 347 var clerkEndPoint = Model.Item.GetString("ClerkEndpoint"); 348 var clerkKeywords = Model.Item.GetString("ClerkKeywords"); 349 var clerkQuery = new List<string>(); 350 var clerkFilter = new List<string>(); 351 352 if (!string.IsNullOrEmpty(clerkKeywords)) 353 { 354 switch (clerkEndPoint) 355 { 356 case "recommendations/keywords": 357 clerkQuery.Add("keywords=['" + clerkKeywords + "']"); 358 break; 359 } 360 } 361 362 if (product != null && !string.IsNullOrEmpty(product.Id)) 363 { 364 switch (clerkEndPoint) 365 { 366 case "recommendations/bundle": 367 clerkQuery.Add("product=" + product.Id); 368 break; 369 370 case "recommendations/complementary": 371 case "recommendations/substituting": 372 case "recommendations/most_sold_with": 373 clerkQuery.Add("products=[" + product.Id + "]"); // NOTE: Clerk format id as integer (Data Sync product feed is string) 374 break; 375 } 376 } 377 378 IList<ProductGroupViewModel> clerkGroupsToRelateTo = Model.Item.GetValue<IList<ProductGroupViewModel>>("ClerkGroupsToRelateTo"); 379 switch (clerkEndPoint) 380 { 381 case "recommendations/category/popular": 382 case "recommendations/category/trending": 383 case "recommendations/category/new": 384 if (clerkGroupsToRelateTo != null && clerkGroupsToRelateTo.Any()) 385 { 386 clerkQuery.Add("category=" + clerkGroupsToRelateTo.First().Id); 387 } 388 else if (Context.Current.Request.HasRequest("GroupID")) 389 { 390 clerkQuery.Add("category=" + Context.Current.Request.GetString("GroupID")); 391 } 392 393 break; 394 395 default: 396 if (clerkGroupsToRelateTo != null && clerkGroupsToRelateTo.Any()) 397 { 398 clerkFilter.Add("categories in ['" + string.Join("','", clerkGroupsToRelateTo.Select(i => i.Id)) + "']"); 399 } 400 401 break; 402 } 403 404 switch (clerkEndPoint) 405 { 406 case "recommendations/page/substituting": 407 case "recommendations/page/related_products": 408 case "recommendations/page/related_categories": 409 clerkQuery.Add("page=" + Model.PageID); 410 break; 411 } 412 413 IList<ItemViewModel> clerkFilters = Model.Item.GetItems("ClerkFilters"); 414 if (clerkFilters != null) 415 { 416 foreach (var i in clerkFilters) 417 { 418 switch (i.GetString("OperatorType")) 419 { 420 case "=": 421 case "!=": 422 case "contains": 423 case "contains not": 424 clerkFilter.Add($"{i.GetString("Field")} {i.GetString("OperatorType")} '{i.GetString("Value")}'"); 425 break; 426 427 case "in": 428 case "not in": 429 clerkFilter.Add($"{i.GetString("Field")} {i.GetString("OperatorType")} ['{i.GetString("Value").Replace(",", "','")}']"); 430 break; 431 432 case "= true": 433 case "= false": 434 clerkFilter.Add($"{i.GetString("Field")} {i.GetString("OperatorType")}"); 435 break; 436 437 default: 438 clerkFilter.Add($"{i.GetString("Field")} {i.GetString("OperatorType")} {i.GetString("Value")}"); 439 break; 440 } 441 } 442 } 443 444 <input type="hidden" name="ClerkEndpoint" value="@HtmlEncoder.HtmlAttributeEncode(clerkEndPoint)" /> 445 <input type="hidden" name="ClerkQuery" value="@HtmlEncoder.HtmlAttributeEncode(string.Join("&", clerkQuery))" /> 446 <input type="hidden" name="ClerkFilter" value="@HtmlEncoder.HtmlAttributeEncode(string.Join(" and ", clerkFilter))" /> 447 <input type="hidden" name="ClerkLabels" value="@HtmlEncoder.HtmlAttributeEncode(Model.Item.GetString("ClerkLabels"))" /> 448 <input type="hidden" name="ClerkLogArea" value="@HtmlEncoder.HtmlAttributeEncode($"{Pageview.Area.Name} (ID: {Pageview.Area.ID})")" /> 449 <input type="hidden" name="ClerkLogPage" value="@HtmlEncoder.HtmlAttributeEncode($"{Pageview.Page.MenuText} (ID: {Pageview.Page.ID})")" /> 450 <input type="hidden" name="ClerkLogParagraph" value="@HtmlEncoder.HtmlAttributeEncode($"{Pageview.CurrentParagraph.Header} (ID: {Pageview.CurrentParagraph.ID})")" /> 451 } 452 @*//--CUSTOM*@ 453 454 @* General parameters *@ 455 <input type="hidden" name="Link" value="@link"> 456 <input type="hidden" name="HideTitle" value="@Model.Item.GetString("HideTitle")"> 457 <input type="hidden" name="HidePrices" value="@Model.Item.GetString("CustomHidePrices")" /> @*//CUSTOM*@ 458 459 @if (Model.Item.GetInt32("ProductsCount") != 0) 460 { 461 <input type="hidden" name="PageSize" value="@Model.Item.GetInt32("ProductsCount")"> 462 } 463 <input type="hidden" name="HeadingTitle" id="RelatedProductsTitle_@Model.ID" value="@title"> 464 @if (!string.IsNullOrEmpty(Model.Item.GetString("Subtitle"))) 465 { 466 <input type="hidden" name="Subtitle" value="@Model.Item.GetString("Subtitle")"> 467 } 468 @if (!string.IsNullOrEmpty(Model.Item.GetString("LinkText"))) 469 { 470 <input type="hidden" name="LinkText" value="@Model.Item.GetString("LinkText")"> 471 } 472 @if (!string.IsNullOrEmpty(Model.Item.GetString("ImageAspectRatio"))) 473 { 474 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 475 ratio = ratio != "0" ? ratio : ""; 476 <input type="hidden" name="ImageAspectRatio" value="@ratio"> 477 } 478 @if (!string.IsNullOrEmpty(Model.Item.GetString("Layout"))) 479 { 480 <input type="hidden" name="Layout" value="@Model.Item.GetRawValueString("Layout")"> 481 } 482 @if (titleFontSize != "") 483 { 484 <input type="hidden" name="TitleFontSize" value="@titleFontSize"> 485 } 486 @if (subtitleFontSize != "") 487 { 488 <input type="hidden" name="SubtitleFontSize" value="@subtitleFontSize"> 489 } 490 @if (buttonStyle != "") 491 { 492 <input type="hidden" name="ButtonStyle" value="@buttonStyle"> 493 } 494 @if (generalTheme != "") 495 { 496 <input type="hidden" name="GeneralTheme" value="@generalTheme"> 497 } 498 @if (theme != "") 499 { 500 <input type="hidden" name="Theme" value="@theme"> 501 } 502 @if (imageTheme != "") 503 { 504 <input type="hidden" name="ImageTheme" value="@imageTheme"> 505 } 506 @if (!string.IsNullOrEmpty(Model.Item.GetString("ContentPadding"))) 507 { 508 string contentPadding = Model.Item.GetRawValueString("ContentPadding"); 509 <input type="hidden" name="ContentPadding" value="@contentPadding"> 510 } 511 <input type="hidden" name="TextReadability" value="@maxWidth"> 512 <input type="hidden" name="ParentColumnSize" id="ParentColumnSize_@Model.ID" value="12"> 513 514 <input type="hidden" name="SaleBadgeType" value="@Model.Item.GetRawValue("SaleBadgeType")"> 515 <input type="hidden" name="SaleBadgeCssClassName" value="@Model.Item.GetRawValue("SaleBadgeDesign")"> 516 <input type="hidden" name="NewBadgeCssClassName" value="@Model.Item.GetRawValue("NewBadgeDesign")"> 517 <input type="hidden" name="NewPublicationDays" value="@Model.Item.GetInt32("NewPublicationDays")"> 518 519 @if (campaignValues != "") 520 { 521 <input type="hidden" name="CampaignBadgesValues" value="@campaignValues"> 522 } 523 </form> 524 525 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/swiffy-slider.js"></script> 526 <script> 527 window.addEventListener("load", () => { 528 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/css/swiffy-slider.min.css', 'css'); 529 }); 530 </script> 531 532 if (Pageview.IsVisualEditorMode) 533 { 534 <div class="alert alert-info" role="alert"> 535 <span>@Translate("Product slider: Edit this column to configure")</span> 536 </div> 537 } 538 539 if (sourceType == "upsell-products") 540 { 541 <div class="w-100 h-100"> 542 <div id="@Model.ID" class="user-select-none" style="scroll-margin-top:var(--header-height,150px)"></div> 543 <div id="RelatedProducts_@Model.ID"></div> 544 </div> 545 } 546 else if (sourceType != "related-products") 547 { 548 <div class="w-100 h-100"> 549 <div id="@Model.ID" class="user-select-none" style="scroll-margin-top:var(--header-height,150px)"></div> 550 <div id="RelatedProducts_@Model.ID" class="h-100 swift_product_slider_container" data-product-count="@Model.Item.GetInt32("ProductsCount")"></div> @*//CUSTOM*@ 551 </div> 552 } 553 else if (product?.RelatedGroups != null) 554 { 555 @* Create multiple slider containers, if type is Product relation *@ 556 <div class="grid w-100 h-100@(generalTheme)" style="grid-row-gap: 4rem"> 557 <div id="@Model.ID" class="user-select-none" style="scroll-margin-top:var(--header-height,150px)"></div> 558 @foreach (var group in product.RelatedGroups) 559 { 560 <div id="RelatedProducts_@(Model.ID)_@group.Id" class="g-col-12 h-100 swift_product_slider_container"></div> 561 } 562 </div> 563 } 564 565 @* Initialize *@ 566 if (sourceType != "related-products") 567 { 568 <script type="module"> 569 if (document.querySelector("#RelatedProducts_@Model.ID").closest("[data-col-size]")) { 570 document.querySelector("#ParentColumnSize_@Model.ID").value = document.querySelector("#RelatedProducts_@Model.ID").closest("[data-col-size]").getAttribute("data-col-size"); 571 } 572 swift.PageUpdater.Update(document.querySelector("#RelatedProductsForm_@Model.ID")).then(function () { 573 setTimeout(function () { 574 const isVisualEditor = @(Converter.ToString(Pageview.IsVisualEditorMode).ToLowerInvariant()); 575 const productSliderContainer = document.querySelector(".swift_product_slider_container"); 576 577 if (productSliderContainer && productSliderContainer.innerHTML !== "") { 578 productSliderContainer.classList.remove("d-none"); 579 } else if (!isVisualEditor && productSliderContainer) { 580 productSliderContainer.closest("[class*=column]").classList.add("d-none"); 581 } 582 custom.UpsellProducts.bindEvents(); 583 }, 150); 584 }); 585 </script> 586 } 587 else if (product?.RelatedGroups != null) 588 { 589 @* Create multiple sliders, if type is Product relation *@ 590 foreach (var group in product.RelatedGroups) 591 { 592 IList<string> fromProductIds = new List<string> { }; 593 594 foreach (var relatedProduct in group.Products) 595 { 596 if (!string.IsNullOrEmpty(relatedProduct.VariantId)) 597 { 598 fromProductIds.Add($"{relatedProduct.ProductId} {relatedProduct.VariantId}"); 599 } 600 else 601 { 602 fromProductIds.Add($"{relatedProduct.ProductId}"); 603 } 604 } 605 606 <script type="module"> 607 document.querySelector("#ParentColumnSize_@Model.ID").value = document.querySelector("#RelatedProducts_@(Model.ID)_@group.Id").closest("[data-col-size]").getAttribute("data-col-size"); 608 document.querySelector("#MainProductID_@Model.ID").value = "@string.Join(",", fromProductIds)"; 609 document.querySelector("#RelatedProductsTitle_@Model.ID").value = "@group.Name"; 610 document.querySelector("#RelatedProductsForm_@Model.ID").setAttribute("data-response-target-element", "RelatedProducts_@(Model.ID)_@group.Id"); 611 612 swift.PageUpdater.Update(document.querySelector("#RelatedProductsForm_@Model.ID")); 613 </script> 614 } 615 } 616 } 617 618 @functions { 619 List<Product> GetActiveUpSellProducts(string productNumbers) 620 { 621 if (!string.IsNullOrEmpty(productNumbers)) 622 { 623 List<Product> upSellProducts = Product.GetProductsByProductIDs(productNumbers.Split(',').Select(x => x.Trim()).ToArray(), true).ToList(); 624 625 if (upSellProducts != null && upSellProducts.Any()) 626 { 627 List<Product> activeUpSellProducts = new List<Product>(); 628 629 foreach (Product upSellProduct in upSellProducts) 630 { 631 if (upSellProduct.Active && GetStock(upSellProduct) > 0 && !upSellProduct.InActive()) 632 { 633 activeUpSellProducts.Add(upSellProduct); 634 } 635 } 636 637 return activeUpSellProducts; 638 } 639 } 640 641 return null; 642 } 643 644 double GetStock(Product product) 645 { 646 double productStock = product.Stock; 647 648 if (Converter.ToBoolean(Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(product, "Custom_FurnitureWarehouse"))) 649 { 650 productStock = Converter.ToDouble(Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(product, "Custom_AlternativeStock")); 651 } 652 653 return productStock; 654 } 655 } 656