Error executing template "Designs/Swift/Paragraph/Swift_ProductGroupGrid.cshtml"
System.ArgumentException: An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at Dynamicweb.Ecommerce.Products.GroupRelation.GetGroupRelationsByChildId(String childId)
at Dynamicweb.Ecommerce.Products.Group.get_IsTopGroup()
at System.Linq.Enumerable.WhereListIterator`1.MoveNext()
at Dynamicweb.Ecommerce.Products.GroupService.GetToplevelGroups()
at Dynamicweb.Ecommerce.Products.GroupService.GetToplevelGroups(String languageId)
at CompiledRazorTemplates.Dynamic.RazorEngine_3c5178e0176c458fb4ecb2efc7f32e5e.GetGroups(String type) in D:\dynamicweb.net\Solutions\Dynamicweb\HCTswift.staging.dynamicweb-cms.com\files\Templates\Designs\Swift\Paragraph\Swift_ProductGroupGrid.cshtml:line 57
at CompiledRazorTemplates.Dynamic.RazorEngine_3c5178e0176c458fb4ecb2efc7f32e5e.Execute() in D:\dynamicweb.net\Solutions\Dynamicweb\HCTswift.staging.dynamicweb-cms.com\files\Templates\Designs\Swift\Paragraph\Swift_ProductGroupGrid.cshtml:line 148
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
3 @using Dynamicweb.Ecommerce.ProductCatalog
4 @using Dynamicweb.Frontend
5
6 @functions
7 {
8 private IList<ProductGroupViewModel> GetGroups(string type)
9 {
10 IList<ProductGroupViewModel> groupList = new List<ProductGroupViewModel> { };
11
12 if (type == "subgroups")
13 {
14 IList<ProductGroupViewModel> groups = Model.Item.GetValue<IList<ProductGroupViewModel>>("Subgroups");
15 if (groups != null)
16 {
17 foreach (var group in groups)
18 {
19 var subGroups = Services.ProductGroups.GetSubgroups(Services.ProductGroups.GetGroup(group.Id));
20
21 foreach (var subGroup in subGroups)
22 {
23 var subGroupViewModel = ViewModelFactory.CreateView(new ProductGroupViewModelSettings(), subGroup);
24 groupList.Add(subGroupViewModel);
25 }
26 }
27 }
28 }
29
30 if (type == "selected-groups")
31 {
32 IList<ProductGroupViewModel> groups = Model.Item.GetValue<IList<ProductGroupViewModel>>("SelectedGroups");
33 if (groups != null)
34 {
35 foreach (var group in groups)
36 {
37 groupList.Add(group);
38 }
39 }
40 }
41
42 if (type == "subgroups-current")
43 {
44 var currentGroupId = Dynamicweb.Context.Current.Request.QueryString.Get("GroupID");
45 var currentGroup = currentGroupId != null ? Services.ProductGroups.GetGroup(currentGroupId) : null;
46 var groups = currentGroup != null ? Services.ProductGroups.GetSubgroups(currentGroup) : null;
47 if (groups != null)
48 {
49 foreach (var group in groups)
50 {
51 var groupViewModel = ViewModelFactory.CreateView(new ProductGroupViewModelSettings(), group);
52 groupList.Add(groupViewModel);
53 }
54 } else {
55
56 var langID = Pageview.Area.EcomLanguageId;
57 groups = Dynamicweb.Ecommerce.Services.ProductGroups.GetToplevelGroups(langID);
58
59 foreach (var group in groups)
60 {
61 if (group.ShopId ==Pageview.Area.EcomShopId){
62 var groupViewModel = Dynamicweb.Ecommerce.ProductCatalog.ViewModelFactory.CreateView(new ProductGroupViewModelSettings(), group);
63 groupList.Add(groupViewModel);
64 }
65 }
66 }
67 }
68
69 return groupList;
70 }
71
72 private LinkViewModel GetLink(ProductGroupViewModel group)
73 {
74 var link = new LinkViewModel()
75 {
76 Url = $"/Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={group.Id.Trim()}",
77 IsExternal = false
78 };
79
80 return link;
81 }
82
83 private string GetGroupImageMarkup(ProductGroupViewModel group, string imageShape)
84 {
85 string groupImage = Services.ProductGroups.GetGroup(group.Id)?.LargeImage;
86 if (groupImage.Contains(".svg")){
87 groupImage = "/Files" + groupImage;
88 } else {
89 if (groupImage.StartsWith("/") && !groupImage.StartsWith("/Files", StringComparison.OrdinalIgnoreCase))
90 {
91 groupImage = $"/Files{groupImage}";
92 }
93
94 groupImage = Dynamicweb.Context.Current.Server.UrlEncode(groupImage);
95 groupImage = !string.IsNullOrEmpty(groupImage) ? $"/Admin/Public/GetImage.ashx?width=640&crop=0&image={groupImage}&format=webp" : string.Empty;
96 }
97
98
99 //string groupImageEncoded = Dynamicweb.Context.Current.Server.UrlEncode(groupImage);
100 string groupImagePath = groupImage;
101 string groupImageMarkup = $"<img class=\"{imageShape}\" src=\"{groupImagePath}\" alt=\"{group.Name}\" style=\"object-fit:cover\">";
102
103 return !string.IsNullOrEmpty(groupImage) ? groupImageMarkup : string.Empty;
104 }
105
106 private string GetImageShape()
107 {
108 string imageShape = Model.Item.GetRawValueString("ImageShape", "boxed");
109 switch (imageShape)
110 {
111 case "boxed":
112 imageShape = "rounded-0";
113 break;
114 case "rounded":
115 imageShape = "rounded-3";
116 break;
117 case "circle":
118 imageShape = "rounded-pill";
119 break;
120 }
121 return imageShape;
122 }
123
124 private string GetButtonAlignment()
125 {
126 string buttonAlignment = Model.Item.GetRawValueString("ButtonAlignment", "align-center-center");
127
128 switch (buttonAlignment)
129 {
130 case "align-center-center":
131 return "text-center justify-content-center align-items-center";
132 case "align-bottom-start":
133 return "text-start justify-content-start align-items-end";
134 case "align-bottom-center":
135 return "text-center justify-content-center align-items-end";
136 case "align-bottom-center-text-center":
137 return "text-center justify-content-center align-items-end";
138 case "align-bottom-end":
139 return "text-end justify-content-end align-items-end";
140 default:
141 return "align-center-center";
142 }
143 }
144 }
145
146 @{
147 string groupType = Model.Item.GetRawValueString("GroupType", "subgroups");
148 var groups = GetGroups(groupType);
149
150 bool hideHeaders = (Model.Item?.GetBoolean("HideHeaders") ?? false);
151 string title = Model.Item?.GetString("Title", string.Empty);
152 string subtitle = Model.Item?.GetString("Subtitle", string.Empty);
153 bool groupsExist = groups is object && groups.Count != 0;
154
155 // Grid layout
156 string gridSize = Model.Item.GetRawValueString("GridSize", "3");
157 string gridSizeMobile = Model.Item.GetRawValueString("GridSizeMobile", "1");
158 gridSize = $"grid-{gridSizeMobile} grid-sm-3 grid-lg-{gridSize}";
159
160 string itemsGap = $"gap-{Model.Item.GetRawValueString("GridItemsGap", "3")}";
161 string layout = Model.Item.GetRawValueString("Layout", "overlay");
162
163 // Styling
164 string paragraphTheme = Model.Item.GetRawValueString("ParagraphTheme");
165 paragraphTheme = !string.IsNullOrWhiteSpace(paragraphTheme) ? $"theme {paragraphTheme.Replace(" ", "").Trim().ToLower()} p-3" : string.Empty;
166
167 string groupTheme = Model.Item.GetRawValueString("GroupTheme");
168 groupTheme = !string.IsNullOrWhiteSpace(groupTheme) ? $"theme {groupTheme.Replace(" ", "").Trim().ToLower()}" : "theme";
169 string groupThemePadding = groupTheme == "theme" ? "pt-2" : "p-2";
170
171 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", string.Empty);
172 ratio = ratio != "0" ? ratio : string.Empty;
173 string ratioCssClass = ratio != string.Empty ? "ratio" : string.Empty;
174 string ratioVariable = ratio != string.Empty ? "--bs-aspect-ratio: " + ratio : string.Empty;
175
176 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "h3");
177 string subtitleFontSize = Model.Item.GetRawValueString("SubtitleFontSize", "fs-5");
178 string maxWidth = Model.Item.GetRawValueString("TextReadability", string.Empty);
179 maxWidth = maxWidth == "max-width-on" ? "mw-75ch" : string.Empty;
180
181 string buttonAlignment = GetButtonAlignment();
182
183 string buttonStyle = Model.Item.GetRawValueString("ButtonStyle", "primary");
184 buttonStyle = buttonStyle == "primary" ? "btn-primary" : buttonStyle;
185 buttonStyle = buttonStyle == "secondary" ? "btn-secondary" : buttonStyle;
186 buttonStyle = buttonStyle == "link" ? "btn-link" : buttonStyle;
187
188 string buttonSize = Model.Item.GetRawValueString("ButtonSize", "regular");
189 buttonSize = buttonSize == "small" ? "btn btn-sm" : buttonSize;
190 buttonSize = buttonSize == "regular" ? "btn" : buttonSize;
191 buttonSize = buttonSize == "large" ? "btn btn-lg" : buttonSize;
192
193 string stretchedLink = "stretched-link";
194
195 string imageShape = GetImageShape();
196 string missingImageMarkup = $"<div class=\"bg-opacity-10 {imageShape}\" style=\"background-color:rgba(var(--swift-foreground-color-rgb),var(--bs-bg-opacity));\"></div>";
197 }
198
199 @if (groupsExist)
200 {
201 <div class="grid gap-0 @(paragraphTheme) item_@(Model.Item.SystemName.ToLower())">
202 <div id="@Model.ID" class="user-select-none" style="scroll-margin-top:var(--header-height,150px)"></div>
203
204 @if (!hideHeaders)
205 {
206 <div class="g-col-12 pb-2 pb-lg-4">
207 <div class="mb-0-last-child">
208 @if (!string.IsNullOrEmpty(title))
209 {
210 <h2 class="mt-0 @titleFontSize @maxWidth">@title</h2>
211 }
212
213 @if (!string.IsNullOrEmpty(subtitle))
214 {
215 <p class="@subtitleFontSize @maxWidth">@subtitle</p>
216 }
217 </div>
218 </div>
219 }
220
221 <div class="g-col-12 grid @gridSize @itemsGap">
222 @foreach (var group in groups)
223 {
224 string groupImageMarkup = GetGroupImageMarkup(group, imageShape) ?? missingImageMarkup;
225 bool groupImage = !string.IsNullOrEmpty(groupImageMarkup);
226
227 <div class="d-flex flex-column h-100">
228 @{
229 switch (layout)
230 {
231 case "overlay":
232 <div class="card rounded-0 border-0 @(groupTheme) @(ratioCssClass)" style="@ratioVariable">
233
234 @(groupImage ? groupImageMarkup : missingImageMarkup)
235
236 <div class="d-grid p-3 @buttonAlignment">
237 @if (GetLink(group) is object)
238 {
239 bool openLinksInNewTab = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && GetLink(group).IsExternal;
240 string target = openLinksInNewTab ? "target=\"_blank\"" : string.Empty;
241 string rel = openLinksInNewTab ? "rel=\"noopener\"" : string.Empty;
242
243 <a href="@GetLink(group)" class="@(buttonSize) @buttonStyle @(stretchedLink)" @target @rel>@group.Name</a>
244 }
245 </div>
246 </div>
247 break;
248 case "below":
249 <div class="card rounded-0 border-0 @(groupTheme)">
250
251 <div class="@(ratioCssClass)" style="@ratioVariable">
252
253 @(groupImage ? groupImageMarkup : missingImageMarkup)
254
255 </div>
256
257 <div class="@(groupImage ? "h-100" : string.Empty) @(groupThemePadding) d-grid @buttonAlignment">
258
259 @if (GetLink(group) is object)
260 {
261 bool openLinksInNewTab = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && GetLink(group).IsExternal;
262 string target = openLinksInNewTab ? "target=\"_blank\"" : string.Empty;
263 string rel = openLinksInNewTab ? "rel=\"noopener\"" : string.Empty;
264
265 <a href="@GetLink(group)" class="@(buttonSize) @buttonStyle @(stretchedLink)" @target @rel>@group.Name</a>
266 }
267 </div>
268 </div>
269 break;
270 }
271 }
272 </div>
273 }
274 </div>
275 </div>
276 }
277 else if (Pageview.IsVisualEditorMode)
278 {
279 <div class="alert alert-dark" role="alert">
280 <span>@Translate("Group grid"): @Translate("Edit this column to configure")</span>
281 </div>
282 }
283