Error executing template "Designs/Swift/Navigation/OffCanvasNavigation_DW10.cshtml"
System.ArgumentException: An item with the same key has already been added. Key: GRP1531322_STRUCTURE
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at Dynamicweb.Ecommerce.Shops.Shop.GetTopLevelGroups(String languageId)
at Dynamicweb.Ecommerce.Frontend.Navigation.GroupNavigationTreeNodeProvider.GetGroupsBySettings(PageNavigationSettings ecomSettings)
at Dynamicweb.Ecommerce.Frontend.Navigation.GroupNavigationTreeNodeProvider.GetNodes(NavigationContext context, NavigationSettings settings, NavigationTreeNode parent)
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
at CompiledRazorTemplates.Dynamic.RazorEngine_c24e5ebd16f342f69e69d390d50d942b.ExecuteAsync()
at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.DynamicWrapperService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String name, 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 RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String templateSource, String name, Type modelType, Object model, DynamicViewBag viewBag)
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.Navigation.NavigationTreeViewModel>
2 @using System.IO
3 @using System.Text.RegularExpressions
4 @using Dynamicweb
5 @using Dynamicweb.Ecommerce.ProductCatalog
6
7 @functions {
8
9 public string GetGroupFieldValue(string systemName, IList<FieldValueViewModel> groupFields)
10 {
11 string groupField = string.Empty;
12
13 if (groupFields is object)
14 {
15
16 groupField = groupFields != null ? groupFields.FirstOrDefault(field => field?.SystemName == systemName)?.Value?.ToString() : string.Empty;
17 }
18
19 return groupField;
20 }
21
22 public string GetImagePathSanitized(string imagePath) {
23
24 if (!imagePath.StartsWith("/Files", StringComparison.OrdinalIgnoreCase))
25 {
26 if (!imagePath.StartsWith("Files/", StringComparison.OrdinalIgnoreCase))
27 {
28
29 imagePath = $"/Files/Images/{imagePath}";
30 }
31 }
32
33 return imagePath;
34 }
35 }
36
37 @{
38 string navType = Model?.Parameters["NavType"] != null ? Model.Parameters["NavType"].ToString() : "first-nav";
39 string menuId = Model.Parameters.ContainsKey("menu-id") ? $"menu_{Model.Parameters["menu-id"].ToString().ToLower()}" : string.Empty;
40
41 string productGroupImageShape = Model.Parameters.ContainsKey("ProductGroupImageShape") ? Model.Parameters["ProductGroupImageShape"].ToString() : string.Empty;
42 bool showProductGroupImage = Model.Parameters.ContainsKey("ShowProductGroupImage") ? Convert.ToBoolean(Model.Parameters["ShowProductGroupImage"].ToString()) : false;
43 string productGroupPromotionImageTheme = Model.Parameters.ContainsKey("ProductGroupPromotionImageTheme") ? Model.Parameters["ProductGroupPromotionImageTheme"].ToString().ToLower() : string.Empty;
44 bool showProductGroupPromotionImage = Model.Parameters.ContainsKey("ShowProductGroupPromotionImage") ? Convert.ToBoolean(Model.Parameters["ShowProductGroupPromotionImage"].ToString()) : false;
45
46 string ratio = Model.Parameters.ContainsKey("ImageAspectRatio") ? Model.Parameters["ImageAspectRatio"].ToString() : string.Empty;
47 ratio = ratio != "0" ? ratio : string.Empty;
48
49 var parameters = new Dictionary<string, object>();
50 parameters.Add("ProductGroupImageShape", productGroupImageShape);
51 parameters.Add("ShowProductGroupImage", showProductGroupImage);
52 parameters.Add("ProductGroupPromotionImageTheme", productGroupPromotionImageTheme);
53 parameters.Add("ShowProductGroupPromotionImage", showProductGroupPromotionImage);
54 parameters.Add("Ratio", ratio);
55 }
56
57 <div class="nav @navType flex-column h-auto w-100 left-0 top-0 offcanvas-navigation @menuId">
58 @foreach (var node in Model.Nodes)
59 {
60 await NavItemHelper(node);
61 }
62 </div>
63
64 @{
65
66
67 async Task NavItemHelper(Dynamicweb.Frontend.Navigation.NavigationTreeNodeViewModel currentNode)
68 {
69
70 string navType = Model?.Parameters["NavType"] != null ? Model.Parameters["NavType"].ToString() : "first-nav";
71 string menuId = Model.Parameters.ContainsKey("menu-id") ? $"menu_{Model.Parameters["menu-id"].ToString().ToLower()}" : string.Empty;
72
73 string productGroupImageShape = Model.Parameters.ContainsKey("ProductGroupImageShape") ? Model.Parameters["ProductGroupImageShape"].ToString() : string.Empty;
74 bool showProductGroupImage = Model.Parameters.ContainsKey("ShowProductGroupImage") ? Convert.ToBoolean(Model.Parameters["ShowProductGroupImage"].ToString()) : false;
75 string productGroupPromotionImageTheme = Model.Parameters.ContainsKey("ProductGroupPromotionImageTheme") ? Model.Parameters["ProductGroupPromotionImageTheme"].ToString().ToLower() : string.Empty;
76 bool showProductGroupPromotionImage = Model.Parameters.ContainsKey("ShowProductGroupPromotionImage") ? Convert.ToBoolean(Model.Parameters["ShowProductGroupPromotionImage"].ToString()) : false;
77
78 string ratio = Model.Parameters.ContainsKey("ImageAspectRatio") ? Model.Parameters["ImageAspectRatio"].ToString() : string.Empty;
79 ratio = ratio != "0" ? ratio : string.Empty;
80 string arrowLeftIconPath = "/Files/Templates/Designs/Swift/Assets/icons/arrow-left.svg";
81 string arrowRightIconPath = "/Files/Templates/Designs/Swift/Assets/icons/arrow-right.svg";
82
83 <div class="nav @navType flex-column h-auto w-100 left-0 top-0 offcanvas-navigation @menuId">
84 @{
85
86 var page = Dynamicweb.Content.Services.Pages.GetPage(currentNode.PageId);
87 string pageType = page.ItemType;
88
89 var paragraphId = Pageview.CurrentParagraph.ID;
90 string groupId = Dynamicweb.Context.Current.Request["GroupID"] != null ? Dynamicweb.Context.Current.Request["GroupID"].ToString() : string.Empty;
91 string productId = Dynamicweb.Context.Current.Request["ProductID"] != null ? Dynamicweb.Context.Current.Request["ProductID"].ToString() : string.Empty;
92 string variantId = Dynamicweb.Context.Current.Request["VariantID"] != null ? Dynamicweb.Context.Current.Request["VariantID"].ToString() : string.Empty;
93
94 string productGroupImageSize = "24";
95
96 Regex reg = new Regex(@"\(([^\)]+)\)");
97
98 var hasChildren = currentNode.Nodes.Count() > 0;
99 var nodeId = !string.IsNullOrEmpty(currentNode.GroupId) ? currentNode.GroupId : currentNode.PageId.ToString();
100 var inPathChecked = currentNode.InPath ? "checked" : string.Empty;
101 var inPathClass = currentNode.InPath ? " in-path" : string.Empty;
102 var activeClass = currentNode.IsActive ? " active fw-bold" : string.Empty;
103 if (currentNode.ShowInMenu)
104 {
105 <div class="nav-item d-flex align-items-center w-100 py-1">
106 @if (pageType != "Swift_Preferences")
107 {
108 var group = currentNode.GetProductGroup();
109 IList<FieldValueViewModel> groupFields = group.GroupFields != null ? group.GroupFields : null;
110
111 if (currentNode.IsClickable)
112 {
113 <a class="nav-link position-relative d-flex align-items-center gap-2 flex-grow-1@(activeClass)@(inPathClass)" @(currentNode.IsActive ? "aria-current='page'" : string.Empty) href="@currentNode.Link" id="@nodeId">
114 @if (showProductGroupImage && !string.IsNullOrEmpty(currentNode.GroupId) && groupFields != null)
115 {
116 foreach (FieldValueViewModel field in groupFields)
117 {
118 if (field.SystemName == "ProductGroupNavigationImage" && !string.IsNullOrEmpty(field.Value.ToString()))
119 {
120
121 var groupImage = field.Value.ToString();
122
123
124 if (groupImage.EndsWith(".svg", StringComparison.OrdinalIgnoreCase))
125 {
126 <span class="icon-auto @productGroupImageShape" style="height: @(productGroupImageSize)px; width: @(productGroupImageSize)px;">
127 @ReadFile(groupImage)
128 </span>
129 }
130 else
131 {
132
133 var imagePath = "/Admin/Public/GetImage.ashx?Image=" + GetImagePathSanitized(groupImage) + "&Width=" + productGroupImageSize + "&Height=" + productGroupImageSize + "&crop=0";
134 <img loading="lazy" class="@productGroupImageShape" alt="@group.Name" width="@productGroupImageSize" height="@productGroupImageSize" src="@imagePath">
135 }
136 }
137 }
138 }
139 <span class="flex-grow-1">
140 @currentNode.Name
141 </span>
142 </a>
143
144 if (hasChildren)
145 {
146 <label class="nav-link position-relative" role="button" aria-label="Unfold @currentNode.Name" for="nav_@(paragraphId)_@(nodeId)">
147 @{
148
149 <span class="icon-3">@ReadFile(arrowRightIconPath)</span>
150
151 }
152 </label>
153 }
154 }
155 else
156 {
157 <label class="nav-link position-relative d-flex align-items-center gap-2 flex-grow-1@(activeClass)@(inPathClass)" @(currentNode.IsActive ? "aria-current='page'" : "") role="button" aria-label="Unfold @currentNode.Name" for="nav_@(paragraphId)_@(nodeId)">
158 @if (showProductGroupImage && !string.IsNullOrEmpty(currentNode.GroupId) && groupFields != null)
159 {
160 foreach (FieldValueViewModel field in groupFields)
161 {
162 if (field.SystemName == "ProductGroupNavigationImage" && !string.IsNullOrEmpty(field.Value.ToString()))
163 {
164 var groupImage = field.Value.ToString();
165
166 if (groupImage.EndsWith(".svg", StringComparison.OrdinalIgnoreCase))
167 {
168 <span class="icon-auto @productGroupImageShape" style="height: @(productGroupImageSize)px; width: @(productGroupImageSize)px;">
169 @ReadFile(groupImage)
170 </span>
171 }
172 else
173 {
174
175 var imagePath = "/Admin/Public/GetImage.ashx?Image=" + GetImagePathSanitized(groupImage) + "&Width=" + productGroupImageSize + "&Height=" + productGroupImageSize + "&crop=0";
176 <img loading="lazy" class="@productGroupImageShape" alt="@group.Name" width="@productGroupImageSize" height="@productGroupImageSize" src="@imagePath">
177 }
178 }
179 }
180 }
181
182 <span class="flex-grow-1">
183 @currentNode.Name
184 </span>
185
186 @if (hasChildren)
187 {
188 <span class="icon-3">@ReadFile(arrowRightIconPath)</span>
189
190 }
191 </label>
192 }
193
194 if (hasChildren)
195 {
196 <input type="checkbox" class="visually-hidden sub-nav-check" id="nav_@(paragraphId)_@(nodeId)" @inPathChecked>
197 <div class="nav sub-nav position-absolute h-100 opacity-0 pe-none invisible w-100 left-0 top-0">
198 <div class="h-100 w-100 overflow-y-auto overflow-x-hidden">
199 <div class="nav-header position-relative py-1">
200 <label class="nav-link position-relative d-flex align-items-center gap-2 flex-grow-1" role="button" aria-label="Go back to @currentNode.Name" for="nav_@(paragraphId)_@(nodeId)">
201 @{
202 <span class="icon-3">@ReadFile(arrowLeftIconPath)</span>
203 }
204 <span class="flex-grow-1">@currentNode.Name</span>
205 </label>
206 </div>
207
208
209 @foreach (var node in currentNode.Nodes)
210 {
211 await NavItemHelper(node);
212 }
213
214 @if (showProductGroupImage && groupFields != null)
215 {
216 var groupName = group.Name;
217 string ratioCssClass = ratio != string.Empty ? " ratio" : string.Empty;
218 string ratioVariable = ratio != string.Empty ? "style=\"--bs-aspect-ratio: " + ratio + "\"" : string.Empty;
219 string productGroupPromotionImage = string.Empty;
220 string productGroupPromotionImagePath = string.Empty;
221 string productGroupPromotionDescription = string.Empty;
222 string productGroupPromotionLinkLabel = string.Empty;
223 string productGroupPromotionLink = string.Empty;
224 string gridGap = !string.IsNullOrEmpty(productGroupPromotionImageTheme) ? "gap-0" : "gap-3";
225 string themePadding = !string.IsNullOrEmpty(productGroupPromotionImageTheme) ? "p-3" : "p-0";
226
227 foreach (FieldValueViewModel field in groupFields)
228 {
229 if (field.SystemName == "ProductGroupPromotionImage")
230 {
231 productGroupPromotionImage = field.Value != null ? field.Value.ToString() : string.Empty;
232 }
233 if (field.SystemName == "ProductGroupPromotionDescription")
234 {
235 productGroupPromotionDescription = field.Value != null ? field.Value.ToString() : string.Empty;
236 }
237 if (field.SystemName == "ProductGroupPromotionLinkLabel")
238 {
239 productGroupPromotionLinkLabel = field.Value != null ? field.Value.ToString() : string.Empty;
240 }
241 if (field.SystemName == "ProductGroupPromotionLink")
242 {
243 productGroupPromotionLink = field.Value != null ? field.Value.ToString() : string.Empty;
244 }
245 }
246 if (showProductGroupPromotionImage && productGroupPromotionImage != string.Empty)
247 {
248 productGroupPromotionLink = !string.IsNullOrEmpty(productGroupPromotionLink) ? productGroupPromotionLink : currentNode.Link;
249
250 productGroupPromotionImagePath = "/Admin/Public/GetImage.ashx?Width=" + 480 + "&crop=0&image=" + GetImagePathSanitized(productGroupPromotionImage);
251
252 <div class="grid grid-1 mt-3 mx-3 @gridGap@(productGroupPromotionImageTheme)">
253
254 <a href="@productGroupPromotionLink" title="@groupName">
255 <figure class="m-0@(ratioCssClass)" @ratioVariable>
256 <img class="img-fluid" src="@productGroupPromotionImagePath" alt="@groupName" style="object-fit:cover">
257 </figure>
258 </a>
259
260 @if (!string.IsNullOrEmpty(productGroupPromotionDescription) || !string.IsNullOrEmpty(productGroupPromotionLinkLabel))
261 {
262 <div class="grid grid-1 @themePadding ">
263
264 @if (!string.IsNullOrEmpty(productGroupPromotionDescription))
265 {
266 <h6 class="m-0">@productGroupPromotionDescription</h6>
267 }
268 @if (!string.IsNullOrEmpty(productGroupPromotionLinkLabel))
269 {
270 productGroupPromotionLink = !string.IsNullOrEmpty(productGroupPromotionLink) ? productGroupPromotionLink : currentNode.Link;
271
272 <a href="@productGroupPromotionLink" title="@productGroupPromotionLinkLabel" class="btn btn-link text-start border-0 p-0">@productGroupPromotionLinkLabel</a>
273 }
274 </div>
275 }
276 </div>
277 }
278 }
279 </div>
280 </div>
281 }
282 }
283 else
284 {
285 bool countrySelector = page.Item?["CountrySelector"] != null ? Convert.ToBoolean(page.Item["CountrySelector"].ToString()) : false;
286 bool languageSelector = page.Item?["LanguageSelector"] != null ? Convert.ToBoolean(page.Item["LanguageSelector"].ToString()) : false;
287 bool currencySelector = page.Item?["CurrencySelector"] != null ? Convert.ToBoolean(page.Item["CurrencySelector"].ToString()) : false;
288 string name = Translate("Preferences");
289 string icon = string.Empty;
290
291 if (languageSelector)
292 {
293 bool hideIcon = page.Item?["HideIcon"] != null ? Convert.ToBoolean(page.Item["HideIcon"].ToString()) : false;
294
295 if (!hideIcon)
296 {
297 icon = $"/Files/FlagIcons/{Pageview.Area.CultureInfo.Name.ToLower()}.svg";
298 }
299
300 name = reg.Replace(Pageview.Area.CultureInfo.DisplayName, string.Empty);
301 }
302
303 <form action="/Default.aspx?ID=@currentNode.PageId" data-response-target-element="PreferencesModalContent" data-layout-template="Swift_Preferences.cshtml" data-preloader="inline" class="w-100">
304 <input type="hidden" name="Layout" value="modal">
305 <input type="hidden" name="CurrentPageID" value="@Pageview.ID">
306 <input type="hidden" name="GroupID" value="@groupId">
307 <input type="hidden" name="ProductID" value="@productId">
308 <input type="hidden" name="VariantID" value="@variantId">
309 <a href="#" role="button" onclick="swift.PageUpdater.Update(event)" class="nav-link position-relative flex-fill swift_open-preferences-modal @activeClass @inPathClass" @(currentNode.IsActive ? "aria-current='page'" : "") data-bs-toggle="modal" data-bs-target="#PreferencesModal">
310 @if (icon != "")
311 {
312 if (icon.EndsWith(".svg", StringComparison.OrdinalIgnoreCase) && !icon.ToLower().Contains("none"))
313 {
314 string iconPath = Dynamicweb.Context.Current.Server.MapPath(icon);
315
316 <span class="icon-2">@ReadFile(iconPath)</span>
317 }
318 }
319 <span>@name</span>
320 </a>
321 </form>
322 }
323 </div>
324
325 }
326 }
327
328 </div>
329
330
331 }
332 }
333