import { LightningElement, api } from "lwc"; import cx from "classnames"; import { Brand, OptionWithLink, OptionWithNested } from "typings/custom"; import { toJson, normalizeBoolean } from "dxUtils/normalizers"; import { track } from "dxUtils/analytics"; const VALID_BRANDS = [ "analytics", "commerce", "employees", "data", "industries", "integration", "learning", "marketing", "partners", "platform", "revenue", "sales", "service", "success", "einstein" ]; export const ANALYTICS_INFO = { click_text: "browse trials", element_type: "button", content_category: "cta" }; export abstract class HeaderBase extends LightningElement { @api bailHref?: string | null = null; @api bailLabel?: string | null = null; @api brand: Brand | null = null; @api coveoOrganizationId: string | null = null; @api coveoPublicAccessToken: string | null = null; @api coveoSearchHub: string | null = null; @api coveoSearchPipeline: string | null = null; @api signupLink?: string | null = null; @api href = null; @api subtitle!: string; @api tbidApiBaseUrl: string | null = null; @api tbidBaseUrl: string | null = null; @api header: string = "Salesforce"; @api version?: string | null = null; @api bannerMarkup = 'Share your feedbackabout our new site.'; @api get navItems() { return this._navItems; } set navItems(value) { this._navItems = toJson(value); } @api get versions() { return this._versions; } set versions(value) { this._versions = toJson(value); } @api get showBanner() { return this._showBanner && this.bannerMarkup; } set showBanner(value) { this._showBanner = normalizeBoolean(value); } private _navItems!: OptionWithNested[]; private _versions!: OptionWithLink[]; private matchMedia!: MediaQueryList; protected mobile: boolean = false; private mobileNavMenuValue: string | null = null; private showMobileNavMenu: boolean = false; private showNavScrollShadow: boolean = false; protected isSearchOpen: boolean = false; private _showBanner?: boolean = false; get url() { return this.href ? new URL(this.href!) : window.location; } get hasBailLink(): boolean { return !!(this.bailHref && this.bailLabel); } get hasSearch() { return ( this.coveoOrganizationId && this.coveoPublicAccessToken && this.coveoSearchHub && this.coveoSearchPipeline ); } get pathname() { return this.url.pathname; } get className() { return cx( this.hasNavItems && "has-nav-items", this.showMobileNavMenu && "state-show-mobile-nav", this.showNavScrollShadow && !this.showMobileNavMenu && "has-navscrollshadow", this.additionalClasses() ); } get versionLabel() { const selectedVersion = (this.versions || []).find( (v) => v.id === this.version ); return selectedVersion ? selectedVersion.label : ""; } get mobileMenuIconSymbol() { return this.showMobileNavMenu ? "close" : "rows"; } get isValidBrand() { return this.brand && VALID_BRANDS.includes(this.brand); } get hasNavItems(): boolean { return this.navItems && this.navItems.length > 0; } connectedCallback() { this.matchMedia = window.matchMedia( `(max-width: ${this.mobileBreakpoint()})` ); this.onMediaChange(this.matchMedia); this.matchMedia.addEventListener("change", this.onMediaChange); this.hashLinkScroll(); } disconnectedCallback() { this.matchMedia.removeEventListener("change", this.onMediaChange); } // Temporary solution to restore native anchor scrolling private hashLinkScroll() { const hash = window.location.hash; if (hash !== "") { // Push onto callback queue so it runs after the DOM is updated setTimeout(() => { const id = hash.replace("#", ""); const element = document.getElementById(id); if (element && element.scrollIntoView) { element.scrollIntoView(); } }, 0); } } private handleStateChange(event: CustomEvent) { event.stopPropagation(); this.isSearchOpen = event.detail; } onVersionChange(e: CustomEvent) { this.dispatchEvent( new CustomEvent("versionchange", { detail: e.detail }) ); } onRequestOpenNavMenu(e: { detail: string }) { this.mobileNavMenuValue = e.detail; this.showMobileNavMenu = true; } private onMobileNavMenuChange(e: { detail: string }) { this.mobileNavMenuValue = e.detail; } private toggleMobileNavMenu() { this.showMobileNavMenu = !this.showMobileNavMenu; } private closeMobileNavMenu() { this.showMobileNavMenu = false; } private onNavScroll(e: Event) { this.showNavScrollShadow = (e.currentTarget).scrollLeft > 4; } private onMediaChange = (e: MediaQueryListEvent | MediaQueryList) => { if (!e.matches) { this.mobile = false; this.closeMobileNavMenu(); } else { this.mobile = true; } }; private handleSignUpClick(e: PointerEvent) { const payload = { ...ANALYTICS_INFO, click_url: this.signupLink, element_title: this.header }; track(e.currentTarget!, "custEv_browseTrialsClick", payload); track(e.currentTarget!, "custEv_linkClick", payload); } protected additionalClasses(): string { return ""; } protected abstract mobileBreakpoint(): string; }