@triptease/tt-navbar 0.0.18 → 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,8 @@ import { LitElement } from 'lit';
2
2
  export declare class TtNavbar extends LitElement {
3
3
  static styles: import("lit").CSSResult;
4
4
  navigate: ((e: MouseEvent) => void) | undefined;
5
- baseUrl?: string;
5
+ campaignManagerUrl: string;
6
+ platformUrl?: string;
6
7
  clientKey?: string;
7
8
  protected allDetailsElements: Array<HTMLDetailsElement>;
8
9
  protected allNavLinks: Array<HTMLAnchorElement>;
@@ -5,9 +5,11 @@ import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
5
5
  import { campaigns, channels, chevronDown, gear, graph, home, logout, user, wallet, external, sidebarCollapsed, } from '@triptease/icons';
6
6
  import { styles } from './styles.js';
7
7
  import { tripteaseLogo } from './triptease-logo.js';
8
+ import { urlMappings } from './urlMappings.js';
8
9
  export class TtNavbar extends LitElement {
9
10
  constructor() {
10
11
  super(...arguments);
12
+ this.campaignManagerUrl = 'https://app.campaign-manager.triptease.io';
11
13
  this.sidebarOpen = true;
12
14
  /*
13
15
  * Set the active state for the current page.
@@ -33,16 +35,31 @@ export class TtNavbar extends LitElement {
33
35
  const currentPath = window.location.pathname;
34
36
  let bestMatch;
35
37
  let bestMatchLength = 0;
36
- for (const link of this.allNavLinks) {
37
- link.classList.remove('current-page');
38
- if (link.hasAttribute('aria-current')) {
39
- link.attributes.removeNamedItem('aria-current');
38
+ // Check special cases first, as everything will always match on / and return Dashboard
39
+ if (this.campaignManagerUrl.includes(window.location.host)) {
40
+ const links = Object.values(this.allNavLinks);
41
+ bestMatch = links.find(link => link.href.includes(this.campaignManagerUrl));
42
+ }
43
+ if (!bestMatch && this.clientKey) {
44
+ const parsedPath = currentPath.replace(this.clientKey, '$CLIENT_KEY');
45
+ const mappedUrl = urlMappings[parsedPath];
46
+ if (mappedUrl) {
47
+ const links = Object.values(this.allNavLinks);
48
+ bestMatch = links.find(link => link.href.includes(mappedUrl));
40
49
  }
41
- const linkPath = new URL(link.href).pathname;
42
- if (currentPath.startsWith(linkPath)) {
43
- if (linkPath.length > bestMatchLength) {
44
- bestMatch = link;
45
- bestMatchLength = linkPath.length;
50
+ }
51
+ if (!bestMatch) {
52
+ for (const link of this.allNavLinks) {
53
+ link.classList.remove('current-page');
54
+ if (link.hasAttribute('aria-current')) {
55
+ link.attributes.removeNamedItem('aria-current');
56
+ }
57
+ const linkPath = new URL(link.href).pathname;
58
+ if (currentPath.startsWith(linkPath)) {
59
+ if (linkPath.length > bestMatchLength) {
60
+ bestMatch = link;
61
+ bestMatchLength = linkPath.length;
62
+ }
46
63
  }
47
64
  }
48
65
  }
@@ -50,6 +67,9 @@ export class TtNavbar extends LitElement {
50
67
  bestMatch.classList.add('current-page');
51
68
  bestMatch.setAttribute('aria-current', 'page');
52
69
  }
70
+ else {
71
+ console.error(`No matching nav link found for path: ${currentPath}`);
72
+ }
53
73
  };
54
74
  this.closeAllDetails = (element) => {
55
75
  this.allDetailsElements.forEach(detail => {
@@ -79,13 +99,14 @@ export class TtNavbar extends LitElement {
79
99
  if (!this.clientKey)
80
100
  throw new Error('clientKey is required');
81
101
  const formattedPath = path.replace('$CLIENT_KEY', this.clientKey);
82
- if (!this.baseUrl)
102
+ if (!this.platformUrl)
83
103
  return formattedPath;
84
- return new URL(formattedPath, this.baseUrl).toString();
104
+ return new URL(formattedPath, this.platformUrl).toString();
85
105
  };
86
106
  this.onAnchorClick = (e) => {
87
107
  if (this.navigate) {
88
108
  this.navigate(e);
109
+ this.setActiveState();
89
110
  }
90
111
  };
91
112
  }
@@ -115,7 +136,7 @@ export class TtNavbar extends LitElement {
115
136
  @click=${this.onAnchorClick}
116
137
  >${unsafeSVG(home)}<span>Dashboard</span></a
117
138
  >
118
- <a class="nav-item" href="https://app.campaign-manager.triptease.io"
139
+ <a class="nav-item" href=${this.campaignManagerUrl}
119
140
  >${unsafeSVG(campaigns)}<span>Campaigns</span></a
120
141
  >
121
142
  <a
@@ -272,8 +293,11 @@ __decorate([
272
293
  property({ type: Function })
273
294
  ], TtNavbar.prototype, "navigate", void 0);
274
295
  __decorate([
275
- property({ type: String, attribute: 'base-url' })
276
- ], TtNavbar.prototype, "baseUrl", void 0);
296
+ property({ type: String, attribute: 'campaign-manager-url' })
297
+ ], TtNavbar.prototype, "campaignManagerUrl", void 0);
298
+ __decorate([
299
+ property({ type: String, attribute: 'platform-url' })
300
+ ], TtNavbar.prototype, "platformUrl", void 0);
277
301
  __decorate([
278
302
  property({ type: String, attribute: 'client-key' })
279
303
  ], TtNavbar.prototype, "clientKey", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"TtNavbar.js","sourceRoot":"","sources":["../../src/TtNavbar.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, LitElement } from 'lit';\nimport { property, queryAll, state } from 'lit/decorators.js';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport {\n campaigns,\n channels,\n chevronDown,\n gear,\n graph,\n home,\n logout,\n user,\n wallet,\n external,\n sidebarCollapsed,\n} from '@triptease/icons';\nimport { styles } from './styles.js';\nimport { tripteaseLogo } from './triptease-logo.js';\n\nexport class TtNavbar extends LitElement {\n static styles = styles;\n\n @property({ type: Function })\n navigate: ((e: MouseEvent) => void) | undefined;\n\n @property({ type: String, attribute: 'base-url' })\n baseUrl?: string;\n\n @property({ type: String, attribute: 'client-key' })\n clientKey?: string;\n\n @queryAll('details')\n protected allDetailsElements!: Array<HTMLDetailsElement>;\n\n @queryAll('a')\n protected allNavLinks!: Array<HTMLAnchorElement>;\n\n @state()\n private sidebarOpen = true;\n\n protected firstUpdated() {\n this.setActiveState();\n }\n\n /*\n * Set the active state for the current page.\n *\n * This function iterates over all nav links and compares the current URL path with the href of each link.\n * If the current URL path starts with the href of a link, the link is marked as active. If multiple links\n * share the same prefix, the longest prefix is used as it is more specific.\n *\n * Example:\n * - Current URL: /channels/123\n * - Nav links:\n * - /channels\n * - /channels/123\n * - /channels/456\n *\n * Loop 1: currentPath = /channels/123, linkPath = /channels, bestMatch = /channels\n * Loop 2: currentPath = /channels/123, linkPath = /channels/123, bestMatch = /channels/123\n * Loop 3: currentPath = /channels/123, linkPath = /channels/456, bestMatch = /channels/123\n * Result: /channels/123 is marked as active\n *\n */\n private setActiveState = () => {\n const currentPath = window.location.pathname;\n\n let bestMatch: HTMLAnchorElement | undefined;\n let bestMatchLength = 0;\n\n for (const link of this.allNavLinks) {\n link.classList.remove('current-page');\n if (link.hasAttribute('aria-current')) {\n link.attributes.removeNamedItem('aria-current');\n }\n\n const linkPath = new URL(link.href).pathname;\n\n if (currentPath.startsWith(linkPath)) {\n if (linkPath.length > bestMatchLength) {\n bestMatch = link;\n bestMatchLength = linkPath.length;\n }\n }\n }\n\n if (bestMatch) {\n bestMatch.classList.add('current-page');\n bestMatch.setAttribute('aria-current', 'page');\n }\n };\n\n private closeAllDetails = (element?: HTMLDetailsElement) => {\n this.allDetailsElements.forEach(detail => {\n if (element && !detail.contains(element)) {\n detail.removeAttribute('open');\n } else if (!element) {\n detail.removeAttribute('open');\n }\n });\n };\n\n private toggleSidebar = () => {\n this.closeAllDetails();\n this.sidebarOpen = !this.sidebarOpen;\n };\n\n private handleToggle = (e: ToggleEvent) => {\n const { newState } = e;\n const target = e.currentTarget as HTMLDetailsElement;\n\n if (newState === 'open') {\n if (!this.sidebarOpen) {\n this.sidebarOpen = true;\n }\n\n this.closeAllDetails(target);\n }\n };\n\n private buildUrl = (path: string): string => {\n if (!this.clientKey) throw new Error('clientKey is required');\n\n const formattedPath = path.replace('$CLIENT_KEY', this.clientKey);\n if (!this.baseUrl) return formattedPath;\n\n return new URL(formattedPath, this.baseUrl).toString();\n };\n\n private onAnchorClick = (e: MouseEvent) => {\n if (this.navigate) {\n this.navigate(e);\n }\n };\n\n render() {\n return html`\n <nav id=${this.id} class=\"${this.sidebarOpen ? '' : 'sidebar-closed'}\">\n <div class=\"sidebar-header ${this.sidebarOpen ? '' : 'sidebar-closed'}\">\n <div class=\"logo\">\n ${unsafeSVG(tripteaseLogo)}\n </div>\n <button id=\"navbar-toggle-btn\" class=\"nav-item nav-toggle-button\" @click=${this.toggleSidebar}>\n ${unsafeSVG(sidebarCollapsed)}\n <span class=\"tooltip nav-toggle-tooltip\">\n ${unsafeSVG(sidebarCollapsed)}\n <span>Collapse sidebar</span>\n </span>\n </button>\n </div>\n\n <div class=\"nav-items ${this.sidebarOpen ? '' : 'sidebar-closed'}\">\n <a\n class=\"nav-item\"\n href=${this.buildUrl('/')}\n @click=${this.onAnchorClick}\n >${unsafeSVG(home)}<span>Dashboard</span></a\n >\n <a class=\"nav-item\" href=\"https://app.campaign-manager.triptease.io\"\n >${unsafeSVG(campaigns)}<span>Campaigns</span></a\n >\n <a\n class=\"nav-item\"\n href=${this.buildUrl('/channels')}\n @click=${this.onAnchorClick}\n >${unsafeSVG(channels)}<span>Channels</span></a\n >\n <details id=\"market-insights\" @toggle=${this.handleToggle}>\n <summary>\n ${unsafeSVG(graph)}\n <span>Market Insights</span>\n <span class=\"icon chevron\"> ${unsafeSVG(chevronDown)}</span>\n </summary>\n <div class=\"dropdown-items\">\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/parity/$CLIENT_KEY')}\n @click=${this.onAnchorClick}\n >Parity</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/guest-insights/$CLIENT_KEY')}\n @click=${this.onAnchorClick}\n >Guest insights</a\n >\n </div>\n </details>\n <details id=\"settings\" @toggle=${this.handleToggle}>\n <summary>\n ${unsafeSVG(gear)}\n <span>Settings</span>\n <span class=\"icon chevron\"> ${unsafeSVG(chevronDown)}</span>\n </summary>\n <div class=\"dropdown-items\">\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/$CLIENT_KEY/guest-behavioural-data')}\n @click=${this.onAnchorClick}\n >Email setup</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/$CLIENT_KEY/crm-config')}\n @click=${this.onAnchorClick}\n >CRM connectivity</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/settings/$CLIENT_KEY/guides')}\n @click=${this.onAnchorClick}\n >Group settings</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/settings/$CLIENT_KEY/hotels')}\n @click=${this.onAnchorClick}\n >Property settings</a\n >\n </div>\n </details>\n <hr />\n <details id=\"account\" @toggle=${this.handleToggle}>\n <summary>\n ${unsafeSVG(user)}\n <span>Account</span>\n <span class=\"icon chevron\"> ${unsafeSVG(chevronDown)}</span>\n </summary>\n <div class=\"dropdown-items\">\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/account')}\n @click=${this.onAnchorClick}\n >User settings</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/account/team/$CLIENT_KEY')}\n @click=${this.onAnchorClick}\n >Team and permissions</a\n >\n </div>\n </details>\n <details id=\"billing-routes\" @toggle=${this.handleToggle}>\n <summary>\n ${unsafeSVG(wallet)}\n <span>Billing</span>\n <span class=\"icon chevron\"> ${unsafeSVG(chevronDown)}</span>\n </summary>\n <div>\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/account/billing-management/$CLIENT_KEY')}\n @click=${this.onAnchorClick}\n >Booking reconciliation</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/subscriptions/$CLIENT_KEY')}\n @click=${this.onAnchorClick}\n >Subscriptions</a\n >\n </div>\n </details>\n </div>\n <div class=\"tertiary-nav ${this.sidebarOpen ? '' : 'sidebar-closed'}\">\n <div id=\"external-links\" class=\"nav-items\">\n <a\n class=\"nav-item external-link\"\n href='https://triptease.canny.io/feature-requests'\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Feature requests\n ${unsafeSVG(external)}\n </a>\n <a\n class='nav-item external-link'\n href='https://triptease.canny.io/changelog'\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Product updates\n ${unsafeSVG(external)}\n </a>\n <a\n class='nav-item external-link'\n href='https://help.triptease.com/'\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Help center\n ${unsafeSVG(external)}\n </a>\n <hr />\n </div>\n <div class='nav-items'>\n <slot id=\"client-selector\" name=\"clientSelector\"></slot>\n <a\n id=\"logout-link\"\n class=\"nav-item\"\n href=${this.buildUrl('/logout')}\n @click=${this.onAnchorClick}\n >${unsafeSVG(logout)}<span>Logout</span></a>\n </div>\n <div>\n </nav>\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"TtNavbar.js","sourceRoot":"","sources":["../../src/TtNavbar.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, LitElement } from 'lit';\nimport { property, queryAll, state } from 'lit/decorators.js';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport {\n campaigns,\n channels,\n chevronDown,\n gear,\n graph,\n home,\n logout,\n user,\n wallet,\n external,\n sidebarCollapsed,\n} from '@triptease/icons';\nimport { styles } from './styles.js';\nimport { tripteaseLogo } from './triptease-logo.js';\nimport { urlMappings } from './urlMappings.js';\n\nexport class TtNavbar extends LitElement {\n static styles = styles;\n\n @property({ type: Function })\n navigate: ((e: MouseEvent) => void) | undefined;\n\n @property({ type: String, attribute: 'campaign-manager-url' })\n campaignManagerUrl: string = 'https://app.campaign-manager.triptease.io';\n\n @property({ type: String, attribute: 'platform-url' })\n platformUrl?: string;\n\n @property({ type: String, attribute: 'client-key' })\n clientKey?: string;\n\n @queryAll('details')\n protected allDetailsElements!: Array<HTMLDetailsElement>;\n\n @queryAll('a')\n protected allNavLinks!: Array<HTMLAnchorElement>;\n\n @state()\n private sidebarOpen = true;\n\n protected firstUpdated() {\n this.setActiveState();\n }\n\n /*\n * Set the active state for the current page.\n *\n * This function iterates over all nav links and compares the current URL path with the href of each link.\n * If the current URL path starts with the href of a link, the link is marked as active. If multiple links\n * share the same prefix, the longest prefix is used as it is more specific.\n *\n * Example:\n * - Current URL: /channels/123\n * - Nav links:\n * - /channels\n * - /channels/123\n * - /channels/456\n *\n * Loop 1: currentPath = /channels/123, linkPath = /channels, bestMatch = /channels\n * Loop 2: currentPath = /channels/123, linkPath = /channels/123, bestMatch = /channels/123\n * Loop 3: currentPath = /channels/123, linkPath = /channels/456, bestMatch = /channels/123\n * Result: /channels/123 is marked as active\n *\n */\n private setActiveState = () => {\n const currentPath = window.location.pathname;\n\n let bestMatch: HTMLAnchorElement | undefined;\n let bestMatchLength = 0;\n\n // Check special cases first, as everything will always match on / and return Dashboard\n\n if (this.campaignManagerUrl.includes(window.location.host)) {\n const links = Object.values(this.allNavLinks);\n bestMatch = links.find(link =>\n link.href.includes(this.campaignManagerUrl),\n );\n }\n\n if (!bestMatch && this.clientKey) {\n const parsedPath = currentPath.replace(this.clientKey, '$CLIENT_KEY');\n const mappedUrl = urlMappings[parsedPath];\n\n if (mappedUrl) {\n const links = Object.values(this.allNavLinks);\n bestMatch = links.find(link => link.href.includes(mappedUrl));\n }\n }\n\n if (!bestMatch) {\n for (const link of this.allNavLinks) {\n link.classList.remove('current-page');\n if (link.hasAttribute('aria-current')) {\n link.attributes.removeNamedItem('aria-current');\n }\n\n const linkPath = new URL(link.href).pathname;\n\n if (currentPath.startsWith(linkPath)) {\n if (linkPath.length > bestMatchLength) {\n bestMatch = link;\n bestMatchLength = linkPath.length;\n }\n }\n }\n }\n\n if (bestMatch) {\n bestMatch.classList.add('current-page');\n bestMatch.setAttribute('aria-current', 'page');\n } else {\n console.error(`No matching nav link found for path: ${currentPath}`);\n }\n };\n\n private closeAllDetails = (element?: HTMLDetailsElement) => {\n this.allDetailsElements.forEach(detail => {\n if (element && !detail.contains(element)) {\n detail.removeAttribute('open');\n } else if (!element) {\n detail.removeAttribute('open');\n }\n });\n };\n\n private toggleSidebar = () => {\n this.closeAllDetails();\n this.sidebarOpen = !this.sidebarOpen;\n };\n\n private handleToggle = (e: ToggleEvent) => {\n const { newState } = e;\n const target = e.currentTarget as HTMLDetailsElement;\n\n if (newState === 'open') {\n if (!this.sidebarOpen) {\n this.sidebarOpen = true;\n }\n\n this.closeAllDetails(target);\n }\n };\n\n private buildUrl = (path: string): string => {\n if (!this.clientKey) throw new Error('clientKey is required');\n\n const formattedPath = path.replace('$CLIENT_KEY', this.clientKey);\n if (!this.platformUrl) return formattedPath;\n\n return new URL(formattedPath, this.platformUrl).toString();\n };\n\n private onAnchorClick = (e: MouseEvent) => {\n if (this.navigate) {\n this.navigate(e);\n this.setActiveState();\n }\n };\n\n render() {\n return html`\n <nav id=${this.id} class=\"${this.sidebarOpen ? '' : 'sidebar-closed'}\">\n <div class=\"sidebar-header ${this.sidebarOpen ? '' : 'sidebar-closed'}\">\n <div class=\"logo\">\n ${unsafeSVG(tripteaseLogo)}\n </div>\n <button id=\"navbar-toggle-btn\" class=\"nav-item nav-toggle-button\" @click=${this.toggleSidebar}>\n ${unsafeSVG(sidebarCollapsed)}\n <span class=\"tooltip nav-toggle-tooltip\">\n ${unsafeSVG(sidebarCollapsed)}\n <span>Collapse sidebar</span>\n </span>\n </button>\n </div>\n\n <div class=\"nav-items ${this.sidebarOpen ? '' : 'sidebar-closed'}\">\n <a\n class=\"nav-item\"\n href=${this.buildUrl('/')}\n @click=${this.onAnchorClick}\n >${unsafeSVG(home)}<span>Dashboard</span></a\n >\n <a class=\"nav-item\" href=${this.campaignManagerUrl}\n >${unsafeSVG(campaigns)}<span>Campaigns</span></a\n >\n <a\n class=\"nav-item\"\n href=${this.buildUrl('/channels')}\n @click=${this.onAnchorClick}\n >${unsafeSVG(channels)}<span>Channels</span></a\n >\n <details id=\"market-insights\" @toggle=${this.handleToggle}>\n <summary>\n ${unsafeSVG(graph)}\n <span>Market Insights</span>\n <span class=\"icon chevron\"> ${unsafeSVG(chevronDown)}</span>\n </summary>\n <div class=\"dropdown-items\">\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/parity/$CLIENT_KEY')}\n @click=${this.onAnchorClick}\n >Parity</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/guest-insights/$CLIENT_KEY')}\n @click=${this.onAnchorClick}\n >Guest insights</a\n >\n </div>\n </details>\n <details id=\"settings\" @toggle=${this.handleToggle}>\n <summary>\n ${unsafeSVG(gear)}\n <span>Settings</span>\n <span class=\"icon chevron\"> ${unsafeSVG(chevronDown)}</span>\n </summary>\n <div class=\"dropdown-items\">\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/$CLIENT_KEY/guest-behavioural-data')}\n @click=${this.onAnchorClick}\n >Email setup</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/$CLIENT_KEY/crm-config')}\n @click=${this.onAnchorClick}\n >CRM connectivity</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/settings/$CLIENT_KEY/guides')}\n @click=${this.onAnchorClick}\n >Group settings</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/settings/$CLIENT_KEY/hotels')}\n @click=${this.onAnchorClick}\n >Property settings</a\n >\n </div>\n </details>\n <hr />\n <details id=\"account\" @toggle=${this.handleToggle}>\n <summary>\n ${unsafeSVG(user)}\n <span>Account</span>\n <span class=\"icon chevron\"> ${unsafeSVG(chevronDown)}</span>\n </summary>\n <div class=\"dropdown-items\">\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/account')}\n @click=${this.onAnchorClick}\n >User settings</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/account/team/$CLIENT_KEY')}\n @click=${this.onAnchorClick}\n >Team and permissions</a\n >\n </div>\n </details>\n <details id=\"billing-routes\" @toggle=${this.handleToggle}>\n <summary>\n ${unsafeSVG(wallet)}\n <span>Billing</span>\n <span class=\"icon chevron\"> ${unsafeSVG(chevronDown)}</span>\n </summary>\n <div>\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/account/billing-management/$CLIENT_KEY')}\n @click=${this.onAnchorClick}\n >Booking reconciliation</a\n >\n <a\n class=\"sub-nav-item\"\n href=${this.buildUrl('/subscriptions/$CLIENT_KEY')}\n @click=${this.onAnchorClick}\n >Subscriptions</a\n >\n </div>\n </details>\n </div>\n <div class=\"tertiary-nav ${this.sidebarOpen ? '' : 'sidebar-closed'}\">\n <div id=\"external-links\" class=\"nav-items\">\n <a\n class=\"nav-item external-link\"\n href='https://triptease.canny.io/feature-requests'\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Feature requests\n ${unsafeSVG(external)}\n </a>\n <a\n class='nav-item external-link'\n href='https://triptease.canny.io/changelog'\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Product updates\n ${unsafeSVG(external)}\n </a>\n <a\n class='nav-item external-link'\n href='https://help.triptease.com/'\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Help center\n ${unsafeSVG(external)}\n </a>\n <hr />\n </div>\n <div class='nav-items'>\n <slot id=\"client-selector\" name=\"clientSelector\"></slot>\n <a\n id=\"logout-link\"\n class=\"nav-item\"\n href=${this.buildUrl('/logout')}\n @click=${this.onAnchorClick}\n >${unsafeSVG(logout)}<span>Logout</span></a>\n </div>\n <div>\n </nav>\n `;\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ type UrlMapping = Record<string, string>;
2
+ declare const urlMappings: UrlMapping;
3
+ export { urlMappings };
@@ -0,0 +1,11 @@
1
+ const urlMappings = {
2
+ '/paidsearch/$CLIENT_KEY/performance': '/channels',
3
+ '/meta/$CLIENT_KEY/performance': '/channels',
4
+ '/retargeting/$CLIENT_KEY/performance': '/channels',
5
+ '/messages/$CLIENT_KEY/messages': '/channels',
6
+ '/$CLIENT_KEY/email': '/channels',
7
+ '/pricematch/$CLIENT_KEY/performance': '/channels',
8
+ '/chat/insights/$CLIENT_KEY': '/channels',
9
+ };
10
+ export { urlMappings };
11
+ //# sourceMappingURL=urlMappings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urlMappings.js","sourceRoot":"","sources":["../../src/urlMappings.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAe;IAC9B,qCAAqC,EAAE,WAAW;IAClD,+BAA+B,EAAE,WAAW;IAC5C,sCAAsC,EAAE,WAAW;IACnD,gCAAgC,EAAE,WAAW;IAC7C,oBAAoB,EAAE,WAAW;IACjC,qCAAqC,EAAE,WAAW;IAClD,4BAA4B,EAAE,WAAW;CAC1C,CAAC;AAEF,OAAO,EAAE,WAAW,EAAE,CAAC","sourcesContent":["type UrlMapping = Record<string, string>;\n\nconst urlMappings: UrlMapping = {\n '/paidsearch/$CLIENT_KEY/performance': '/channels',\n '/meta/$CLIENT_KEY/performance': '/channels',\n '/retargeting/$CLIENT_KEY/performance': '/channels',\n '/messages/$CLIENT_KEY/messages': '/channels',\n '/$CLIENT_KEY/email': '/channels',\n '/pricematch/$CLIENT_KEY/performance': '/channels',\n '/chat/insights/$CLIENT_KEY': '/channels',\n};\n\nexport { urlMappings };\n"]}
@@ -6,7 +6,10 @@ export default {
6
6
  };
7
7
  const Template = () => html `
8
8
  <div>
9
- <tt-navbar client-key="zxd47KQGAP">
9
+ <tt-navbar
10
+ client-key="zxd47KQGAP"
11
+ campaign-manager-url="https://app.campaign-manager.triptease.io"
12
+ >
10
13
  <div slot="clientSelector">
11
14
  <p>My Cool Client Selector</p>
12
15
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"index.stories.js","sourceRoot":"","sources":["../../stories/index.stories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC3B,OAAO,qBAAqB,CAAC;AAE7B,eAAe;IACb,KAAK,EAAE,UAAU;IACjB,SAAS,EAAE,WAAW;CACvB,CAAC;AAEF,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,IAAI,CAAA;;;;;;;;CAQ1B,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC","sourcesContent":["import { html } from 'lit';\nimport '../src/tt-navbar.js';\n\nexport default {\n title: 'TtNavbar',\n component: 'tt-navbar',\n};\n\nconst Template = () => html`\n <div>\n <tt-navbar client-key=\"zxd47KQGAP\">\n <div slot=\"clientSelector\">\n <p>My Cool Client Selector</p>\n </div>\n </tt-navbar>\n </div>\n`;\n\nexport const Regular = Template.bind({});\n"]}
1
+ {"version":3,"file":"index.stories.js","sourceRoot":"","sources":["../../stories/index.stories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC3B,OAAO,qBAAqB,CAAC;AAE7B,eAAe;IACb,KAAK,EAAE,UAAU;IACjB,SAAS,EAAE,WAAW;CACvB,CAAC;AAEF,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,IAAI,CAAA;;;;;;;;;;;CAW1B,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC","sourcesContent":["import { html } from 'lit';\nimport '../src/tt-navbar.js';\n\nexport default {\n title: 'TtNavbar',\n component: 'tt-navbar',\n};\n\nconst Template = () => html`\n <div>\n <tt-navbar\n client-key=\"zxd47KQGAP\"\n campaign-manager-url=\"https://app.campaign-manager.triptease.io\"\n >\n <div slot=\"clientSelector\">\n <p>My Cool Client Selector</p>\n </div>\n </tt-navbar>\n </div>\n`;\n\nexport const Regular = Template.bind({});\n"]}
@@ -56,14 +56,14 @@ describe('TtNavbar', () => {
56
56
  }
57
57
  });
58
58
  it('should render platform URLs against the base URL when it is defined', async () => {
59
- const baseUrl = 'https://app.triptease.io';
60
- const navbar = await fixture(`<tt-navbar client-key=${CLIENT_KEY} base-url="${baseUrl}"></tt-navbar>`);
59
+ const platformUrl = 'https://app.triptease.io';
60
+ const navbar = await fixture(`<tt-navbar client-key=${CLIENT_KEY} platform-url="${platformUrl}"></tt-navbar>`);
61
61
  const links = navbar.shadowRoot?.querySelectorAll('a');
62
62
  if (links) {
63
- expect(getLinkByHref(links, `${baseUrl}/`)).to.exist;
63
+ expect(getLinkByHref(links, `${platformUrl}/`)).to.exist;
64
64
  expect(getLinkByHref(links, 'https://app.campaign-manager.triptease.io'))
65
65
  .to.exist; // This shouldn't change
66
- expect(getLinkByHref(links, `${baseUrl}/channels`)).to.exist;
66
+ expect(getLinkByHref(links, `${platformUrl}/channels`)).to.exist;
67
67
  }
68
68
  });
69
69
  it.skip('should allow navigation events to be handled externally', async () => {
@@ -165,6 +165,9 @@ describe('TtNavbar', () => {
165
165
  [`/parity/${CLIENT_KEY}`, 'Parity'],
166
166
  [`/parity/${CLIENT_KEY}`, 'Parity'],
167
167
  [`/parity/${CLIENT_KEY}/foo`, 'Parity'],
168
+ [`/meta/${CLIENT_KEY}/performance`, 'Channels'],
169
+ [`/chat/insights/${CLIENT_KEY}`, 'Channels'],
170
+ [`/${CLIENT_KEY}/email`, 'Channels'],
168
171
  ];
169
172
  URLs.forEach(([route, text]) => {
170
173
  it(`should show the current page as active when link is ${route}`, async () => {
@@ -176,5 +179,13 @@ describe('TtNavbar', () => {
176
179
  expect(anchor.textContent).to.include(text);
177
180
  });
178
181
  });
182
+ it('should show the current page as campaign manager when on the given campaign manager url', async () => {
183
+ const platformUrl = 'https://app.triptease.io';
184
+ const campaignManagerUrl = 'http://localhost:8000';
185
+ const navbar = await fixture(`<tt-navbar client-key=${CLIENT_KEY} platform-url=${platformUrl} campaign-manager-url=${campaignManagerUrl}></tt-navbar>`);
186
+ const anchor = navbar.shadowRoot.querySelector('a[aria-current="page"]');
187
+ expect(anchor).to.exist;
188
+ expect(anchor.textContent).to.include('Campaigns');
189
+ });
179
190
  });
180
191
  //# sourceMappingURL=tt-navbar.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tt-navbar.test.js","sourceRoot":"","sources":["../../test/tt-navbar.test.ts"],"names":[],"mappings":"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","sourcesContent":["import '../src/tt-navbar.js';\nimport {\n elementUpdated,\n expect,\n fixture,\n nextFrame,\n waitUntil,\n} from '@open-wc/testing';\nimport { TtNavbar } from '../src/index.js';\n\n// eslint-disable-next-line no-undef\nconst getLinkByHref = (links: NodeListOf<HTMLAnchorElement>, href: string) => {\n for (const link of links) {\n if (link.getAttribute('href') === href) {\n return link;\n }\n }\n\n return undefined;\n};\n\nconst isVisuallyHidden = (element: Element) => {\n const style = getComputedStyle(element);\n\n const result =\n style.position === 'absolute' &&\n style.width === '1px' &&\n style.height === '1px' &&\n style.margin === '-1px' &&\n style.padding === '0px' &&\n style.borderWidth === '0px' &&\n style.overflow === 'hidden' &&\n style.clip === 'rect(0px, 0px, 0px, 0px)' &&\n style.clipPath === 'inset(50%)' &&\n style.whiteSpace === 'nowrap';\n\n return result;\n};\n\nconst CLIENT_KEY = 'zxd47KQGAP';\n\ndescribe('TtNavbar', () => {\n it('should throw an error if the clientKey is not provided', async () => {\n try {\n await fixture<TtNavbar>(`<tt-navbar></tt-navbar>`);\n } catch (e) {\n expect(e).to.match(/clientKey is required/);\n }\n });\n it('should render with the default links', async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n const links = navbar.shadowRoot?.querySelectorAll('a');\n\n if (links) {\n expect(getLinkByHref(links, '/')).to.exist;\n expect(getLinkByHref(links, 'https://app.campaign-manager.triptease.io'))\n .to.exist;\n expect(getLinkByHref(links, '/channels')).to.exist;\n expect(getLinkByHref(links, `/parity/${CLIENT_KEY}`)).to.exist;\n expect(getLinkByHref(links, `/guest-insights/${CLIENT_KEY}`)).to.exist;\n expect(getLinkByHref(links, `/${CLIENT_KEY}/guest-behavioural-data`)).to\n .exist;\n expect(getLinkByHref(links, `/${CLIENT_KEY}/crm-config`)).to.exist;\n expect(getLinkByHref(links, `/settings/${CLIENT_KEY}/guides`)).to.exist;\n expect(getLinkByHref(links, `/settings/${CLIENT_KEY}/hotels`)).to.exist;\n expect(getLinkByHref(links, `/account`)).to.exist;\n expect(getLinkByHref(links, `/account/team/${CLIENT_KEY}`)).to.exist;\n expect(getLinkByHref(links, `/account/billing-management/${CLIENT_KEY}`))\n .to.exist;\n expect(getLinkByHref(links, `/subscriptions/${CLIENT_KEY}`)).to.exist;\n }\n });\n\n it('should render platform URLs against the base URL when it is defined', async () => {\n const baseUrl = 'https://app.triptease.io';\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY} base-url=\"${baseUrl}\"></tt-navbar>`,\n );\n const links = navbar.shadowRoot?.querySelectorAll('a');\n\n if (links) {\n expect(getLinkByHref(links, `${baseUrl}/`)).to.exist;\n expect(getLinkByHref(links, 'https://app.campaign-manager.triptease.io'))\n .to.exist; // This shouldn't change\n expect(getLinkByHref(links, `${baseUrl}/channels`)).to.exist;\n }\n });\n\n it.skip('should allow navigation events to be handled externally', async () => {\n let navigateEventCount = 0;\n\n const onNavigate = (e: MouseEvent) => {\n e.preventDefault();\n navigateEventCount += 1;\n };\n\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n navbar.navigate = onNavigate;\n await navbar.updateComplete;\n\n const links = navbar.shadowRoot?.querySelectorAll('a');\n links?.forEach(l => l.click());\n\n await waitUntil(\n () => expect(navigateEventCount).to.equal(13),\n 'navigate event did not fire',\n );\n });\n\n it('should render the given client selector', async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}><div slot=\"clientSelector\"><div id=\"myCoolClientSelector\"></div></div></tt-navbar>`,\n );\n\n const clientSelector = navbar.querySelector('#myCoolClientSelector');\n\n expect(clientSelector).to.exist;\n });\n\n it('should render the logout link', async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n\n const links = navbar.shadowRoot?.querySelectorAll('a');\n const logoutLink = getLinkByHref(links!, '/logout');\n\n expect(logoutLink).to.exist;\n });\n\n it('should close other details when one is being opened', async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n\n const allDetails = navbar.shadowRoot!.querySelectorAll('summary');\n const [marketInsights, settings] = allDetails;\n\n marketInsights.click();\n /*\n * Wait for the DOM to update before continuing. This is necessary because helpers like elementUpdated don't wait for\n * the browser to fire the $toggle handler as well as adding the open attribute.\n */\n await nextFrame();\n await nextFrame();\n\n expect(marketInsights.closest('details')?.open).to.be.true;\n\n settings.click();\n await nextFrame();\n await nextFrame();\n\n expect(settings.closest('details')?.open).to.be.true;\n expect(marketInsights.closest('details')?.open).to.be.false;\n });\n\n it('should collapse the navbar when toggle clicked', async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n\n const navbarToggleBtn = navbar.shadowRoot!.querySelector(\n '#navbar-toggle-btn',\n ) as HTMLButtonElement;\n\n navbarToggleBtn.click();\n await elementUpdated(navbar);\n\n const logo = navbar.shadowRoot!.querySelector('.logo');\n const rootLinksHiddenElements =\n navbar.shadowRoot!.querySelectorAll('nav a span');\n const summaryHiddenElements =\n navbar.shadowRoot!.querySelectorAll('nav summary span');\n const externalLinks =\n navbar.shadowRoot!.querySelectorAll('#external-links a');\n const logoutLink = navbar.shadowRoot!.querySelector('#logout-link span');\n const clientSelector = navbar.shadowRoot!.querySelector('#client-selector');\n\n // Visually and accessibly hidden\n expect(logo?.checkVisibility()).to.be.false;\n expect(clientSelector?.checkVisibility()).to.be.false;\n for (const link of externalLinks) {\n expect(link.checkVisibility()).to.be.false;\n }\n\n // Visually hidden only\n expect(logoutLink).to.exist;\n expect(rootLinksHiddenElements.length).to.be.greaterThan(1);\n expect(summaryHiddenElements.length).to.be.greaterThan(1);\n for (const element of [\n ...rootLinksHiddenElements,\n ...summaryHiddenElements,\n logoutLink!,\n ]) {\n expect(isVisuallyHidden(element)).to.be.true;\n }\n });\n\n const collapsibleIds: string[] = [\n 'market-insights',\n 'settings',\n 'account',\n 'billing-routes',\n ];\n collapsibleIds.forEach(id => {\n it(`should open the nav bar when the ${id} collapsible is clicked`, async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n\n const navbarToggleBtn = navbar.shadowRoot!.querySelector(\n '#navbar-toggle-btn',\n ) as HTMLButtonElement;\n\n navbarToggleBtn.click();\n await elementUpdated(navbar);\n\n const logo = navbar.shadowRoot!.querySelector('.logo');\n expect(logo?.checkVisibility()).to.be.false;\n\n const element: HTMLDetailsElement | null =\n navbar.shadowRoot!.querySelector(`#${id} summary`);\n\n expect(element).to.exist;\n\n element!.click();\n\n await waitUntil(() => logo?.checkVisibility(), 'navbar should be open', {\n timeout: 500,\n });\n });\n });\n\n const URLs = [\n ['/', 'Dashboard'],\n ['/channels', 'Channels'],\n [`/parity/${CLIENT_KEY}`, 'Parity'],\n [`/parity/${CLIENT_KEY}`, 'Parity'],\n [`/parity/${CLIENT_KEY}/foo`, 'Parity'],\n ];\n\n URLs.forEach(([route, text]) => {\n it(`should show the current page as active when link is ${route}`, async () => {\n // eslint-disable-next-line no-restricted-globals\n history.pushState({}, '', route); // 👈 mock URL\n\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n\n const anchor = navbar.shadowRoot!.querySelector('a[aria-current=\"page\"]');\n\n expect(anchor).to.exist;\n expect(anchor!.textContent).to.include(text);\n });\n });\n});\n"]}
1
+ {"version":3,"file":"tt-navbar.test.js","sourceRoot":"","sources":["../../test/tt-navbar.test.ts"],"names":[],"mappings":"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","sourcesContent":["import '../src/tt-navbar.js';\nimport {\n elementUpdated,\n expect,\n fixture,\n nextFrame,\n waitUntil,\n} from '@open-wc/testing';\nimport { TtNavbar } from '../src/index.js';\n\n// eslint-disable-next-line no-undef\nconst getLinkByHref = (links: NodeListOf<HTMLAnchorElement>, href: string) => {\n for (const link of links) {\n if (link.getAttribute('href') === href) {\n return link;\n }\n }\n\n return undefined;\n};\n\nconst isVisuallyHidden = (element: Element) => {\n const style = getComputedStyle(element);\n\n const result =\n style.position === 'absolute' &&\n style.width === '1px' &&\n style.height === '1px' &&\n style.margin === '-1px' &&\n style.padding === '0px' &&\n style.borderWidth === '0px' &&\n style.overflow === 'hidden' &&\n style.clip === 'rect(0px, 0px, 0px, 0px)' &&\n style.clipPath === 'inset(50%)' &&\n style.whiteSpace === 'nowrap';\n\n return result;\n};\n\nconst CLIENT_KEY = 'zxd47KQGAP';\n\ndescribe('TtNavbar', () => {\n it('should throw an error if the clientKey is not provided', async () => {\n try {\n await fixture<TtNavbar>(`<tt-navbar></tt-navbar>`);\n } catch (e) {\n expect(e).to.match(/clientKey is required/);\n }\n });\n it('should render with the default links', async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n const links = navbar.shadowRoot?.querySelectorAll('a');\n\n if (links) {\n expect(getLinkByHref(links, '/')).to.exist;\n expect(getLinkByHref(links, 'https://app.campaign-manager.triptease.io'))\n .to.exist;\n expect(getLinkByHref(links, '/channels')).to.exist;\n expect(getLinkByHref(links, `/parity/${CLIENT_KEY}`)).to.exist;\n expect(getLinkByHref(links, `/guest-insights/${CLIENT_KEY}`)).to.exist;\n expect(getLinkByHref(links, `/${CLIENT_KEY}/guest-behavioural-data`)).to\n .exist;\n expect(getLinkByHref(links, `/${CLIENT_KEY}/crm-config`)).to.exist;\n expect(getLinkByHref(links, `/settings/${CLIENT_KEY}/guides`)).to.exist;\n expect(getLinkByHref(links, `/settings/${CLIENT_KEY}/hotels`)).to.exist;\n expect(getLinkByHref(links, `/account`)).to.exist;\n expect(getLinkByHref(links, `/account/team/${CLIENT_KEY}`)).to.exist;\n expect(getLinkByHref(links, `/account/billing-management/${CLIENT_KEY}`))\n .to.exist;\n expect(getLinkByHref(links, `/subscriptions/${CLIENT_KEY}`)).to.exist;\n }\n });\n\n it('should render platform URLs against the base URL when it is defined', async () => {\n const platformUrl = 'https://app.triptease.io';\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY} platform-url=\"${platformUrl}\"></tt-navbar>`,\n );\n const links = navbar.shadowRoot?.querySelectorAll('a');\n\n if (links) {\n expect(getLinkByHref(links, `${platformUrl}/`)).to.exist;\n expect(getLinkByHref(links, 'https://app.campaign-manager.triptease.io'))\n .to.exist; // This shouldn't change\n expect(getLinkByHref(links, `${platformUrl}/channels`)).to.exist;\n }\n });\n\n it.skip('should allow navigation events to be handled externally', async () => {\n let navigateEventCount = 0;\n\n const onNavigate = (e: MouseEvent) => {\n e.preventDefault();\n navigateEventCount += 1;\n };\n\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n navbar.navigate = onNavigate;\n await navbar.updateComplete;\n\n const links = navbar.shadowRoot?.querySelectorAll('a');\n links?.forEach(l => l.click());\n\n await waitUntil(\n () => expect(navigateEventCount).to.equal(13),\n 'navigate event did not fire',\n );\n });\n\n it('should render the given client selector', async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}><div slot=\"clientSelector\"><div id=\"myCoolClientSelector\"></div></div></tt-navbar>`,\n );\n\n const clientSelector = navbar.querySelector('#myCoolClientSelector');\n\n expect(clientSelector).to.exist;\n });\n\n it('should render the logout link', async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n\n const links = navbar.shadowRoot?.querySelectorAll('a');\n const logoutLink = getLinkByHref(links!, '/logout');\n\n expect(logoutLink).to.exist;\n });\n\n it('should close other details when one is being opened', async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n\n const allDetails = navbar.shadowRoot!.querySelectorAll('summary');\n const [marketInsights, settings] = allDetails;\n\n marketInsights.click();\n /*\n * Wait for the DOM to update before continuing. This is necessary because helpers like elementUpdated don't wait for\n * the browser to fire the $toggle handler as well as adding the open attribute.\n */\n await nextFrame();\n await nextFrame();\n\n expect(marketInsights.closest('details')?.open).to.be.true;\n\n settings.click();\n await nextFrame();\n await nextFrame();\n\n expect(settings.closest('details')?.open).to.be.true;\n expect(marketInsights.closest('details')?.open).to.be.false;\n });\n\n it('should collapse the navbar when toggle clicked', async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n\n const navbarToggleBtn = navbar.shadowRoot!.querySelector(\n '#navbar-toggle-btn',\n ) as HTMLButtonElement;\n\n navbarToggleBtn.click();\n await elementUpdated(navbar);\n\n const logo = navbar.shadowRoot!.querySelector('.logo');\n const rootLinksHiddenElements =\n navbar.shadowRoot!.querySelectorAll('nav a span');\n const summaryHiddenElements =\n navbar.shadowRoot!.querySelectorAll('nav summary span');\n const externalLinks =\n navbar.shadowRoot!.querySelectorAll('#external-links a');\n const logoutLink = navbar.shadowRoot!.querySelector('#logout-link span');\n const clientSelector = navbar.shadowRoot!.querySelector('#client-selector');\n\n // Visually and accessibly hidden\n expect(logo?.checkVisibility()).to.be.false;\n expect(clientSelector?.checkVisibility()).to.be.false;\n for (const link of externalLinks) {\n expect(link.checkVisibility()).to.be.false;\n }\n\n // Visually hidden only\n expect(logoutLink).to.exist;\n expect(rootLinksHiddenElements.length).to.be.greaterThan(1);\n expect(summaryHiddenElements.length).to.be.greaterThan(1);\n for (const element of [\n ...rootLinksHiddenElements,\n ...summaryHiddenElements,\n logoutLink!,\n ]) {\n expect(isVisuallyHidden(element)).to.be.true;\n }\n });\n\n const collapsibleIds: string[] = [\n 'market-insights',\n 'settings',\n 'account',\n 'billing-routes',\n ];\n collapsibleIds.forEach(id => {\n it(`should open the nav bar when the ${id} collapsible is clicked`, async () => {\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n\n const navbarToggleBtn = navbar.shadowRoot!.querySelector(\n '#navbar-toggle-btn',\n ) as HTMLButtonElement;\n\n navbarToggleBtn.click();\n await elementUpdated(navbar);\n\n const logo = navbar.shadowRoot!.querySelector('.logo');\n expect(logo?.checkVisibility()).to.be.false;\n\n const element: HTMLDetailsElement | null =\n navbar.shadowRoot!.querySelector(`#${id} summary`);\n\n expect(element).to.exist;\n\n element!.click();\n\n await waitUntil(() => logo?.checkVisibility(), 'navbar should be open', {\n timeout: 500,\n });\n });\n });\n\n const URLs = [\n ['/', 'Dashboard'],\n ['/channels', 'Channels'],\n [`/parity/${CLIENT_KEY}`, 'Parity'],\n [`/parity/${CLIENT_KEY}`, 'Parity'],\n [`/parity/${CLIENT_KEY}/foo`, 'Parity'],\n [`/meta/${CLIENT_KEY}/performance`, 'Channels'],\n [`/chat/insights/${CLIENT_KEY}`, 'Channels'],\n [`/${CLIENT_KEY}/email`, 'Channels'],\n ];\n\n URLs.forEach(([route, text]) => {\n it(`should show the current page as active when link is ${route}`, async () => {\n // eslint-disable-next-line no-restricted-globals\n history.pushState({}, '', route); // 👈 mock URL\n\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY}></tt-navbar>`,\n );\n\n const anchor = navbar.shadowRoot!.querySelector('a[aria-current=\"page\"]');\n\n expect(anchor).to.exist;\n expect(anchor!.textContent).to.include(text);\n });\n });\n\n it('should show the current page as campaign manager when on the given campaign manager url', async () => {\n const platformUrl = 'https://app.triptease.io';\n const campaignManagerUrl = 'http://localhost:8000';\n\n const navbar = await fixture<TtNavbar>(\n `<tt-navbar client-key=${CLIENT_KEY} platform-url=${platformUrl} campaign-manager-url=${campaignManagerUrl}></tt-navbar>`,\n );\n const anchor = navbar.shadowRoot!.querySelector('a[aria-current=\"page\"]');\n expect(anchor).to.exist;\n expect(anchor!.textContent).to.include('Campaigns');\n });\n});\n"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @triptease/tt-navbar v0.0.18
2
+ * @triptease/tt-navbar v0.0.20
3
3
  */
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1059,10 +1059,22 @@ var tripteaseLogo = `<svg width="112" height="32" viewBox="0 0 112 32" fill="no
1059
1059
  </defs>
1060
1060
  </svg>`;
1061
1061
 
1062
+ // src/urlMappings.ts
1063
+ var urlMappings = {
1064
+ "/paidsearch/$CLIENT_KEY/performance": "/channels",
1065
+ "/meta/$CLIENT_KEY/performance": "/channels",
1066
+ "/retargeting/$CLIENT_KEY/performance": "/channels",
1067
+ "/messages/$CLIENT_KEY/messages": "/channels",
1068
+ "/$CLIENT_KEY/email": "/channels",
1069
+ "/pricematch/$CLIENT_KEY/performance": "/channels",
1070
+ "/chat/insights/$CLIENT_KEY": "/channels"
1071
+ };
1072
+
1062
1073
  // src/TtNavbar.ts
1063
1074
  var TtNavbar = class extends i4 {
1064
1075
  constructor() {
1065
1076
  super(...arguments);
1077
+ this.campaignManagerUrl = "https://app.campaign-manager.triptease.io";
1066
1078
  this.sidebarOpen = true;
1067
1079
  /*
1068
1080
  * Set the active state for the current page.
@@ -1088,22 +1100,40 @@ var TtNavbar = class extends i4 {
1088
1100
  const currentPath = window.location.pathname;
1089
1101
  let bestMatch;
1090
1102
  let bestMatchLength = 0;
1091
- for (const link of this.allNavLinks) {
1092
- link.classList.remove("current-page");
1093
- if (link.hasAttribute("aria-current")) {
1094
- link.attributes.removeNamedItem("aria-current");
1103
+ if (this.campaignManagerUrl.includes(window.location.host)) {
1104
+ const links = Object.values(this.allNavLinks);
1105
+ bestMatch = links.find(
1106
+ (link) => link.href.includes(this.campaignManagerUrl)
1107
+ );
1108
+ }
1109
+ if (!bestMatch && this.clientKey) {
1110
+ const parsedPath = currentPath.replace(this.clientKey, "$CLIENT_KEY");
1111
+ const mappedUrl = urlMappings[parsedPath];
1112
+ if (mappedUrl) {
1113
+ const links = Object.values(this.allNavLinks);
1114
+ bestMatch = links.find((link) => link.href.includes(mappedUrl));
1095
1115
  }
1096
- const linkPath = new URL(link.href).pathname;
1097
- if (currentPath.startsWith(linkPath)) {
1098
- if (linkPath.length > bestMatchLength) {
1099
- bestMatch = link;
1100
- bestMatchLength = linkPath.length;
1116
+ }
1117
+ if (!bestMatch) {
1118
+ for (const link of this.allNavLinks) {
1119
+ link.classList.remove("current-page");
1120
+ if (link.hasAttribute("aria-current")) {
1121
+ link.attributes.removeNamedItem("aria-current");
1122
+ }
1123
+ const linkPath = new URL(link.href).pathname;
1124
+ if (currentPath.startsWith(linkPath)) {
1125
+ if (linkPath.length > bestMatchLength) {
1126
+ bestMatch = link;
1127
+ bestMatchLength = linkPath.length;
1128
+ }
1101
1129
  }
1102
1130
  }
1103
1131
  }
1104
1132
  if (bestMatch) {
1105
1133
  bestMatch.classList.add("current-page");
1106
1134
  bestMatch.setAttribute("aria-current", "page");
1135
+ } else {
1136
+ console.error(`No matching nav link found for path: ${currentPath}`);
1107
1137
  }
1108
1138
  };
1109
1139
  this.closeAllDetails = (element) => {
@@ -1132,12 +1162,13 @@ var TtNavbar = class extends i4 {
1132
1162
  this.buildUrl = (path) => {
1133
1163
  if (!this.clientKey) throw new Error("clientKey is required");
1134
1164
  const formattedPath = path.replace("$CLIENT_KEY", this.clientKey);
1135
- if (!this.baseUrl) return formattedPath;
1136
- return new URL(formattedPath, this.baseUrl).toString();
1165
+ if (!this.platformUrl) return formattedPath;
1166
+ return new URL(formattedPath, this.platformUrl).toString();
1137
1167
  };
1138
1168
  this.onAnchorClick = (e8) => {
1139
1169
  if (this.navigate) {
1140
1170
  this.navigate(e8);
1171
+ this.setActiveState();
1141
1172
  }
1142
1173
  };
1143
1174
  }
@@ -1167,7 +1198,7 @@ var TtNavbar = class extends i4 {
1167
1198
  @click=${this.onAnchorClick}
1168
1199
  >${o7(home)}<span>Dashboard</span></a
1169
1200
  >
1170
- <a class="nav-item" href="https://app.campaign-manager.triptease.io"
1201
+ <a class="nav-item" href=${this.campaignManagerUrl}
1171
1202
  >${o7(campaigns)}<span>Campaigns</span></a
1172
1203
  >
1173
1204
  <a
@@ -1324,8 +1355,11 @@ __decorateClass([
1324
1355
  n4({ type: Function })
1325
1356
  ], TtNavbar.prototype, "navigate", 2);
1326
1357
  __decorateClass([
1327
- n4({ type: String, attribute: "base-url" })
1328
- ], TtNavbar.prototype, "baseUrl", 2);
1358
+ n4({ type: String, attribute: "campaign-manager-url" })
1359
+ ], TtNavbar.prototype, "campaignManagerUrl", 2);
1360
+ __decorateClass([
1361
+ n4({ type: String, attribute: "platform-url" })
1362
+ ], TtNavbar.prototype, "platformUrl", 2);
1329
1363
  __decorateClass([
1330
1364
  n4({ type: String, attribute: "client-key" })
1331
1365
  ], TtNavbar.prototype, "clientKey", 2);