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