Repository: department-of-veterans-affairs/next-build
Pull request #980: VACMS-19861: Lovell Left Nav Bar Link Defect Fix
Author: login: moanu404
Created: 2025-04-16T21:09:50Z | Merged: 2025-04-24T16:08:35Z

# Description
This PR addresses a bug where some of the left nav links under "About Us" are linking to Lovell VA pages instead of TRICARE. These need to route to VA or TRICARE depending on what variant the end user is viewing for these sidebar links 

- About Us
- Programs
- Work With us

## Generated description

This pull request introduces functionality to handle Lovell facility-specific URL transformations for TRICARE and VA variants across the `StoryListing` and `SideNav` components. It also includes testing to ensure the correct handling of these variants. The most important changes are grouped below by theme.

### Feature Enhancements for Lovell Facility Handling:

* Updated `buildSideNavDataFromMenu` in `src/lib/drupal/facilitySideNav.ts` to support Lovell variant-specific URL transformations by introducing an optional `variant` parameter and modifying the `normalizeMenuItem` and `normalizeMenuData` functions to handle URL adjustments. [[1]](diffhunk://#diff-c931cad709f1a1e5fd69c51a9a3714ed71cc1f6c10bf9fcd4fa573fa2f430bbcR7-R41) [[2]](diffhunk://#diff-c931cad709f1a1e5fd69c51a9a3714ed71cc1f6c10bf9fcd4fa573fa2f430bbcL46-R59)
* Enhanced `formatter` in `src/data/queries/storyListing.ts` to detect Lovell TRICARE and VA variants based on the entity path and pass the variant to `buildSideNavDataFromMenu`.

### Unit Tests for Lovell Variants:

* Added comprehensive tests in `src/lib/drupal/facilitySideNav.test.ts` to validate URL transformations for TRICARE and VA variants, non-variant cases, and recursive handling of nested menu items.
* Expanded `src/data/queries/tests/storyListing.test.tsx` to include tests for the `formatter` function's ability to detect Lovell variants and correctly format menus based on the path.

### Refactoring and Mocking:

* Introduced a custom `CustomMenuLinkContent` type in `src/lib/drupal/facilitySideNav.test.ts` to simplify testing by extending `DrupalMenuLinkContent` with additional fields. [[1]](diffhunk://#diff-64b406a947e965af27489ff15bc2b2f788fe46756660cb3937cabbd9dc71e424L1-R12) [[2]](diffhunk://#diff-64b406a947e965af27489ff15bc2b2f788fe46756660cb3937cabbd9dc71e424R26-R38)
* Mocked the `formatter` and `queries` modules in `src/data/queries/tests/storyListing.test.tsx` to simulate dependencies and isolate test cases. [[1]](diffhunk://#diff-2ff6228210e973b91ba4010907157884748531b162dfd498fb83faa7bccc6988R9-R12) [[2]](diffhunk://#diff-2ff6228210e973b91ba4010907157884748531b162dfd498fb83faa7bccc6988R45-R61)
## Ticket

Closes [19861](https://github.com/department-of-veterans-affairs/va.gov-cms/issues/19861)

## Developer Task

```md
- [ ] PR submitted against the `main` branch of `next-build`.
- [ ] Link to the issue that this PR addresses (if applicable).
- [ ] Define all changes in your PR and note any changes that could potentially be breaking changes.
- [ ] PR includes steps to test your changes and links to these changes in the Tugboat preview (if applicable).
- [ ] Provided before and after screenshots of your changes (if applicable).
- [ ] Alerted the #next-build Slack channel to request a PR review.
- [ ] You understand that once approved, you are responsible for merging your changes into `main`. (Note that changes to `main` will move automatically into production.)
```

## Testing Steps

- [ ] Load up local server
- [ ] Go to http://localhost:3999/lovell-federal-health-care-tricare/stories/
- [ ] Ensure `About Us, Programs, Work With us` on the sidebar navigate to a tricare URL like http://localhost:3999/lovell-federal-health-care-tricare/about-us
- [ ] View the same page as a VA beneficiary and ensure the navigation is VA on the sidebar links
- [ ] Also test http://localhost:3999/boston-health-care/stories/ just to be sure
- [ ] Test on tugboat 
- [ ] Run unit tests

## QA steps
Click the sidebar links on a lot of facilities/tricare/va pages!
## Screenshots (see the link on the bottom left) 
Before:
<img width="1250" alt="image" src="https://github.com/user-attachments/assets/3e9725ab-431c-4ab0-903a-ce3f5c116484" />
<img width="1273" alt="image" src="https://github.com/user-attachments/assets/ccdf9f04-b533-4506-91ed-3f04bd506317" />
<img width="1443" alt="image" src="https://github.com/user-attachments/assets/b1a239f8-fded-4b63-adac-7489f9dd978f" />

After:
<img width="1409" alt="image" src="https://github.com/user-attachments/assets/691f2423-d036-4f12-95f4-0d43b4a95cfd" />
<img width="1346" alt="image" src="https://github.com/user-attachments/assets/ccac55f2-6d87-42c3-a6ca-259ce72c83c2" />
<img width="1342" alt="image" src="https://github.com/user-attachments/assets/0036df9c-22a7-4950-acff-15e209be3a9a" />

## Is this PR blocked by another PR? - No

- Add the `DO NOT MERGE` label
- Add links to additional PRs here:

---

## Reviewer

### Reviewing a PR

This section lists items that need to be checked or updated when making changes to this repository.

## Standard Checks

```md
- [ ] Code Quality: Readabilty, Naming Conventions, Consistency, Reusability
- [ ] Test Coverage: 80% coverage
- [ ] Functionality: Change functions as expected with no additional bugs
- [ ] Performance: Code does not introduce performance issues
- [ ] Documentation: Changes are documented in their respective README.md files
- [ ] Security: Packages have been approved in the TRM
```

## Merging a Layout

When merging a layout, you must ensure that the content type has been turned on for `next-build` in the [.tugboat.env](../envs/.tugboat.env). This method mocks the CMS flag that must be turned on for a layout to be included in the build.

The layout component and matching resource type should be included in the [slug.tsx](../src/pages/[[...slug]].tsx), so that it can reviewed. Including a component in the slug.tsx does not mean a page will be viewable in production only on the tugboat for the branch.

When a layout is merged to main and approved for deployment, the prod CMS will turn the toggle on for the resource type. 

The status of layouts should be kept up to date inside [templates.md](../READMEs/templates.md). This includes QA progress, development progress, etc. A link should be provided for where testing can occur.


Diff:
diff --git a/src/data/queries/storyListing.ts b/src/data/queries/storyListing.ts
index 18fa16b32..63476abe5 100644
--- a/src/data/queries/storyListing.ts
+++ b/src/data/queries/storyListing.ts
@@ -8,6 +8,8 @@ import { buildSideNavDataFromMenu } from '@/lib/drupal/facilitySideNav'
 import { ListingPageDataOpts } from '@/lib/drupal/listingPages'
 import { RESOURCE_TYPES } from '@/lib/constants/resourceTypes'
 import { PAGE_SIZES } from '@/lib/constants/pageSizes'
+import { LOVELL } from '@/lib/drupal/lovell/constants'
+import { isLovellTricarePath, isLovellVaPath } from '@/lib/drupal/lovell/utils'
 import {
   fetchAndConcatAllResourceCollectionPages,
   fetchSingleResourceCollectionPage,
@@ -97,7 +99,18 @@ export const formatter: QueryFormatter<StoryListingData, StoryListing> = ({
     return queries.formatData(`${RESOURCE_TYPES.STORY}--teaser`, story)
   })
 
-  const formattedMenu = buildSideNavDataFromMenu(entity.path.alias, menu)
+  // Check if this is a Lovell facility page (TRICARE or VA variant)
+  let variant = undefined
+  if (isLovellTricarePath(entity.path.alias)) {
+    variant = LOVELL.tricare.variant
+  } else if (isLovellVaPath(entity.path.alias)) {
+    variant = LOVELL.va.variant
+  }
+  const formattedMenu = buildSideNavDataFromMenu(
+    entity.path.alias,
+    menu,
+    variant
+  )
 
   return {
     ...entityBaseFields(entity),
diff --git a/src/data/queries/tests/storyListing.test.tsx b/src/data/queries/tests/storyListing.test.tsx
index 42357373e..c811ece89 100644
--- a/src/data/queries/tests/storyListing.test.tsx
+++ b/src/data/queries/tests/storyListing.test.tsx
@@ -6,6 +6,7 @@ import {
   params as storyListingParams,
   listingParams,
   data,
+  formatter,
 } from '../storyListing'
 import * as queryModule from '@/lib/drupal/query'
 
@@ -40,6 +41,23 @@ jest.mock('@/lib/drupal/query', () => {
   }
 })
 
+// mocking the queries object to return a mock params object
+jest.mock('..', () => {
+  const mockParams = {
+    addFilter: jest.fn().mockReturnThis(),
+    addSort: jest.fn().mockReturnThis(),
+    getQueryString: jest
+      .fn()
+      .mockReturnValue('filter[field_listing.id]=123&sort=-created'),
+  }
+  return {
+    queries: {
+      getParams: jest.fn().mockReturnValue(mockParams),
+    },
+    formatData: jest.fn().mockReturnValue({}),
+  }
+})
+
 describe('data function for StoryListing', () => {
   test('invokes data function with mocked dependencies', async () => {
     const opts = { id: 'test-id' }
@@ -79,4 +97,197 @@ describe('data function for StoryListing', () => {
       expect(queryString).toContain('sort=-created')
     })
   })
+
+  describe('formatter variant detection and menu handling', () => {
+    const mockData = {
+      entity: {
+        id: 'test-id',
+        type: 'node--story_listing',
+        langcode: 'en',
+        status: true,
+        drupal_internal__nid: 123,
+        drupal_internal__vid: 456,
+        created: '2024-01-01',
+        changed: '2024-01-02',
+        title: 'Test Story Listing',
+        path: {
+          alias: '/test-story',
+          pid: 1,
+          langcode: 'en',
+          severity: 0,
+        },
+        field_description: 'Test description',
+        field_intro_text: 'Test intro',
+        field_office: {
+          id: '1',
+          type: 'node--health_care_region_page',
+          langcode: 'en',
+          status: true,
+          drupal_internal__nid: 1,
+          drupal_internal__vid: 1,
+          created: '2020-01-01',
+          changed: '2020-01-01',
+          title: 'Test Office',
+          path: {
+            alias: '/test-path',
+            pid: 1,
+            langcode: 'en',
+            severity: 1,
+          },
+          field_description: 'Test Description',
+          field_intro_text: 'Test Intro Text',
+          field_vamc_system_official_name: 'Test Office',
+          field_appointments_online: null,
+          field_media: null,
+          field_related_links: {
+            id: '1',
+            field_link: null,
+            field_links: [],
+            field_section_header: null,
+            drupal_internal__id: 1,
+            drupal_internal__revision_id: 1,
+            langcode: 'en',
+            status: true,
+            created: '2020-01-01',
+            parent_id: null,
+            parent_type: null,
+            parent_field_name: null,
+            behavior_settings: [],
+            default_langcode: true,
+            revision_translation_affected: true,
+            type: 'paragraph--list_of_links',
+          },
+          field_vamc_ehr_system: null,
+          field_facebook: null,
+          field_flickr: null,
+          field_instagram: null,
+          field_locations_intro_blurb: null,
+          field_operating_status_emerg: null,
+          field_operating_status_more_info: null,
+          field_twitter: null,
+          field_youtube: null,
+          field_operating_status: null,
+          field_region_page: null,
+          field_banner_alert: null,
+          field_govdelivery_id_emerg: null,
+          field_govdelivery_id_news: null,
+          field_other_va_locations: null,
+          field_clinical_health_services: [],
+          field_mental_health_services: [],
+          field_specialty_care_services: [],
+          field_va_health_connect_phone: null,
+          default_langcode: true,
+          sticky: false,
+        },
+        metatag: [],
+        default_langcode: true,
+        sticky: false,
+      },
+      stories: [],
+      menu: {
+        items: [
+          {
+            title: 'Test Menu Item',
+            description: 'Test Description',
+            expanded: true,
+            url: '/test-url',
+            items: [],
+            enabled: true,
+            id: 'test-menu-item-id',
+            menu_name: 'test-menu',
+            meta: {
+              entity_id: '1',
+              entity_type: 'menu_link_content',
+              entity_uuid: 'test-uuid',
+            },
+            parent: '',
+            provider: 'menu_link_content',
+            route_name: 'entity.node.canonical',
+            weight: '0',
+            options: {},
+            route: {
+              name: 'entity.node.canonical',
+              parameters: {},
+            },
+            type: 'menu_link_content',
+            severity: 0,
+          },
+        ],
+        tree: [
+          {
+            title: 'Test Menu Item',
+            description: 'Test Description',
+            expanded: true,
+            url: '/test-url',
+            items: [],
+            enabled: true,
+            id: 'test-menu-item-id',
+            menu_name: 'test-menu',
+            meta: {
+              entity_id: '1',
+              entity_type: 'menu_link_content',
+              entity_uuid: 'test-uuid',
+            },
+            parent: '',
+            provider: 'menu_link_content',
+            route_name: 'entity.node.canonical',
+            weight: '0',
+            options: {},
+            route: {
+              name: 'entity.node.canonical',
+              parameters: {},
+            },
+            type: 'menu_link_content',
+            severity: 0,
+          },
+        ],
+      },
+      totalItems: 0,
+      totalPages: 0,
+      current: 1,
+    }
+
+    test('detects TRICARE variant from path', () => {
+      const tricareData = {
+        ...mockData,
+        entity: {
+          ...mockData.entity,
+          path: {
+            alias: '/lovell-federal-health-care-tricare/stories',
+            pid: 1,
+            langcode: 'en',
+            severity: 0,
+          },
+        },
+      }
+      const result = formatter(tricareData)
+      expect(result.menu.rootPath).toBe(
+        '/lovell-federal-health-care-tricare/stories/'
+      )
+    })
+
+    test('detects VA variant from path', () => {
+      const vaData = {
+        ...mockData,
+        entity: {
+          ...mockData.entity,
+          path: {
+            alias: '/lovell-federal-health-care-va/stories',
+            pid: 1,
+            langcode: 'en',
+            severity: 0,
+          },
+        },
+      }
+      const result = formatter(vaData)
+      expect(result.menu.rootPath).toBe(
+        '/lovell-federal-health-care-va/stories/'
+      )
+    })
+
+    test('handles non-Lovell paths without transformation', () => {
+      const result = formatter(mockData)
+      expect(result.menu.rootPath).toBe('/test-story/')
+    })
+  })
 })
diff --git a/src/lib/drupal/facilitySideNav.test.ts b/src/lib/drupal/facilitySideNav.test.ts
index 1e4f93e4b..9bdb8aac8 100644
--- a/src/lib/drupal/facilitySideNav.test.ts
+++ b/src/lib/drupal/facilitySideNav.test.ts
@@ -1,6 +1,8 @@
-import { buildSideNavDataFromMenu } from './facilitySideNav' // Adjust the import path as necessary
+import { buildSideNavDataFromMenu } from './facilitySideNav'
 import { Menu } from '@/types/drupal/menu'
 import { SideNavMenu } from '@/types/formatted/sideNav'
+import { LOVELL } from './lovell/constants'
+import { LovellVariant } from './lovell/types'
 
 const mockMenu: Partial<Menu> = {
   items: [],
@@ -14,6 +16,17 @@ const mockMenu: Partial<Menu> = {
       enabled: true,
       field_menu_section: 'Test Section',
       items: [], // Assuming it's a flat structure for simplicity
+      menu_name: 'test-menu',
+      provider: 'menu_link_content',
+      weight: '0',
+      options: {},
+      route: {
+        name: 'entity.node.canonical',
+        parameters: {},
+      },
+      type: 'menu_link_content',
+      meta: {},
+      parent: '',
     },
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
   ] as any[], // Use 'any[]' to bypass detailed type requirements
@@ -44,4 +57,112 @@ describe('SideNav Data Building Function', () => {
 
     expect(sideNavData.data).toBeNull()
   })
+
+  describe('Lovell variant URL transformation', () => {
+    const lovellMenu: Partial<Menu> = {
+      items: [],
+      tree: [
+        {
+          id: '1',
+          url: '/lovell-federal-health-care/stories',
+          title: 'Test Title',
+          description: 'Test Description',
+          expanded: true,
+          enabled: true,
+          field_menu_section: 'Test Section',
+          items: [
+            {
+              id: '2',
+              url: '/lovell-federal-health-care/news',
+              title: 'Nested Item',
+              description: 'Nested Description',
+              expanded: false,
+              enabled: true,
+              field_menu_section: null,
+              items: [],
+              menu_name: 'test-menu',
+              provider: 'menu_link_content',
+              weight: '0',
+              options: {},
+              route: {
+                name: 'entity.node.canonical',
+                parameters: {},
+              },
+              type: 'menu_link_content',
+              meta: {},
+              parent: '',
+            },
+          ],
+          menu_name: 'test-menu',
+          provider: 'menu_link_content',
+          weight: '0',
+          options: {},
+          route: {
+            name: 'entity.node.canonical',
+            parameters: {},
+          },
+          type: 'menu_link_content',
+          meta: {},
+          parent: '',
+        },
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
+      ] as any[], // Use 'any[]' to bypass detailed type requirements
+    }
+
+    it('transforms URLs for TRICARE variant', () => {
+      const sideNavData = buildSideNavDataFromMenu(
+        '/test-path',
+        lovellMenu as Menu,
+        LOVELL.tricare.variant as LovellVariant
+      )
+      expect(sideNavData.data?.links[0].url.path).toEqual(
+        '/lovell-federal-health-care-tricare/stories'
+      )
+      expect(sideNavData.data?.links[0].links[0].url.path).toEqual(
+        '/lovell-federal-health-care-tricare/news'
+      )
+    })
+
+    it('transforms URLs for VA variant', () => {
+      const sideNavData = buildSideNavDataFromMenu(
+        '/test-path',
+        lovellMenu as Menu,
+        LOVELL.va.variant as LovellVariant
+      )
+      expect(sideNavData.data?.links[0].url.path).toEqual(
+        '/lovell-federal-health-care-va/stories'
+      )
+      expect(sideNavData.data?.links[0].links[0].url.path).toEqual(
+        '/lovell-federal-health-care-va/news'
+      )
+    })
+
+    it('preserves original URLs when no variant is provided', () => {
+      const sideNavData = buildSideNavDataFromMenu(
+        '/test-path',
+        lovellMenu as Menu
+      )
+      expect(sideNavData.data?.links[0].url.path).toEqual(
+        '/lovell-federal-health-care/stories'
+      )
+      expect(sideNavData.data?.links[0].links[0].url.path).toEqual(
+        '/lovell-federal-health-care/news'
+      )
+    })
+
+    it('recursively transforms URLs in nested menu items', () => {
+      const sideNavData = buildSideNavDataFromMenu(
+        '/test-path',
+        lovellMenu as Menu,
+        LOVELL.tricare.variant as LovellVariant
+      )
+      const firstItem = sideNavData.data?.links[0]
+      expect(firstItem?.url.path).toEqual(
+        '/lovell-federal-health-care-tricare/stories'
+      )
+      expect(firstItem?.links?.[0]?.url.path).toEqual(
+        '/lovell-federal-health-care-tricare/news'
+      )
+    })
+  })
 })
diff --git a/src/lib/drupal/facilitySideNav.ts b/src/lib/drupal/facilitySideNav.ts
index f55526bd1..ad50a444f 100644
--- a/src/lib/drupal/facilitySideNav.ts
+++ b/src/lib/drupal/facilitySideNav.ts
@@ -4,31 +4,41 @@ import {
   SideNavItem,
   SideNavMenu,
 } from '@/types/formatted/sideNav'
+import { LovellVariant } from '@/lib/drupal/lovell/types'
+import { getLovellVariantOfUrl } from './lovell/utils'
 
 // Recursively fit menu items into sidenav-requested shape
-const normalizeMenuItem = (item: MenuItem): SideNavItem => {
+const normalizeMenuItem = (
+  item: MenuItem,
+  variant?: LovellVariant
+): SideNavItem => {
   const nestedItems = []
 
   if (item.items && item.items.length > 0) {
-    item.items.forEach((i) => nestedItems.push(normalizeMenuItem(i)))
+    item.items.forEach((i) => nestedItems.push(normalizeMenuItem(i, variant)))
   }
+  // Transform URL if Lovell variant is specified
+  const path = variant ? getLovellVariantOfUrl(item.url, variant) : item.url
   return {
     description: item.description,
     expanded: item.expanded,
     label: item.title,
     links: nestedItems,
-    url: { path: item.url },
+    url: { path },
     lovellSection: item.field_menu_section || null,
   }
 }
 
-const normalizeMenuData = (menu: Menu): SideNavData => {
+const normalizeMenuData = (
+  menu: Menu,
+  variant?: LovellVariant
+): SideNavData => {
   // Bail early if no tree is provided
   if (!menu || !menu.tree || menu.tree.length === 0) return null
 
   const links = []
   menu.tree.forEach((item) => {
-    return links.push(normalizeMenuItem(item))
+    return links.push(normalizeMenuItem(item, variant))
   })
   return {
     name: menu.tree[0].title,
@@ -43,9 +53,10 @@ const normalizeMenuData = (menu: Menu): SideNavData => {
 */
 export const buildSideNavDataFromMenu = (
   entityPath: string,
-  menu: Menu
+  menu: Menu,
+  variant?: LovellVariant
 ): SideNavMenu => {
-  const data = normalizeMenuData(menu)
+  const data = normalizeMenuData(menu, variant)
   return {
     rootPath: `${entityPath}/`,
     data,
diff --git a/src/products/eventListing/query.test.ts b/src/products/eventListing/query.test.ts
index 67942192e..e945f2821 100644
--- a/src/products/eventListing/query.test.ts
+++ b/src/products/eventListing/query.test.ts
@@ -8,6 +8,7 @@ import { mockResponse } from '@/products/eventListing/mock.js'
 import mockEventData from '@/products/event/mock.json'
 import { RESOURCE_TYPES } from '@/lib/constants/resourceTypes'
 import { params } from './query'
+import { formatter } from './query'
 
 const EventListingMock: NodeEventListing = mockResponse
 const EventMock: NodeEvent[] = [mockEventData]
@@ -33,3 +34,402 @@ describe(`${RESOURCE_TYPES.EVENT_LISTING} formatData`, () => {
     ).toMatchSnapshot()
   })
 })
+
+describe('EventListing formatter', () => {
+  const mockMenu = {
+    items: [
+      {
+        title: 'Test Menu Item',
+        description: 'Test Description',
+        expanded: false,
+        url: '/test-url',
+        items: [],
+        enabled: true,
+        id: 'menu-1',
+        menu_name: 'main',
+        meta: { entity_id: '123' },
+        parent: '',
+        provider: 'test',
+        route: { name: 'test', parameters: {} },
+        type: 'menu_link_content',
+        weight: '0',
+        options: {},
+        severity: 0,
+      },
+    ],
+    tree: [
+      {
+        title: 'Test Menu Item',
+        description: 'Test Description',
+        expanded: true,
+        url: '/test-url',
+        items: [],
+      },
+    ],
+  }
+
+  const mockData = {
+    entity: {
+      id: 'test-id',
+      type: 'node--event_listing',
+      status: true,
+      title: 'Test Event Listing',
+      path: {
+        alias: '/test-path',
+        pid: 123,
+        langcode: 'en',
+        severity: 0,
+      },
+      field_intro_text: 'Test intro text',
+      field_description: 'Test description',
+      field_enforce_unique_combo: false,
+      field_office: {
+        type: 'node--health_care_region_page',
+        id: 'test-office-id',
+        field_system_menu: null,
+        field_body: null,
+        field_email_updates_link: null,
+        field_external_link: null,
+        field_description: 'Test office description',
+        field_facility_hours: null,
+        field_facility_locator_api_id: null,
+        field_intro_text: null,
+        field_link_facility_emerg_list: null,
+        field_link_facility_health_list: null,
+        field_link_facility_nca_list: null,
+        field_link_facility_vba_list: null,
+        field_media: null,
+        field_meta_tags: null,
+        field_meta_title: null,
+        field_nickname_for_this_facility: null,
+        field_operating_status: null,
+        field_operating_status_facility: null,
+        field_operating_status_more_info: null,
+        field_press_release_office: null,
+        field_region_page: null,
+        field_social_media_links: null,
+        field_twitter_feed_url: null,
+        field_website_url: null,
+        field_office_id: null,
+        field_parent_office: null,
+        drupal_internal__nid: 456,
+        drupal_internal__vid: 789,
+        status: true,
+        title: 'Test Office',
+        path: {
+          alias: '/test-office',
+          pid: 123,
+          langcode: 'en',
+          severity: 0,
+        },
+        changed: '2024-03-20',
+        created: '2024-03-20',
+        default_langcode: true,
+        langcode: 'en',
+        promote: false,
+        revision_log: '',
+        revision_timestamp: '2024-03-20',
+        sticky: false,
+        uuid: 'test-uuid',
+      },
+      drupal_internal__nid: 123,
+      drupal_internal__vid: 456,
+      created: '2024-01-01',
+      changed: '2024-01-02',
+      promote: false,
+      sticky: false,
+      default_langcode: true,
+      revision_translation_affected: true,
+      moderation_state: 'published',
+      langcode: 'en',
+    },
+    events: [],
+    menu: {
+      items: [],
+      tree: [
+        {
+          title: 'Test Menu Item',
+          description: 'Test Description',
+          expanded: false,
+          enabled: true,
+          id: 'test-id',
+          menu_name: 'main',
+          meta: {},
+          parent: '',
+          provider: 'menu_link_content',
+          route: { name: 'test', parameters: {} },
+          type: 'menu_link_content',
+          url: '/lovell-federal-health-care/test-url',
+          weight: '0',
+          options: {},
+          severity: 0,
+          items: [],
+        },
+      ],
+    },
+    totalItems: 0,
+    totalPages: 1,
+  }
+
+  const mockDataWithoutEvents = {
+    entity: {
+      path: {
+        alias: '/test-path',
+        pid: 123,
+        langcode: 'en',
+        severity: 0,
+      },
+      id: 'test-id',
+      type: 'node--event_listing',
+      status: true,
+      title: 'Test Event Listing',
+      field_intro_text: 'Test intro text',
+      field_description: 'Test description',
+      field_enforce_unique_combo: false,
+      field_office: {
+        type: 'node--health_care_region_page',
+        id: 'test-office-id',
+        field_system_menu: null,
+        field_body: null,
+        field_email_updates_link: null,
+        field_external_link: null,
+        field_description: 'Test office description',
+        field_facility_hours: null,
+        field_facility_locator_api_id: null,
+        field_intro_text: null,
+        field_link_facility_emerg_list: null,
+        field_link_facility_health_list: null,
+        field_link_facility_nca_list: null,
+        field_link_facility_vba_list: null,
+        field_media: null,
+        field_meta_tags: null,
+        field_meta_title: null,
+        field_nickname_for_this_facility: null,
+        field_operating_status: null,
+        field_operating_status_facility: null,
+        field_operating_status_more_info: null,
+        field_press_release_office: null,
+        field_region_page: null,
+        field_social_media_links: null,
+        field_twitter_feed_url: null,
+        field_website_url: null,
+        field_office_id: null,
+        field_parent_office: null,
+        drupal_internal__nid: 456,
+        drupal_internal__vid: 789,
+        status: true,
+        title: 'Test Office',
+        path: {
+          alias: '/test-office',
+          pid: 123,
+          langcode: 'en',
+          severity: 0,
+        },
+        changed: '2024-03-20',
+        created: '2024-03-20',
+        default_langcode: true,
+        langcode: 'en',
+        promote: false,
+        revision_log: '',
+        revision_timestamp: '2024-03-20',
+        sticky: false,
+        uuid: 'test-uuid',
+      },
+      drupal_internal__nid: 123,
+      drupal_internal__vid: 456,
+      created: '2024-01-01',
+      changed: '2024-01-02',
+      promote: false,
+      sticky: false,
+      default_langcode: true,
+      revision_translation_affected: true,
+      moderation_state: 'published',
+      langcode: 'en',
+    },
+    events: [],
+    menu: {
+      items: [],
+      tree: [
+        {
+          title: 'Test Menu Item',
+          description: 'Test Description',
+          expanded: false,
+          enabled: true,
+          id: 'test-id',
+          menu_name: 'main',
+          meta: {},
+          parent: '',
+          provider: 'menu_link_content',
+          route: { name: 'test', parameters: {} },
+          type: 'menu_link_content',
+          url: '/lovell-federal-health-care/test-url',
+          weight: '0',
+          options: {},
+          severity: 0,
+          items: [],
+        },
+      ],
+    },
+    totalItems: 0,
+    totalPages: 1,
+  }
+
+  const mockDataWithLovellPath = {
+    entity: {
+      path: {
+        alias: '/lovell/test-path',
+        pid: 123,
+        langcode: 'en',
+        severity: 0,
+      },
+      id: 'test-id',
+      type: 'node--event_listing',
+      status: true,
+      title: 'Test Event Listing',
+      field_intro_text: 'Test intro text',
+      field_description: 'Test description',
+      field_enforce_unique_combo: false,
+      field_office: {
+        type: 'node--health_care_region_page',
+        id: 'test-office-id',
+        field_system_menu: null,
+        field_body: null,
+        field_email_updates_link: null,
+        field_external_link: null,
+        field_description: 'Test office description',
+        field_facility_hours: null,
+        field_facility_locator_api_id: null,
+        field_intro_text: null,
+        field_link_facility_emerg_list: null,
+        field_link_facility_health_list: null,
+        field_link_facility_nca_list: null,
+        field_link_facility_vba_list: null,
+        field_media: null,
+        field_meta_tags: null,
+        field_meta_title: null,
+        field_nickname_for_this_facility: null,
+        field_operating_status: null,
+        field_operating_status_facility: null,
+        field_operating_status_more_info: null,
+        field_press_release_office: null,
+        field_region_page: null,
+        field_social_media_links: null,
+        field_twitter_feed_url: null,
+        field_website_url: null,
+        field_office_id: null,
+        field_parent_office: null,
+        drupal_internal__nid: 456,
+        drupal_internal__vid: 789,
+        status: true,
+        title: 'Test Office',
+        path: {
+          alias: '/test-office',
+          pid: 123,
+          langcode: 'en',
+          severity: 0,
+        },
+        changed: '2024-03-20',
+        created: '2024-03-20',
+        default_langcode: true,
+        langcode: 'en',
+        promote: false,
+        revision_log: '',
+        revision_timestamp: '2024-03-20',
+        sticky: false,
+        uuid: 'test-uuid',
+      },
+      drupal_internal__nid: 123,
+      drupal_internal__vid: 456,
+      created: '2024-01-01',
+      changed: '2024-01-02',
+      promote: false,
+      sticky: false,
+      default_langcode: true,
+      revision_translation_affected: true,
+      moderation_state: 'published',
+      langcode: 'en',
+    },
+    events: [],
+    menu: {
+      items: [],
+      tree: [
+        {
+          title: 'Test Menu Item',
+          description: 'Test Description',
+          expanded: false,
+          enabled: true,
+          id: 'test-id',
+          menu_name: 'main',
+          meta: {},
+          parent: '',
+          provider: 'menu_link_content',
+          route: { name: 'test', parameters: {} },
+          type: 'menu_link_content',
+          url: '/lovell-federal-health-care/test-url',
+          weight: '0',
+          options: {},
+          severity: 0,
+          items: [],
+        },
+      ],
+    },
+    totalItems: 0,
+    totalPages: 1,
+  }
+
+  test('handles non-Lovell paths without transformation', () => {
+    const nonLovellData = {
+      ...mockData,
+      menu: {
+        items: [],
+        tree: [
+          {
+            ...mockData.menu.tree[0],
+            url: '/test-url',
+          },
+        ],
+      },
+    }
+    const result = formatter(nonLovellData)
+    expect(result.menu.rootPath).toBe('/test-path/')
+    expect(result.menu.data.links[0].url.path).toBe('/test-url')
+  })
+
+  test('detects TRICARE variant and transforms menu URLs', () => {
+    const tricareData = {
+      ...mockData,
+      entity: {
+        ...mockData.entity,
+        path: {
+          alias: '/lovell-federal-health-care-tricare/events',
+          pid: 123,
+          langcode: 'en',
+          severity: 0,
+        },
+      },
+    }
+    const result = formatter(tricareData)
+    expect(result.menu.rootPath).toBe(
+      '/lovell-federal-health-care-tricare/events/'
+    )
+    expect(result.menu.data.links[0].url.path).toContain('tricare')
+  })
+
+  test('detects VA variant and transforms menu URLs', () => {
+    const vaData = {
+      ...mockData,
+      entity: {
+        ...mockData.entity,
+        path: {
+          alias: '/lovell-federal-health-care-va/events',
+          pid: 123,
+          langcode: 'en',
+          severity: 0,
+        },
+      },
+    }
+    const result = formatter(vaData)
+    expect(result.menu.rootPath).toBe('/lovell-federal-health-care-va/events/')
+    expect(result.menu.data.links[0].url.path).toContain('va')
+  })
+})
diff --git a/src/products/eventListing/query.ts b/src/products/eventListing/query.ts
index b299c0f6d..e6c577eb1 100644
--- a/src/products/eventListing/query.ts
+++ b/src/products/eventListing/query.ts
@@ -14,6 +14,8 @@ import {
   getMenu,
 } from '@/lib/drupal/query'
 import { buildSideNavDataFromMenu } from '@/lib/drupal/facilitySideNav'
+import { LOVELL } from '@/lib/drupal/lovell/constants'
+import { isLovellTricarePath, isLovellVaPath } from '@/lib/drupal/lovell/utils'
 
 const PAGE_SIZE = PAGE_SIZES[RESOURCE_TYPES.EVENT_LISTING]
 // See listingParams for more information about this value and its use.
@@ -109,9 +111,18 @@ export const formatter: QueryFormatter<EventListingData, EventListing> = ({
     return queries.formatData(`${RESOURCE_TYPES.EVENT}--teaser`, event)
   })
 
+  // Check if this is a Lovell facility page (TRICARE or VA variant)
+  let variant = undefined
+  if (isLovellTricarePath(entity.path.alias)) {
+    variant = LOVELL.tricare.variant
+  } else if (isLovellVaPath(entity.path.alias)) {
+    variant = LOVELL.va.variant
+  }
+
   let formattedMenu = null
-  if (menu !== null)
-    formattedMenu = buildSideNavDataFromMenu(entity.path.alias, menu)
+  if (menu !== null) {
+    formattedMenu = buildSideNavDataFromMenu(entity.path.alias, menu, variant)
+  }
 
   return {
     ...entityBaseFields(entity),


Reviews:
user: login: brianseek
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T23:11:34Z
user: login: brianseek
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T23:27:58Z
user: login: brianseek
body: Works well for me! A one little thing but nothing blocking. 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T23:32:10Z
user: login: laflannery
body: @moanu404 This looks great! I tested Lovell VA, TRICARE and non-Lovell VAMCs.

However when testing, I discovered that the exact same thing is happening on [Lovell TRICARE Event listing](https://www.va.gov/lovell-federal-health-care-tricare/events/) (with the exact same pages). This is not a result of anything you did because it's happening on Prod. Would it make sense to resolve that within this PR or would a separate ticket for a future sprint be better?
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T12:53:27Z
user: login: moanu404
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T16:14:23Z
user: login: moanu404
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T22:56:19Z

Review comments:
diff_hunk: @@ -6,8 +6,10 @@ import {
   params as storyListingParams,
   listingParams,
   data,
+  formatter,
 } from '../storyListing'
 import * as queryModule from '@/lib/drupal/query'
+import { LOVELL } from '@/lib/drupal/lovell/constants'
path: src/data/queries/tests/storyListing.test.tsx
user: login: brianseek
body: doesn't look like you are using this one.
created_at: 2025-04-22T23:11:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,9 +23,19 @@ const mockMenu: Partial<Menu> = {
       enabled: true,
       field_menu_section: 'Test Section',
       items: [], // Assuming it's a flat structure for simplicity
+      menu_name: 'test-menu',
+      provider: 'menu_link_content',
+      weight: '0',
+      options: {},
+      route: {
+        name: 'entity.node.canonical',
+        parameters: {},
+      },
+      type: 'menu_link_content',
+      meta: {},
+      parent: '',
     },
-    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  ] as any[], // Use 'any[]' to bypass detailed type requirements
+  ] as CustomMenuLinkContent[],
path: src/lib/drupal/facilitySideNav.test.ts
user: login: brianseek
body: I got a comment from Chris about avoiding type assertions...but I dunno how to avoid that with this partial menu and custom type. Maybe Chris has an opinion on this?
created_at: 2025-04-22T23:27:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,8 +6,10 @@ import {
   params as storyListingParams,
   listingParams,
   data,
+  formatter,
 } from '../storyListing'
 import * as queryModule from '@/lib/drupal/query'
+import { LOVELL } from '@/lib/drupal/lovell/constants'
path: src/data/queries/tests/storyListing.test.tsx
user: login: moanu404
body: argh yes, you are correct it is lingering around, good catch! i'll fix it up
created_at: 2025-04-23T16:14:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,8 +6,10 @@ import {
   params as storyListingParams,
   listingParams,
   data,
+  formatter,
 } from '../storyListing'
 import * as queryModule from '@/lib/drupal/query'
+import { LOVELL } from '@/lib/drupal/lovell/constants'
path: src/data/queries/tests/storyListing.test.tsx
user: login: moanu404
body: tbh, I seem to remember it is possible to add in a linter rule we can leverage to check any unused imports, might be worth looking into that so that it would fail the CI/be a pre commit hook 🤔 
created_at: 2025-04-23T22:56:19Z
author_association: CONTRIBUTOR

PR comments:
user: login: moanu404
created_at: 2025-04-23T16:15:34Z
body: > @moanu404 This looks great! I tested Lovell VA, TRICARE and non-Lovell VAMCs.
> 
> However when testing, I discovered that the exact same thing is happening on [Lovell TRICARE Event listing](https://www.va.gov/lovell-federal-health-care-tricare/events/) (with the exact same pages). This is not a result of anything you did because it's happening on Prod. Would it make sense to resolve that within this PR or would a separate ticket for a future sprint be better?

Thanks! let me take a look on the tricare event page and see if its small enough to see whats going on and to fold in a fix here and if it takes some time I can let you know if a separate ticket is better!
author_association: CONTRIBUTOR
user: login: laflannery
created_at: 2025-04-24T12:22:07Z
body: Events listings look good, thanks @moanu404!
author_association: CONTRIBUTOR