Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VACMS-16432 banner updates #294

Merged
merged 35 commits into from
Dec 29, 2023
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
75eb04c
fix unused imports
tjheffner Dec 14, 2023
7c9d531
move banner data fetch to query
tjheffner Dec 15, 2023
679b8fc
move auth check to preview fetch only
tjheffner Dec 15, 2023
bd789a7
banners mostly refactored
tjheffner Dec 15, 2023
016d9eb
dont remove path
tjheffner Dec 15, 2023
ac44864
Verify VA Edge Devices Support Secure TLS Renegotiation (#282)
olivereri Dec 15, 2023
1a663c8
Redis hotfix (#283)
tjheffner Dec 16, 2023
4d6fdad
Bump @storybook/addon-interactions from 7.6.4 to 7.6.5 (#286)
dependabot[bot] Dec 18, 2023
4c11701
Bump @axe-core/playwright from 4.8.1 to 4.8.2 (#288)
dependabot[bot] Dec 18, 2023
19aa7d2
Bump @types/node from 20.4.4 to 20.10.5 (#289)
dependabot[bot] Dec 18, 2023
e58090e
Bump @typescript-eslint/eslint-plugin from 6.8.0 to 6.14.0 (#290)
dependabot[bot] Dec 18, 2023
3468dcf
Bump actions/upload-artifact from 3 to 4 (#291)
dependabot[bot] Dec 18, 2023
4209e88
move auth check to preview fetch only
tjheffner Dec 15, 2023
7d462f9
keep global auth for now
tjheffner Dec 18, 2023
71b102a
const to let
tjheffner Dec 18, 2023
c8d37aa
Merge branch 'main' into VACMS-16432-banner-updates
tjheffner Dec 18, 2023
933f259
prettier because i --no-verify sometimes
tjheffner Dec 18, 2023
346f83a
Merge branch 'main' into VACMS-16432-banner-updates
tjheffner Dec 18, 2023
acbc4e8
move auth check to preview fetch only
tjheffner Dec 15, 2023
11c40db
Run playwright in a container (#295)
olivereri Dec 18, 2023
c9084be
VACMS-15322: env config (#296)
ryguyk Dec 19, 2023
da53018
VACMS-15322: ENV/CLI follow-up (#299)
ryguyk Dec 19, 2023
8b0459f
banners break auth for some reason
tjheffner Dec 20, 2023
582f17d
const to let
tjheffner Dec 20, 2023
653660d
Merge branch 'main' into VACMS-16432-banner-updates
tjheffner Dec 20, 2023
c4762ec
comment out auth
tjheffner Dec 20, 2023
3f8e227
fix banner types causing auth error
tjheffner Dec 20, 2023
62297a9
update wrapper + tests
tjheffner Dec 20, 2023
970977a
remove unused import
tjheffner Dec 20, 2023
eb7324b
facility banner nonsense
tjheffner Dec 20, 2023
a390d0b
Merge branch 'main' into VACMS-16432-banner-updates
tjheffner Dec 26, 2023
494bbce
VACMS-10355 component generator (#305)
tjheffner Dec 28, 2023
dc0d18a
fix conflicts
tjheffner Dec 28, 2023
74b29ff
remove unneeded webpack mod
tjheffner Dec 28, 2023
0c0ae34
simplify banner type logic
tjheffner Dec 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,24 @@ const nextConfig = {
swcMinify: true,
trailingSlash: true,
staticPageGenerationTimeout: 180, //arbitrary; 60 is default but it's too small

webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve = {
...config.resolve,
fallback: {
// redis can't be used client side
// see https://github.com/getsentry/sentry-javascript/issues/6548
// note: this repo isn't using sentry but the issue explains the problem
net: false,
dns: false,
tls: false,
assert: false,
fs: false,
},
}
}
return config
},
tjheffner marked this conversation as resolved.
Show resolved Hide resolved
}
module.exports = nextConfig
15 changes: 10 additions & 5 deletions playwright/tests/a11y.spec.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
/* eslint-disable no-console */
import AxeBuilder from '@axe-core/playwright'
import { test, expect } from '@playwright/test'
const { test } = require('../utils/next-test')
const getSitemapLocations = require('../utils/getSitemapLocations')

async function runA11yTestsForPages(pages, testName, page) {
async function runA11yTestsForPages(pages, testName, page, makeAxeBuilder) {
let a11yFailures = []

for (const pageUrl of pages) {
await page.goto(pageUrl)
const accessibilityScanResults = await new AxeBuilder({ page }).analyze()
const accessibilityScanResults = await makeAxeBuilder().analyze()

if (accessibilityScanResults.violations.length > 0) {
accessibilityScanResults.violations.forEach((violation) => {
Expand Down Expand Up @@ -56,8 +55,14 @@ test.describe('Accessibility Tests', () => {
for (let i = 0; i < 5; i++) {
test(`the site should be accessible - Segment ${i + 1}`, async ({
page,
makeAxeBuilder,
}) => {
await runA11yTestsForPages(pageSegments[i], `Segment ${i + 1}`, page)
await runA11yTestsForPages(
pageSegments[i],
`Segment ${i + 1}`,
page,
makeAxeBuilder
)
})
}
})
42 changes: 26 additions & 16 deletions src/data/queries/banners.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
import { QueryFormatter } from 'next-drupal-query'
import { QueryData, QueryFormatter } from 'next-drupal-query'
import { NodeBanner } from '@/types/dataTypes/drupal/node'
import {
Banner,
FacilityBanner,
PromoBanner,
BannerDisplayType,
BannerTypeMapping,
BannersData,
} from '@/types/dataTypes/formatted/banners'
import { drupalClient } from '@/lib/drupal/drupalClient'

export const BannerDisplayType = {
PROMO_BANNER: 'promoBanner',
FACILITY_BANNER: 'facilityBanner',
BANNER: 'banner',
export type BannerDataOpts = {
itemPath?: string
}

export const BannerTypeMapping = {
[BannerDisplayType.PROMO_BANNER]: 'node--promo_banner',
[BannerDisplayType.FACILITY_BANNER]: 'node--full_width_banner_alert',
[BannerDisplayType.BANNER]: 'node--banner',
// The banner data endpoint is a custom endpoint provided by Drupal due to how banners are associated with a page.
// A given page does not reference a banner node via entity reference, banner node types have a field that lists what
// paths they are supposed to be visible on. This endpoint queries banners based on their path lists.
// See docroot/modules/custom/va_gov_api/src/Resources/BannerAlerts.php in va.gov-cms for more info.
export const data: QueryData<BannerDataOpts, NodeBanner[]> = async (opts) => {
if (opts.itemPath) {
const bannerUrl = `${process.env.NEXT_PUBLIC_DRUPAL_BASE_URL}/jsonapi/banner-alerts?item-path=${opts.itemPath}`

const response = await drupalClient.fetch(bannerUrl)
const data: [] | unknown = drupalClient.deserialize(await response.json())

return data as NodeBanner[]
}

return []
}

export const formatter: QueryFormatter<
NodeBanner[],
Array<PromoBanner | Banner | FacilityBanner | NodeBanner>
> = (entities: NodeBanner[]) => {
export const formatter: QueryFormatter<NodeBanner[], BannersData> = (
entities: NodeBanner[]
) => {
return entities?.map((banner) => {
switch (banner?.type as string) {
case BannerTypeMapping[BannerDisplayType.BANNER]:
Expand Down Expand Up @@ -54,6 +63,7 @@ export const formatter: QueryFormatter<
operatingStatus: banner.field_alert_operating_status_cta,
inheritanceSubpages: banner.field_alert_inheritance_subpages,
path: banner.path?.alias,
findFacilities: banner.field_alert_find_facilities_cta,
bannerAlertVamcs: banner.field_banner_alert_vamcs,
type: banner.type,
}
Expand Down
4 changes: 2 additions & 2 deletions src/data/queries/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as QuestionAnswer from './questionAnswer'
import * as ExpandableText from './expandableText'
import * as LinkTeaser from './linkTeaser'
import * as MediaImage from './mediaImage'
import * as Banner from './banners'
import * as Banners from './banners'
import * as PersonProfile from './personProfile'
import * as Button from './button'
import * as AudienceTopics from './audienceTopics'
Expand Down Expand Up @@ -41,7 +41,7 @@ export const QUERIES_MAP = {
'block_content--promo': PromoBlock,

// Custom queries
'banner--alerts_lookup': Banner,
'banner-data': Banners,
'header-footer-data': HeaderFooter,

// Static Path Generation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ exports[`Banners return formatted data outputs formatted data 1`] = `
",
},
"dismiss": true,
"findFacilities": false,
"id": "ccd9d30f-78f9-4358-80d7-191f99b18d43",
"inheritanceSubpages": false,
"operatingStatus": true,
Expand Down
4 changes: 1 addition & 3 deletions src/data/queries/tests/banners.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ describe('Banners return formatted data', () => {
test('outputs formatted data', () => {
windowSpy.mockImplementation(() => undefined)
const formattedData = nodeBannerMock
expect(
queries.formatData('banner--alerts_lookup', formattedData)
).toMatchSnapshot()
expect(queries.formatData('banner-data', formattedData)).toMatchSnapshot()
})
})
44 changes: 15 additions & 29 deletions src/lib/drupal/getGlobalElements.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,31 @@
import { formatter } from '@/data/queries/banners'
import { drupalClient } from '@/lib/drupal/drupalClient'
import { LayoutProps } from '@/templates/globals/wrapper'
import { NodeBanner } from '@/types/dataTypes/drupal/node'
import { queries } from '@/data/queries'

const nonSlugRoute = `${process.env.NEXT_PUBLIC_DRUPAL_BASE_URL}/jsonapi/banner-alerts?item-path=/`

// Helper function to fetch global elements for layout.
// It is called once for every page on build.
// TODO: add cache layer to drupalClient query results

// Helper function to fetch global elements for layout. This is called once for every page during a build,
// because banners are associated with individual pages via slug lookup (itemPath).
export async function getGlobalElements(
jsonApiEntryPoint?: string,
itemPath?: string,
headerOnly: boolean = false
): Promise<LayoutProps> {
let banners = []
// This query is cached so header and footer menu data is only directly requested once per build.
const headerFooterData = await queries.getData('header-footer-data')

// If we are not in headerOnly mode and the necessary parameters are provided, fetch banners
// move all of this into @/data/queries/banners.ts
if (!headerOnly && jsonApiEntryPoint && itemPath) {
let bannerPath = `${jsonApiEntryPoint}/banner-alerts?item-path=${itemPath}`
// Banners can be fetched as long as we have context and a path (slug).
if (!headerOnly && itemPath) {
// Gather data for banners currently visible on this page.
const bannerData = await queries.getData('banner-data', {
itemPath,
})

if (itemPath.includes('home')) {
bannerPath = nonSlugRoute
return {
bannerData,
headerFooterData,
}

const requestBanner = await drupalClient.fetch(`${bannerPath}`)
const bannerData: [] | unknown = drupalClient.deserialize(
await requestBanner.json()
)
banners = formatter(bannerData as NodeBanner[])

// gather data for banners currently visible on this page
// const bannerData = await queries.getData('banner--alerts_lookup')
}

const headerFooterData = await queries.getData('header-footer-data')

// Otherwise return header data without banners.
return {
bannerData: banners,
bannerData: [],
headerFooterData,
}
}
1 change: 0 additions & 1 deletion src/lib/drupal/staticProps.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { GetStaticPropsContext } from 'next'
import { DrupalTranslatedPath } from 'next-drupal'
import { QueryOpts } from 'next-drupal-query'
import { drupalClient } from '@/lib/drupal/drupalClient'
import { queries } from '@/data/queries'
import {
Expand Down
5 changes: 2 additions & 3 deletions src/pages/404.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ const Error404Page = ({ headerFooterData }) => {
export async function getStaticProps() {
try {
const { headerFooterData } = await getGlobalElements(
undefined,
undefined,
true
undefined, // no banners on 404
true // header only
)
return {
props: {
Expand Down
4 changes: 1 addition & 3 deletions src/pages/[[...slug]].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,9 @@ export async function getStaticProps(context: GetStaticPropsContext) {
notFound: true,
}
}

// If resource is good, gather additional data for global elements.
// This will be cached in the future so the header isn't re-requested a million times.
// The headerFooter data is cached, banner content is requested per page
const { bannerData, headerFooterData } = await getGlobalElements(
pathInfo.jsonapi?.entryPoint,
expandedContext.drupalPath
)

Expand Down
16 changes: 5 additions & 11 deletions src/templates/globals/banners/facilityBanner/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useRef, useEffect, useState } from 'react'
import { recordEvent } from '@/lib/analytics/recordEvent'
import { regionBaseURL } from '@/lib/utils/helpers'
// import { regionBaseURL } from '@/lib/utils/helpers'
import { VaBanner } from '@department-of-veterans-affairs/component-library/dist/react-bindings'
import { NodeMetaInfo } from '@/types/dataTypes/drupal/node'
import { FacilityBanner as FormattedFacilityBanner } from '@/types/dataTypes/formatted/banners'

export const FacilityBanner = ({
Expand Down Expand Up @@ -31,17 +30,16 @@ export const FacilityBanner = ({
return () => window.removeEventListener('click', handler)
}, [])

const findPath = path
const hideOnSubpages = inheritanceSubpages
// const findPath = path
// const hideOnSubpages = inheritanceSubpages
const alertType = fieldAlertType === 'information' ? 'info' : fieldAlertType

const region = '/' + regionBaseURL(findPath)
const lastArg = findPath?.substring(findPath?.lastIndexOf('/'))
// const region = '/' + regionBaseURL(findPath)
// const lastArg = findPath?.substring(findPath?.lastIndexOf('/'))

let content = body
const statusUrl = ''

// TODO: Banner AlertVAMCS data is a special case. we need to call a relationship which our current banner endpoint does not support. node--vamc_operating_status_and_alerts
// if (bannerAlertVamcs) {
// bannerAlertVamcs?.map((vamc) => {
// if (region == vamc?.office?.path) {
Expand Down Expand Up @@ -119,7 +117,3 @@ export const FacilityBanner = ({
</>
)
}

/** Export information necessary to identify the component and query it.
* See {@link NodeMetaInfo}
*/
23 changes: 13 additions & 10 deletions src/templates/globals/wrapper/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ const banners = [
type: 'node--banner',
},
]
const props = { bannerData: [], headerFooterData: {} }

describe('<Wrapper> renders', () => {
test('body', () => {
render(
<>
<Wrapper>
<Wrapper {...props}>
<div>This is the layout</div>
</Wrapper>
</>
Expand All @@ -29,9 +30,11 @@ describe('<Wrapper> renders', () => {
})

test('<Banner> when bannerData exists', () => {
const props = { bannerData: banners }

render(<Wrapper bannerData={props.bannerData}>{children}</Wrapper>)
render(
<Wrapper {...props} bannerData={banners}>
{children}
</Wrapper>
)
expect(screen.getByRole('region')).toHaveAttribute(
'headline',
'COVID-19 vaccines at VA'
Expand All @@ -40,18 +43,18 @@ describe('<Wrapper> renders', () => {
})

test('<Banner> when bannerData does not exist', () => {
const props = { bannerData: null }

render(<Wrapper bannerData={props.bannerData}>{children}</Wrapper>)
render(<Wrapper {...props}>{children}</Wrapper>)
expect(
screen.queryByText(/This is the banner body/)
).not.toBeInTheDocument()
})

test('Header and Footer are present', () => {
const props = { bannerData: banners }

render(<Wrapper bannerData={props.bannerData}>{children}</Wrapper>)
render(
<Wrapper {...props} bannerData={banners}>
{children}
</Wrapper>
)

expect(screen.getByRole('banner')).toHaveClass('header')

Expand Down
Loading
Loading