Error executing template "Designs/Swift/_parsed/Swift_CustomerCenter.parsed.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
at CompiledRazorTemplates.Dynamic.RazorEngine_5067df1f98c44aa0a455026a02156a29.Execute() in C:\inetpub\wwwroot\directions2023_dev\Files\Templates\Designs\Swift\_parsed\Swift_CustomerCenter.parsed.cshtml:line 603
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.PageViewModel>
2 @using System
3 @using Dynamicweb
4 @using Dynamicweb.Environment
5 @using Dynamicweb.Frontend
6
7 @functions {
8 string GetCookieOptInPermission(string category)
9 {
10 bool categoryOrAllGranted = false;
11
12 if (CookieManager.IsCookieManagementActive)
13 {
14 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
15 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
16 categoryOrAllGranted = cookieOptInCategories.Contains(category) || cookieOptInLevel == CookieOptInLevel.All;
17
18 }
19
20 return categoryOrAllGranted ? "granted" : "denied";
21 }
22
23 bool AllowTracking()
24 {
25 bool allowTracking = true;
26 if (CookieManager.IsCookieManagementActive)
27 {
28 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
29 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
30
31 bool consentEither = (cookieOptInCategories.Contains("Statistical") || cookieOptInCategories.Contains("Marketing"));
32 bool consentFunctional = cookieOptInLevel == CookieOptInLevel.Functional;
33 bool consentAtLeastOne = cookieOptInLevel == CookieOptInLevel.All || (consentFunctional && consentEither);
34
35 allowTracking = consentAtLeastOne;
36 }
37 return allowTracking;
38 }
39 }
40
41 @{
42
43 //CUSTOM CODE
44 //handle Maintenance mode
45 var maintenancePage = Model.Area.Item?.GetLink("MaintenancePage") ?? null;
46 bool maintenanceMode = Model.Area.Item.GetBoolean("MaintenanceMode");
47 DateTime maintenanceStartDate = Model.Area.Item.GetDateTime("MaintenanceStartDate");
48 DateTime maintenanceEndDate = Model.Area.Item.GetDateTime("MaintenanceEndDate");
49 DateTime currentDate = System.DateTime.Now;
50 maintenanceMode = maintenanceMode && maintenanceStartDate <= currentDate && maintenanceEndDate >= currentDate;
51 var adminUser = Dynamicweb.Security.UserManagement.User.GetCurrentBackendUser();
52 int currentPage = Dynamicweb.Frontend.PageView.Current().Page.ID;
53
54 if(maintenanceMode && maintenancePage != null && adminUser == null && maintenancePage.PageId != currentPage)
55 {
56 string redirectLink = "/" + maintenancePage;
57 Dynamicweb.Context.Current.Response.Redirect(redirectLink);
58 }
59
60 //CUSTOM CODE
61
62 var cartSummaryPageId = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Model.Area.ID, "CartSummary")?.ID;
63 bool enableMiniCart = Model.Area.Item?.GetBoolean("EnableOffcanvasMiniCart") ?? false;
64 var offcanvasMiniCartBehaviour = Model.Area.Item?.GetRawValueString("OffcanvasMinicartBehaviour", "3") ?? "3";
65 bool miniCartEnabled = cartSummaryPageId != null && enableMiniCart;
66 var brandingPageId = Model.Area.Item?.GetInt32("BrandingPage") ?? 0;
67 var themePageId = Model.Area.Item?.GetInt32("ThemesPage") ?? 0;
68 var cssPageId = Model.Area.Item?.GetInt32("CssPage") ?? 0;
69 var brandingPage = brandingPageId != 0 ? Dynamicweb.Content.Services.Pages?.GetPage(brandingPageId) ?? null : null;
70 var themesParagraphs = themePageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(themePageId) ?? null : null;
71 var cssParagraphs = cssPageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(cssPageId) ?? null : null;
72
73 //CUSTOM CODE
74 var backgroundPageId = Model.Area.Item?.GetInt32("BackgroundsPage") ?? 0;
75 var backgroundParagraphs = backgroundPageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(backgroundPageId) ?? null : null;
76 //CUSTOM CODE
77
78 var otpRedirectPage = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(GetPageIdByNavigationTag("MyAccountDashboardPageInactive"));
79 }
80
81 @if (themesParagraphs != null || brandingPage != null)
82 {
83 string swiftVersion = ReadFile("/Files/Templates/Designs/Swift/swift_version.txt");
84 bool renderAsResponsive = Model.Area.Item.GetString("DeviceRendering", "responsive").Equals("responsive", StringComparison.OrdinalIgnoreCase);
85 bool renderMobile = Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile || Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Tablet;
86 string responsiveClassDesktop = string.Empty;
87 string responsiveClassMobile = string.Empty;
88 if (renderAsResponsive)
89 {
90 responsiveClassDesktop = " d-none d-xl-block";
91 responsiveClassMobile = " d-block d-xl-none";
92 }
93
94 var headerDesktopLink = Model.Area.Item?.GetLink("HeaderDesktop") ?? null;
95 var headerMobileLink = Model.Area.Item?.GetLink("HeaderMobile") ?? null;
96
97 var footerDesktopLink = Model.Area.Item?.GetLink("FooterDesktop") ?? null;
98 var footerMobileLink = Model.Area.Item?.GetLink("FooterMobile") ?? null;
99
100 var disableWideBreakpoints = Model.Area?.Item?.GetRawValueString("DisableWideBreakpoints", "default");
101
102 string customHeaderInclude = !string.IsNullOrEmpty(Model.Area.Item.GetRawValueString("CustomHeaderInclude")) ? Model.Area.Item.GetFile("CustomHeaderInclude").Name : string.Empty;
103
104 var themesParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(themePageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
105 var cssLastModified = brandingPage.Audit.LastModifiedAt > themesParagraphLastChanged.Audit.LastModifiedAt ? brandingPage.Audit.LastModifiedAt : themesParagraphLastChanged.Audit.LastModifiedAt;
106
107 var cssThemeAndBrandingStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css"));
108
109 //CUSTOM CODE
110 //Create a collection with all last modified dates
111 List<DateTime> filesAudit = new List<DateTime>();
112 if(brandingPage != null)
113 {
114 filesAudit.Add(brandingPage.Audit.LastModifiedAt);
115 }
116 if(backgroundParagraphs != null)
117 {
118 var backgroundParagraphLastChanged = backgroundParagraphs.OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
119 filesAudit.Add(backgroundParagraphLastChanged.Audit.LastModifiedAt);
120 }
121
122 cssLastModified = filesAudit.Max();
123
124 if (backgroundPageId != 0)
125 {
126 var backgroundFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_backgrounds_styles_{Model.Area.ID}.css"));
127
128 if(backgroundParagraphs.Any() && !backgroundFileInfo.Exists)
129 {
130
131 var backgroundParagraphLastChanged = backgroundParagraphs.OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
132 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < backgroundParagraphLastChanged.Audit.LastModifiedAt)
133 {
134
135 var backgroundPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(backgroundPageId);
136 backgroundPageview.Redirect = false;
137 backgroundPageview.Output();
138 }
139 }
140 }
141
142 //CUSTOM CODE
143
144 if (cssPageId != 0)
145 {
146 var cssFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_css_styles_{Model.Area.ID}.css"));
147 var cssParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(cssPageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
148 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < cssParagraphLastChanged.Audit.LastModifiedAt)
149 {
150 var cssPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(cssPageId);
151 cssPageview.Redirect = false;
152 cssPageview.Output();
153
154 var backgroundPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(backgroundPageId);
155 backgroundPageview.Redirect = false;
156 backgroundPageview.Output();
157 }
158 }
159
160 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < brandingPage.Audit.LastModifiedAt)
161 {
162 //Branding page has been saved or the file is missing. Rewrite the file to disc.
163 if (brandingPageId > 0)
164 {
165 var brandingPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(brandingPageId);
166 brandingPageview.Redirect = false;
167 brandingPageview.Output();
168 }
169 }
170
171 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < themesParagraphLastChanged.Audit.LastModifiedAt)
172 {
173 //Branding page has been saved or the file is missing. Rewrite the file to disc.
174 if (themePageId > 0)
175 {
176 var themePageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(themePageId);
177 themePageview.Redirect = false;
178 themePageview.Output();
179 }
180 }
181
182 // Schema.org details for PDP
183 bool isProductDetailsPage = Dynamicweb.Context.Current.Request.QueryString.AllKeys.Contains("ProductID");
184 bool isArticlePage = Model.ItemType == "Swift_Article";
185 string schemaOrgType = string.Empty;
186
187 if (isProductDetailsPage)
188 {
189 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Product\"";
190 }
191
192 if (isArticlePage)
193 {
194 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Article\"";
195 }
196
197
198 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/styles.css"));
199 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/scripts.js"));
200 //CUSTOM CODE//
201 var customJsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("Files/Templates/Designs/Swift/Assets/js/custom-scripts.js"));
202 //CUSTOM CODE//
203 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
204
205 string favicon = Model.Area.Item.GetRawValueString("Favicon", "/Files/Templates/Designs/Swift/Assets/Images/favicon.png");
206 string appleTouchIcon = Model.Area.Item.GetRawValueString("AppleTouchIcon", "/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon.png");
207
208 string headerCssClass = "sticky-top";
209 bool movePageBehind = false;
210
211 if (Model.PropertyItem != null)
212 {
213 headerCssClass = Model.PropertyItem.GetRawValueString("MoveThisPageBehindTheHeader", "sticky-top");
214 movePageBehind = headerCssClass == "fixed-top" && !Pageview.IsVisualEditorMode ? true : false;
215 }
216
217 headerCssClass = headerCssClass == "" ? "sticky-top" : headerCssClass;
218 headerCssClass = Pageview.IsVisualEditorMode ? "" : headerCssClass;
219
220 string googleTagManagerID = Model.Area.Item.GetString("GoogleTagManagerID").Trim();
221 string googleAnalyticsMeasurementID = Model.Area.Item.GetString("GoogleAnalyticsMeasurementID").Trim();
222
223 bool allowTracking = AllowTracking();
224
225 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/styles.css?{cssStyleFileInfo.LastWriteTime.Ticks}>; rel=preload; as=style;");
226 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css?{cssLastModified.Ticks}>; rel=preload; as=style;");
227 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/scripts.js?{jsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;");
228 //CUSTOM CODE
229 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/custom-scripts.js?{customJsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;");
230 //CUSTOM CODE
231
232 SetMetaTags();
233
234 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>();
235
236 var masterPage = Pageview.Area.IsMaster ? Pageview.Page : Pageview.Page.MasterPage;
237 languages.Add(masterPage);
238 if (masterPage?.Languages != null)
239 {
240 foreach (var language in masterPage.Languages)
241 {
242 languages.Add(language);
243 }
244 }
245
246 Uri url = Dynamicweb.Context.Current.Request.Url;
247 string hostName = url.Host;
248
249 <!doctype html>
250 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName">
251 <head>
252 <!-- @swiftVersion -->
253 @* Required meta tags *@
254 <meta charset="utf-8">
255 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0">
256 <link rel="shortcut icon" href="@favicon">
257 <link rel="apple-touch-icon" href="@appleTouchIcon">
258
259 @Model.MetaTags
260
261 @{
262 var alreadyWrittenTwoletterIsos = new List<string>();
263 @* Languages meta data *@
264 foreach (var language in languages)
265 {
266 hostName = url.Host;
267 if (language?.Area != null)
268 {
269 if (language.Area?.MasterArea != null && !string.IsNullOrEmpty(language.Area.MasterArea.DomainLock))
270 {
271 hostName = language.Area.MasterArea.DomainLock; //dk.domain.com or dk-domain.dk
272 }
273 if (language != null && language.Area != null && language.Published && language.Area.Active && language.Area.Published)
274 {
275 if (!string.IsNullOrEmpty(language.Area.DomainLock))
276 {
277 hostName = language.Area.DomainLock; //dk.domain.com or dk-domain.dk
278 }
279 string querystring = $"Default.aspx?ID={language.ID}";
280 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["GroupID"]))
281 {
282 querystring += $"&GroupID={Dynamicweb.Context.Current.Request.QueryString["GroupID"]}";
283 }
284 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"]))
285 {
286 querystring += $"&ProductID={Dynamicweb.Context.Current.Request.QueryString["ProductID"]}";
287 }
288 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["VariantID"]))
289 {
290 querystring += $"&VariantID={Dynamicweb.Context.Current.Request.QueryString["VariantID"]}";
291 }
292
293 string friendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(querystring);
294 if (language.Area.RedirectFirstPage && language.ParentPageId == 0 && language.Sort == 1)
295 {
296 friendlyUrl = "/";
297 }
298 string href = $"{url.Scheme}://{hostName}{friendlyUrl}";
299
300
301 <link rel="alternate" hreflang="@language.Area.CultureInfo.Name.ToLower()" href="@href">
302 if (!alreadyWrittenTwoletterIsos.Contains(language.Area.CultureInfo.TwoLetterISOLanguageName))
303 {
304 alreadyWrittenTwoletterIsos.Add(language.Area.CultureInfo.TwoLetterISOLanguageName);
305 <link rel="alternate" hreflang="@language.Area.CultureInfo.TwoLetterISOLanguageName.ToLower()" href="@href">
306 }
307 }
308 }
309 }
310 }
311
312 <title>@Model.Title</title>
313 @* Bootstrap + Swift stylesheet *@
314 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css">
315
316 @if (disableWideBreakpoints != "disableBoth")
317 {
318 <style>
319 @@media ( min-width: 1600px ) {
320 .container-xxl,
321 .container-xl,
322 .container-lg,
323 .container-md,
324 .container-sm,
325 .container {
326 max-width: 1520px;
327 }
328 }
329 </style>
330
331
332
333 if (disableWideBreakpoints != "disableUltraWideOnly")
334 {
335 <style>
336 @@media ( min-width: 1920px ) {
337 .container-xxl,
338 .container-xl,
339 .container-lg,
340 .container-md,
341 .container-sm,
342 .container {
343 max-width: 1820px;
344 }
345 }
346 </style>
347 }
348 }
349
350 @* Branding and Themes min stylesheet *@
351 <link href="/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_@(Model.Area.ID).min.css?@cssLastModified.Ticks" rel="stylesheet" media="all" type="text/css" data-last-modified-content="@cssLastModified">
352 <script src="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks"></script>
353 @*CUSTOM CODE*@
354 <script src="/Files/Templates/Designs/Swift/Assets/js/custom-scripts.js?@customJsFileInfo.LastWriteTime.Ticks" defer></script>
355 @*CUSTOM CODE*@
356 <script type="module">
357 swift.Scroll.hideHeadersOnScroll();
358 swift.Scroll.handleAlternativeTheme();
359
360 //Only load if AOS
361 const aosColumns = document.querySelectorAll('[data-aos]');
362 if (aosColumns.length > 0) {
363 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks', 'js');
364 document.addEventListener('load.swift.assetloader', function () {
365 AOS.init({ duration: 400, delay: 100, easing: 'ease-in-out', mirror: false, disable: window.matchMedia('(prefers-reduced-motion: reduce)') });
366 });
367 }
368 </script>
369
370 @* Google gtag method - always include even if it is not used for anything *@
371 <script>
372 window.dataLayer = window.dataLayer || [];
373 function gtag() { dataLayer.push(arguments); }
374 </script>
375
376 @* Google tag manager *@
377 @if (!string.IsNullOrWhiteSpace(googleTagManagerID))
378 {
379 <script>
380 gtag('consent', 'default', {
381 'ad_storage': 'denied',
382 'ad_user_data': 'denied',
383 'ad_personalization': 'denied',
384 'analytics_storage': 'denied'
385 });
386
387 window.dataLayer.push({
388 'event': 'cookie_cat_functional',
389 'cookie_cat_functional': 'true'
390
391 });
392 </script>
393 <script>
394 (function (w, d, s, l, i) {
395 w[l] = w[l] || []; w[l].push({
396 'gtm.start':
397 new Date().getTime(), event: 'gtm.js'
398 }); var f = d.getElementsByTagName(s)[0],
399 j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src =
400 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f);
401 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)');
402 </script>
403
404 if (allowTracking)
405 {
406 string adConsent = GetCookieOptInPermission("Marketing");
407 string analyticsConsent = GetCookieOptInPermission("Statistical");
408
409 string dataLayerMarketing = adConsent == "granted" ? "'event': 'cookie_cat_marketing','cookie_cat_marketing': 'true'" : "'event': 'cookie_cat_marketing','cookie_cat_marketing': 'false'";
410 string dataLayerStatistical = analyticsConsent == "granted" ? "'event': 'cookie_cat_statistic','cookie_cat_statistic': 'true'" : "'event': 'cookie_cat_statistic','cookie_cat_statistic': 'false'";
411
412 <script>
413 gtag('consent', 'update', {
414 'ad_storage': '@adConsent',
415 'ad_user_data': '@adConsent',
416 'ad_personalization': '@adConsent',
417 'analytics_storage': '@analyticsConsent'
418 });
419
420
421 dataLayer.push({@dataLayerMarketing});
422 dataLayer.push({@dataLayerStatistical});
423
424 </script>
425 } else {
426 <script>
427 window.dataLayer.push({
428 'event': 'cookie_cat_marketing',
429 'cookie_cat_marketing' : 'false'
430
431 });
432 window.dataLayer.push({
433 'event': 'cookie_cat_statistic',
434 'cookie_cat_statistic' : 'false'
435 });
436 </script>
437 }
438 }
439
440 @if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking)
441 {
442 var GoogleAnalyticsDebugMode = "";
443
444 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode"))
445 {
446 GoogleAnalyticsDebugMode = ", {'debug_mode': true}";
447 }
448
449 <script async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script>
450 <script>
451 gtag('js', new Date());
452 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode);
453 </script>
454 }
455
456 @if (!string.IsNullOrWhiteSpace(customHeaderInclude))
457 {
458 @RenderPartial($"Components/Custom/{customHeaderInclude}")
459 }
460 </head>
461 <body class="brand @(masterTheme)" id="page@(Model.ID)" data-otp-redirect-page="@otpRedirectPage">
462
463 @* Google tag manager *@
464 @if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking)
465 {
466 <noscript>
467 <iframe src="https://www.googletagmanager.com/ns.html?id=@(googleTagManagerID)"
468 height="0" width="0" style="display:none;visibility:hidden"></iframe>
469 </noscript>
470 }
471
472 @if (renderAsResponsive || !renderMobile)
473 {
474 <header class="page-header @headerCssClass top-0@(responsiveClassDesktop)" id="page-header-desktop">
475 @if (headerDesktopLink != null)
476 {
477 @RenderGrid(headerDesktopLink.PageId)
478 }
479 </header>
480 }
481
482 @if ((renderAsResponsive || renderMobile))
483 {
484 <header class="page-header @headerCssClass top-0@(responsiveClassMobile)" id="page-header-mobile">
485 @if (headerMobileLink != null)
486 {
487 @RenderGrid(headerMobileLink.PageId)
488 }
489 </header>
490 }
491
492 <div data-intersect></div>
493
494 <main id="content" @(schemaOrgType)>
495 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>
496 @using System
497 @using Dynamicweb.Ecommerce.ProductCatalog
498 @using Dynamicweb.Frontend.Navigation
499
500
501 @{
502 string productIdFromUrl = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : string.Empty;
503 bool isProductDetail = !string.IsNullOrEmpty(productIdFromUrl) && Pageview.Page.NavigationTag.ToLower() == "shop";
504
505 bool isArticlePagePage = Model.ItemType == "Swift_Article";
506 bool isArticleListPage = Model.ItemType == "Swift_ArticleListPage";
507 string schemaOrgProp = string.Empty;
508 if(isArticlePagePage)
509 {
510 schemaOrgProp = "itemprop=\"articleBody\"";
511 }
512
513 string theme = "";
514 string gridContent = "";
515
516 if (Model.PropertyItem != null)
517 {
518 theme = !string.IsNullOrWhiteSpace(Model.PropertyItem.GetRawValueString("Theme")) ? "theme " + Model.PropertyItem.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
519 }
520
521 if (Model.Item != null || Pageview.IsVisualEditorMode)
522 {
523 if (!isProductDetail)
524 {
525 gridContent = Model.Grid("Grid", "Grid", "default:true;sort:1", "Page");
526 }
527 else
528 {
529 var productObject = Dynamicweb.Ecommerce.Services.Products.GetProductById(productIdFromUrl, "", Pageview.Area.EcomLanguageId);
530 var detailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(productObject.PrimaryGroupId)?.Meta.PrimaryPage ?? string.Empty;
531 var detailPageId = detailPage != string.Empty ? Convert.ToInt16(detailPage.Substring(detailPage.LastIndexOf('=') + 1)) : GetPageIdByNavigationTag("ProductDetailPage");
532
533 @RenderGrid(detailPageId)
534 }
535 }
536
537 //Navigation settings
538 string navAlignment = "justify-content-start text-start";
539 string navOrientation = "flex-column";
540 string layout = "lines";
541 string linkFontWeight = "fw-normal";
542 string navTitleFontWeight = "fw-bold";
543 string NavTitleCasing = "text-capitalize";
544 string linkCasing = "";
545 string linkFontSize = "fs-6";
546 string navTitleFontSize = "h6";
547 string navigationRoot = "112";
548 bool showOnlyFirstLevel = true;
549 string contentPadding = " px-3 py-3";
550
551 var navigationSettings = new NavigationSettings();
552 navigationSettings.StartLevel = 1;
553 navigationSettings.StopLevel = 10;
554 navigationSettings.ExpandMode = ExpandMode.All;
555
556 navigationSettings.Parameters.Add("Layout", layout);
557 navigationSettings.Parameters.Add("LinkFontSize", linkFontSize);
558 navigationSettings.Parameters.Add("NavOrientation", navOrientation);
559 navigationSettings.Parameters.Add("LinkFontWeight", linkFontWeight);
560 navigationSettings.Parameters.Add("NavAlignment", navAlignment);
561 navigationSettings.Parameters.Add("LinkCasing", linkCasing);
562 navigationSettings.Parameters.Add("Theme", theme);
563 navigationSettings.Parameters.Add("ShowOnlyFirstNavLevel", showOnlyFirstLevel);
564
565 if (!string.IsNullOrEmpty(navigationRoot))
566 {
567 int rootPageId = Convert.ToInt32(navigationRoot);
568 navigationSettings.RootPageId = rootPageId;
569
570 var page = Dynamicweb.Content.Services.Pages.GetPage(rootPageId);
571 if (page != null && !string.IsNullOrEmpty(page.NavigationTag))
572 {
573 navigationSettings.Parameters.Add("menu-id", page.NavigationTag.ToLower());
574 }
575
576 }
577 else
578 {
579 navigationSettings.Parameters.Add("menu-id", "root");
580 }
581
582
583 bool doNotRenderPage = false;
584
585 //Check if we are on the poduct detail page, and if there is data to render
586 ProductViewModel product = new ProductViewModel();
587 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
588 {
589 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
590 if (string.IsNullOrEmpty(product.Id)) {
591 doNotRenderPage = true;
592 }
593 }
594
595 //Render the page
596 if (!doNotRenderPage) {
597 string itemIdentifier = Model?.Item?.SystemName != null ? "item_" + Model.Item.SystemName.ToLower() : "item_Swift_Page";
598 string sectionClass = "py-3 py-lg-3";
599 string containerClass = "container-xl";
600 string mobileColumnSize = "1";
601 string rowClass = "";
602
603 <div class="@theme @itemIdentifier" @schemaOrgProp>
604 <div class="@(sectionClass)@(theme)">
605 <div class="@containerClass">
606 <div class="grid grid-@(mobileColumnSize) grid-lg-4@(rowClass)">
607 <div class="g-col order-first order-lg-0" data-col-size="3" style="--bs-columns:12">
608 <div class="h-100@(theme) item_@Model.Item.SystemName.ToLower()">
609 @if (!string.IsNullOrEmpty(Model.Item.GetString("Title")) && !Model.Item.GetBoolean("HideTitle"))
610 {
611 <h3 class="@contentPadding">@Model.Item.GetString("Title")</h3>
612 }
613
614 @Navigation.RenderNavigation("Navigation/Vertical.cshtml", navigationSettings)
615 </div>
616 </div>
617 <div class="g-col g-col-lg-3" data-col-size="9" style="--bs-columns:12">
618 @gridContent
619 </div>
620 </div>
621 </div>
622 </div>
623
624 </div>
625
626 } else {
627 <div class="container">
628 <div class="alert alert-info" role="alert">@Translate("Sorry. There is nothing to view here")</div>
629 </div>
630 }
631
632 if (!Model.IsCurrentUserAllowed)
633 {
634 int signInPage = GetPageIdByNavigationTag("SignInPage");
635 int dashboardPage = GetPageIdByNavigationTag("MyAccountDashboardPage");
636
637 if (!Pageview.IsVisualEditorMode)
638 {
639 if (signInPage != 0)
640 {
641 if (signInPage != Model.ID) {
642 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + signInPage);
643 } else {
644 if (dashboardPage != 0) {
645 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + dashboardPage);
646 } else {
647 Dynamicweb.Context.Current.Response.Redirect("/");
648 }
649 }
650 }
651 else
652 {
653 <div class="alert alert-dark m-0" role="alert">
654 <span>@Translate("You do not have access to this page") @Pageview.Page.ID</span>
655 </div>
656 }
657 }
658 else
659 {
660 <div class="alert alert-dark m-0" role="alert">
661 <span>@Translate("To work on this page, you must be signed in, in the frontend")</span>
662 </div>
663 }
664 }
665 }
666
667 </main>
668
669 @if (renderAsResponsive || !renderMobile)
670 {
671 <footer class="page-footer@(responsiveClassDesktop)" id="page-footer-desktop">
672 @if (footerDesktopLink != null)
673 {
674 @RenderGrid(footerDesktopLink.PageId)
675 }
676 </footer>
677 }
678
679 @if (renderAsResponsive || renderMobile)
680 {
681 <footer class="page-footer@(responsiveClassMobile)" id="page-footer-mobile">
682 @if (footerMobileLink != null)
683 {
684 @RenderGrid(footerMobileLink.PageId)
685 }
686 </footer>
687 }
688
689 @* Render any offcanvas menu here *@
690 @RenderSnippet("offcanvas")
691
692 @{
693 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]);
694 }
695
696 @* Language selector modal *@
697 <div class="modal fade" id="PreferencesModal" tabindex="-1" aria-hidden="true">
698 <div class="modal-dialog modal-dialog-centered modal-sm" id="PreferencesModalContent">
699 @* The content here comes from an external request *@
700 </div>
701 </div>
702
703 @* Favorite toast *@
704 <div aria-live="polite" aria-atomic="true">
705 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
706 <div id="favoriteNotificationToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
707 <div class="toast-header">
708 <strong class="me-auto">@Translate("Favorite list updated")</strong>
709 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
710 </div>
711 <div class="toast-body d-flex gap-3">
712 <div id="favoriteNotificationToast_Image"></div>
713 <div id="favoriteNotificationToast_Text"></div>
714 </div>
715 </div>
716 </div>
717 </div>
718
719 @* Modal for dynamic content *@
720 <div class="modal fade js-product" id="DynamicModal" tabindex="-1" aria-hidden="true">
721 <div class="modal-dialog modal-dialog-centered modal-md">
722 <div class="modal-content theme light" id="DynamicModalContent">
723 @* The content here comes from an external request *@
724 </div>
725 </div>
726 </div>
727
728 @* Offcanvas for dynamic content *@
729 <div class="offcanvas offcanvas-end theme light" tabindex="-1" id="DynamicOffcanvas">
730 @* The content here comes from an external request *@
731 </div>
732
733 @if (Model.Area.Item.GetBoolean("ShowErpDownMessage") && !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]))
734 {
735 string erpDownMessageTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("ErpDownMessageTheme")) ? " theme " + Model.Area.Item.GetRawValueString("ErpDownMessageTheme").Replace(" ", "").Trim().ToLower() : "theme light";
736
737 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1040">
738 <div class="toast fade show border-0 @erpDownMessageTheme" role="alert" aria-live="assertive" aria-atomic="true">
739 <div class="toast-header">
740 <strong class="me-auto">@Translate("Connection down")</strong>
741 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
742 </div>
743 <div class="toast-body">
744 @Translate("We are experiencing some connectivity issues. Not all features may be available to you.")
745 </div>
746 </div>
747 </div>
748 }
749
750 @if (miniCartEnabled)
751 {
752 @* Open MiniCart when the cart is updated *@
753 <script type="module">
754 document.addEventListener('updated.swift.cart', (event) => {
755 let orderContext = event?.detail?.formData?.get("OrderContext");
756 updateCartSummary(orderContext);
757
758 @if (offcanvasMiniCartBehaviour == "2" || offcanvasMiniCartBehaviour == "3") {
759 <text>openMiniCartOffcanvas();</text>
760 }
761 });
762 </script>
763
764 if (offcanvasMiniCartBehaviour == "1" || offcanvasMiniCartBehaviour == "3")
765 {
766 @* Open MiniCart when toggle is clicked *@
767 <script type="module">
768 let miniCartToggles = document.querySelectorAll('.mini-cart-quantity');
769 miniCartToggles?.forEach((toggle) => {
770 toggle.parentElement.addEventListener('click', (event) => {
771 event.preventDefault();
772 let orderContext = toggle.dataset?.orderContext;
773 updateCartSummary(orderContext);
774
775 openMiniCartOffcanvas();
776 });
777 });
778 </script>
779 }
780
781 <script>
782
783 const updateCartSummary = (orderContext) => {
784 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas');
785 swift.PageUpdater.UpdateFromUrlInline(event, '/Default.aspx?ID=@(cartSummaryPageId)&CartType=minicart&RequestPageID=@(Pageview.Page.ID)&OrderContext=' + orderContext +'', 'Swift_CartSummary.cshtml', dynamicOffcanvas);
786 };
787
788 const openMiniCartOffcanvas = () => {
789 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas');
790 const miniCartOffcanvas = bootstrap.Offcanvas.getOrCreateInstance(dynamicOffcanvas);
791 dynamicOffcanvas.classList.add('overflow-y-auto');
792
793 if (!miniCartOffcanvas._isShown) {
794 miniCartOffcanvas.show();
795 hideActiveOffcanvases(miniCartOffcanvas);
796 }
797 };
798
799 const hideActiveOffcanvases = (miniCartOffcanvas) => {
800 let activeOffcanvases = document.querySelectorAll('.offcanvas.show');
801 activeOffcanvases?.forEach((offCanvas) => {
802 offCanvas = bootstrap.Offcanvas.getInstance(offCanvas);
803 if (offCanvas !== miniCartOffcanvas) {
804 offCanvas.hide();
805 }
806 });
807 };
808
809 </script>
810 }
811
812 @* START CUSTOM CODE *@
813 @RenderFaqModal()
814 @RenderCustomFontStyleTag()
815 @* END CUSTOM CODE *@
816
817
818
819 @{
820 var cookieBannerParameter = Dynamicweb.Context.Current.Request.QueryString["showcookiebanner"];
821 string showCookieBanner = cookieBannerParameter != null ? cookieBannerParameter.ToString() : "";
822
823 //if(showCookieBanner.Equals("true", StringComparison.OrdinalIgnoreCase))
824 if(CookieManager.GetCookieOptInCategories().Any() && CookieManager.IsCookieManagementActive)
825 {
826 @RenderPartial($"CookieWarning/{Pageview.Area.CookieWarningTemplate}")
827 }
828 }
829
830 <button class="btn btn-secondary position-fixed bottom-0 mb-2 ms-2 bg-white" id="launchCookieModal" onclick="renderCookieModal()">
831 @RenderIcon("/Files/Icons/cookies.svg")
832 </button>
833
834
835 @* @using System
836 @using Dynamicweb
837 @using Dynamicweb.Environment
838 @using Dynamicweb.Frontend
839 @using DirectionsEMEA.Domain.Models.DW.OTP
840 @using DirectionsEMEA.Infrastructure.Facade
841 @using DirectionsEMEA.Infrastructure.Config
842
843 @{
844 var request = Context.Current.Request;
845 bool isPostBack = request.HttpMethod == "POST";
846
847 string email = request.Form["Email"] ?? "";
848 string code = request.Form["Code"] ?? "";
849 string action = request.Form["Action"] ?? "";
850
851 string message = "";
852 bool showCodeInput = false;
853
854 if (Context.Current.Session["OTP_Email"] != null)
855 {
856 email = Context.Current.Session["OTP_Email"].ToString();
857 showCodeInput = true;
858 }
859
860 if (isPostBack)
861 {
862 if (action == "Send")
863 {
864 var result = AuthenticationFacade.RequestOTP(email);
865 if (result.Success)
866 {
867 Context.Current.Session["OTP_Email"] = email;
868 showCodeInput = true;
869 message = "✅ Code sent to your email!";
870 }
871 else
872 {
873 message = "❌ " + result.Message;
874 }
875 }
876 else if (action == "Verify")
877 {
878 var result = AuthenticationFacade.VerifyOTP(email, code);
879 if (result.IsValid && result.User != null)
880 {
881 bool isUserAuth = AuthenticationFacade.LoginUser(result.User , LoginType.OTP);
882 Context.Current.Session.Remove("OTP_Email");
883 Context.Current.Response.Redirect("/");
884 return;
885 }
886 else
887 {
888 message = "❌ " + result.Message;
889 }
890 }
891 else if (action == "Reset")
892 {
893 Context.Current.Session.Remove("OTP_Email");
894 showCodeInput = false;
895 email = "";
896 message = "";
897 }
898 }
899
900 var otpEmailFromSession = Context.Current?.Session["OTP_Email"]?.ToString() ?? "";
901 var config = DirectionsConfig.GetFromDynamicweb();
902 int otpCodeMaxAttempts = config.OTP.CodeMaxAttempts;
903 var otpCodeExpiryMins = config.OTP.CodeExpiryMinutes;
904 var codeExpiresMessage = Translate("Code expires in") + " " + otpCodeExpiryMins + " " + Translate("minutes");
905 bool disableVerifyButton = message.Contains("attempts") && message.Contains("0");
906 }
907
908 <div class="modal fade modal-md @(showCodeInput ? "show-modal" : "")" id="SignInOTPModal">
909 <div class="modal-dialog @(Pageview.User != null ? "reload" : "")">
910 <div class="modal-content rounded-7">
911 <div class="modal-header">
912 <h3 class="modal-title">@Translate("OTP Login")</h3>
913 <button type="button" class="btn-close me-1" data-bs-dismiss="modal" aria-label="@Translate("Close")"></button>
914 </div>
915
916 <div class="modal-body" id="SignInOTPModalBody" data-opt-wizard>
917 <div class="d-grid gap-3 @(showCodeInput ? "d-none" : "active")" data-step="1">
918 <h5 class="mb-0">@Translate("Enter your email")</h5>
919 <div class="form-floating">
920 <input type="email" class="form-control" required placeholder="@Translate("your.email@example.com")" name="Email" id="OTPEmail">
921 <label for="Email">@Translate("Email")</label>
922 </div>
923 <button type="submit" class="btn btn-primary action-button" data-action="Send">@Translate("Send verification code")</button>
924 <p class="small mb-0 text-center color-gray">@Translate("We'll send a 6-digit code to your email")</p>
925 </div>
926
927 <div class="d-grid gap-3 @(showCodeInput ? "active" : "d-none")" data-step="2">
928 <div class="d-grid gap-1">
929 <h5 class="mb-0">@Translate("Enter verification code")</h5>
930 @if (!string.IsNullOrEmpty(otpEmailFromSession))
931 {
932 <p class="mb-0 small text-muted">@Translate("Code sent to :") <b>@otpEmailFromSession</b></p>
933 }
934 </div>
935 <input type="hidden" name="Action" value="Verify">
936 <input type="hidden" name="Email" value="@otpEmailFromSession">
937 <div class="form-floating">
938 <input type="text" maxlength="6" minlength="6" class="form-control text-center fw-bold" style="letter-spacing: 8px" placeholder="000000" name="Code" required>
939 <label for="Code">@codeExpiresMessage</label>
940 </div>
941 <button class="btn btn-primary action-button" data-action="Verify" data-current-attempt="1" data-max-attempts="@otpCodeMaxAttempts" @(disableVerifyButton ? "disabled" : "")>@Translate("Verify & Sign In")</button>
942 <div class="d-flex flex-wrap justify-content-center">
943 <button class="btn btn-link action-button" data-action="Send" skip @(!disableVerifyButton ? "disabled enable-after" : "")>@Translate("Resend code")</button>
944 <button class="btn btn-link action-button" data-action="Reset" skip>@Translate("Use different email")</button>
945 </div>
946 </div>
947 </div>
948
949 @if (!string.IsNullOrEmpty(message))
950 {
951 <div class="modal-footer justify-content-center">
952 <div class="d-grid">
953 @message
954 </div>
955 </div>
956 }
957
958 </div>
959 </div>
960 </div> *@
961 </body>
962
963 </html>
964
965 }
966 else if (Pageview.IsVisualEditorMode)
967 {
968 <head>
969 <title>@Model.Title</title>
970 @* Bootstrap + Swift stylesheet *@
971 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css" rel="stylesheet" media="all" type="text/css">
972 </head>
973 <body class="p-3">
974 <div class="alert alert-danger" role="alert">
975 @Translate("Basic Swift setup is needed!")
976 </div>
977
978 @if (brandingPage == null)
979 {
980 <div class="alert alert-warning" role="alert">
981 @Translate("Please add a Branding page and reference it in website settings")
982 </div>
983 }
984
985 @if (themesParagraphs == null)
986 {
987 <div class="alert alert-warning" role="alert">
988 @Translate("Please add a Themes collection page and reference it in website settings")
989 </div>
990 }
991
992
993 </body>
994 }
995
996
997 @functions {
998 void SetMetaTags()
999 {
1000 //Verification Tokens
1001 string siteVerificationGoogle = Model.Area.Item.GetString("Google_Site_Verification") != null ? Model.Area.Item.GetString("Google_Site_Verification") : "";
1002
1003 //Generic Site Values
1004 string openGraphFacebookAppID = Model.Area.Item.GetString("Fb_app_id") != null ? Model.Area.Item.GetString("Fb_app_id") : "";
1005 string openGraphType = Model.Area.Item.GetString("Open_Graph_Type") != null ? Model.Area.Item.GetString("Open_Graph_Type") : "";
1006 string openGraphSiteName = Model.Area.Item.GetString("Open_Graph_Site_Name") != null ? Model.Area.Item.GetString("Open_Graph_Site_Name") : "";
1007
1008 string twitterCardSite = Model.Area.Item.GetString("Twitter_Site") != null ? Model.Area.Item.GetString("Twitter_Site") : "";
1009
1010 //Page specific values
1011 string openGraphSiteTitle = Model.Area.Item.GetString("Open_Graph_Title") != null ? Model.Area.Item.GetString("Open_Graph_Title") : "";
1012 FileViewModel openGraphImage = Model.Area.Item.GetFile("Open_Graph_Image");
1013 string openGraphImageALT = Model.Area.Item.GetString("Open_Graph_Image_ALT") != null ? Model.Area.Item.GetString("Open_Graph_Image_ALT") : "";
1014 string openGraphDescription = Model.Area.Item.GetString("Open_Graph_Description") != null ? Model.Area.Item.GetString("Open_Graph_Description") : "";
1015
1016 string twitterCardURL = Model.Area.Item.GetString("Twitter_URL") != null ? Model.Area.Item.GetString("Twitter_URL") : "";
1017 string twitterCardTitle = Model.Area.Item.GetString("Twitter_Title") != null ? Model.Area.Item.GetString("Twitter_Title") : "";
1018 string twitterCardDescription = Model.Area.Item.GetString("Twitter_Description") != null ? Model.Area.Item.GetString("Twitter_Description") : "";
1019 FileViewModel twitterCardImage = Model.Area.Item.GetFile("Twitter_Image");
1020 string twitterCardImageALT = Model.Area.Item.GetString("Twitter_Image_ALT") != null ? Model.Area.Item.GetString("Twitter_Image_ALT") : "";
1021 string topImage = Pageview.Page.TopImage.StartsWith("/Files", StringComparison.OrdinalIgnoreCase) ? Pageview.Page.TopImage : $"/Files{Pageview.Page.TopImage}";
1022
1023 if (string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"]))
1024 {
1025 if (!string.IsNullOrEmpty(Model.Description))
1026 {
1027 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{Model.Description}\">");
1028 }
1029 else
1030 {
1031 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{openGraphDescription}\">");
1032 }
1033
1034 if (!string.IsNullOrEmpty(Pageview.Page.TopImage))
1035 {
1036 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">");
1037 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">");
1038 }
1039 else if (openGraphImage != null)
1040 {
1041 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">");
1042 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">");
1043 }
1044
1045 if (!string.IsNullOrEmpty(openGraphImageALT))
1046 {
1047 Pageview.Meta.AddTag($"<meta property=\"og:image:alt\" content=\"{openGraphImageALT}\">");
1048 }
1049 if (!string.IsNullOrEmpty(twitterCardDescription))
1050 {
1051 Pageview.Meta.AddTag("twitter:description", twitterCardDescription);
1052 }
1053
1054 if (!string.IsNullOrEmpty(Pageview.Page.TopImage))
1055 {
1056 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}");
1057 }
1058 else if (twitterCardImage != null)
1059 {
1060 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}");
1061 }
1062
1063 if (!string.IsNullOrEmpty(twitterCardImageALT))
1064 {
1065 Pageview.Meta.AddTag("twitter:image:alt", twitterCardImageALT);
1066 }
1067 }
1068
1069 if (!string.IsNullOrEmpty(siteVerificationGoogle))
1070 {
1071 Pageview.Meta.AddTag("google-site-verification", siteVerificationGoogle);
1072 }
1073
1074 if (!string.IsNullOrEmpty(openGraphFacebookAppID))
1075 {
1076 Pageview.Meta.AddTag($"<meta property=\"fb:app_id\" content=\"{openGraphFacebookAppID}\">");
1077 }
1078
1079 if (!string.IsNullOrEmpty(openGraphType))
1080 {
1081 Pageview.Meta.AddTag($"<meta property=\"og:type\" content=\"{openGraphType}\">");
1082 }
1083
1084 if (!string.IsNullOrEmpty(openGraphSiteName))
1085 {
1086 Pageview.Meta.AddTag($"<meta property=\"og:url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{Pageview.SearchFriendlyUrl}\">");
1087 }
1088
1089 if (!string.IsNullOrEmpty(openGraphSiteName))
1090 {
1091 Pageview.Meta.AddTag($"<meta property=\"og:site_name\" content=\"{openGraphSiteName}\">");
1092 }
1093
1094 if (!string.IsNullOrEmpty(Model.Title))
1095 {
1096 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{Model.Title}\">");
1097 }
1098 else
1099 {
1100 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{openGraphSiteTitle}\">");
1101 }
1102
1103 if (!string.IsNullOrEmpty(twitterCardSite))
1104 {
1105 Pageview.Meta.AddTag("twitter:site", twitterCardSite);
1106 }
1107
1108 if (!string.IsNullOrEmpty(twitterCardURL))
1109 {
1110 Pageview.Meta.AddTag("twitter:url", twitterCardURL);
1111 }
1112
1113 if (!string.IsNullOrEmpty(twitterCardTitle))
1114 {
1115 Pageview.Meta.AddTag("twitter:title", twitterCardTitle);
1116 }
1117 }
1118 }
1119 @* START CUSTOM CODE *@
1120 @helper RenderFaqModal()
1121 {
1122 var faqPage = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(GetPageIdByNavigationTag("FAQ"));
1123 <div class="modal modal-xl faq-modal" aria-hidden="true" data-url="@faqPage">
1124 <div class="modal-dialog">
1125 <div class="modal-content">
1126 <div class="modal-header">
1127 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
1128 </div>
1129 <div class="modal-body p-0"></div>
1130 </div>
1131 </div>
1132 </div>
1133 }
1134 @helper RenderCustomFontStyleTag()
1135 {
1136 <style>
1137 @@font-face {
1138 font-family: 'Arsilon';
1139 font-style: normal;
1140 font-weight: 400;
1141 font-display: swap;
1142 src: url(/Files/Templates/Designs/Swift/Assets/fonts/Arsilon.woff2) format('woff2');
1143 }
1144
1145
1146 span.special {
1147 font-family:'Arsilon';
1148 font-weight:400;
1149 font-style:normal;
1150 line-height:1.5;
1151 font-size:72px;
1152 }
1153 </style>
1154 }
1155 @helper RenderIcon(string icon)
1156 {
1157 if (System.IO.Path.GetExtension(icon).ToLower() == ".svg")
1158 {
1159 if (!icon.ToLower().Contains("none") && icon != string.Empty)
1160 {
1161 <span class="icon-auto">
1162 @ReadFile(icon)
1163 </span>
1164 }
1165 }
1166 }
1167 @* END CUSTOM CODE *@