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 *@