diff --git a/src/__fixtures__/data/cmsSearch.ts b/src/__fixtures__/data/cmsSearch.ts
index 29b30ba81..2f32f7ce3 100644
--- a/src/__fixtures__/data/cmsSearch.ts
+++ b/src/__fixtures__/data/cmsSearch.ts
@@ -3,7 +3,7 @@ export const mockCmsSearchResults = [
__typename: 'ArticleResult',
type: 'Article',
id: 'cl3buldda0247riyt6h85cpgc',
- permalink: 'my-fitness-article',
+ permalink: 'http://example.com/article/my-fitness-article',
title: 'My Fitness Article',
preview: 'This is the preview text!',
date: '2022-05-18T17:18:40.802Z',
diff --git a/src/__fixtures__/data/searchResults.ts b/src/__fixtures__/data/searchResults.ts
new file mode 100644
index 000000000..08eabaa8d
--- /dev/null
+++ b/src/__fixtures__/data/searchResults.ts
@@ -0,0 +1,58 @@
+import type { SearchResultRecord } from 'types/index'
+
+export const testApplicationResult: SearchResultRecord = {
+ id: 'testBookmark123',
+ type: 'Bookmark',
+ title: 'MyFSS',
+ preview:
+ 'How is Air Force Information Management System abbreviated? AFIMS stands for Air Force Information Management System. For those who have seen the Earth from space, and for the hundreds and perhaps thousands more who will, the experience most certainly changes your perspective.',
+ permalink: 'https://www.url.com/myfss',
+}
+
+export const testDocumentationResult: SearchResultRecord = {
+ id: 'testDocumentation123',
+ type: 'Documentation',
+ title: 'Some Documentation',
+ preview:
+ 'Documentation posted about some important topic that you should read about.',
+ permalink: 'https://localhost:3000/path/to/documentation',
+}
+
+export const testLandingPageResult: SearchResultRecord = {
+ id: 'testLandingPage123',
+ type: 'LandingPage',
+ title: 'Some Landing Page',
+ preview:
+ 'Our team landing page where you can find all the information you need to know about our team.',
+ permalink: 'https://localhost:3000/landing/team',
+}
+
+export const testArticleResultNoLabels: SearchResultRecord = {
+ id: 'testArticle124',
+ type: 'Article',
+ title:
+ 'Physical training: but without labels Everything you need to know about the update in requirements',
+ preview:
+ 'There are no labels. As a steward of almost 9 million acres encompassing forests, prairies, deserts, wetlands, and coastal habitats, the Department of the Air Force recognizes the importance of protecting and sustaining the natural environment.',
+ permalink:
+ 'https://localhost:3000/articles/physical-training-everything-you-need-to-know-no-labels',
+ date: '2022-05-17T13:44:39.796Z',
+}
+export const testArticleResult: SearchResultRecord = {
+ id: 'testArticle123',
+ type: 'Article',
+ title:
+ 'Physical training: Everything you need to know about the update in requirements',
+ preview:
+ 'As a steward of almost 9 million acres encompassing forests, prairies, deserts, wetlands, and coastal habitats, the Department of the Air Force recognizes the importance of protecting and sustaining the natural environment.',
+ permalink:
+ 'https://localhost:3000/articles/physical-training-everything-you-need-to-know',
+ date: '2022-05-17T13:44:39.796Z',
+ labels: [
+ {
+ id: 'testLabel',
+ name: 'All Guardians',
+ type: 'Audience',
+ },
+ ],
+}
diff --git a/src/__tests__/pages/search.test.tsx b/src/__tests__/pages/search.test.tsx
index 37f28671e..6180516fd 100644
--- a/src/__tests__/pages/search.test.tsx
+++ b/src/__tests__/pages/search.test.tsx
@@ -72,13 +72,7 @@ describe('Search page getServerSideProps', () => {
props: {
query: 'fitness',
pageTitle: 'fitness Search Results',
- results: mockCmsSearchResults.map((r) => ({
- ...r,
- permalink:
- r.type === 'Article'
- ? `http://example.com/articles/${r.permalink}`
- : r.permalink,
- })),
+ results: mockCmsSearchResults,
},
})
})
diff --git a/src/components/SearchResultItem/SearchResultItem.stories.tsx b/src/components/SearchResultItem/SearchResultItem.stories.tsx
index 2f4212a43..f925bb352 100644
--- a/src/components/SearchResultItem/SearchResultItem.stories.tsx
+++ b/src/components/SearchResultItem/SearchResultItem.stories.tsx
@@ -2,45 +2,22 @@ import React from 'react'
import { Meta } from '@storybook/react'
import { SearchResultItem } from './SearchResultItem'
-import type { SearchResultRecord } from 'types/index'
+import {
+ testArticleResult,
+ testApplicationResult,
+ testDocumentationResult,
+ testLandingPageResult,
+} from '__fixtures__/data/searchResults'
export default {
title: 'Components/SearchResults/SearchResultItem',
component: SearchResultItem,
} as Meta
-const testApplicationResult: SearchResultRecord = {
- id: 'testBookmark123',
- type: 'Bookmark',
- title: 'MyFSS',
- preview:
- 'How is Air Force Information Management System abbreviated? AFIMS stands for Air Force Information Management System. For those who have seen the Earth from space, and for the hundreds and perhaps thousands more who will, the experience most certainly changes your perspective.',
- permalink: 'https://www.url.com/myfss',
-}
-
export const ApplicationResult = () => (
)
-const testArticleResult: SearchResultRecord = {
- id: 'testArticle123',
- type: 'Article',
- title:
- 'Physical training: Everything you need to know about the update in requirements',
- preview:
- 'As a steward of almost 9 million acres encompassing forests, prairies, deserts, wetlands, and coastal habitats, the Department of the Air Force recognizes the importance of protecting and sustaining the natural environment.',
- permalink:
- 'https://localhost:3000/articles/physical-training-everything-you-need-to-know',
- date: '2022-05-17T13:44:39.796Z',
- labels: [
- {
- id: 'testLabel',
- name: 'All Guardians',
- type: 'Audience',
- },
- ],
-}
-
export const ArticleResult = () =>
export const ArticleResultLineClamp = () => (
@@ -54,3 +31,11 @@ export const ArticleResultLineClamp = () => (
}}
/>
)
+
+export const DocumentationResult = () => (
+
+)
+
+export const LandingPageResult = () => (
+
+)
diff --git a/src/components/SearchResultItem/SearchResultItem.test.tsx b/src/components/SearchResultItem/SearchResultItem.test.tsx
index 1b75439b0..b9ca283f2 100644
--- a/src/components/SearchResultItem/SearchResultItem.test.tsx
+++ b/src/components/SearchResultItem/SearchResultItem.test.tsx
@@ -7,81 +7,117 @@ import { axe } from 'jest-axe'
import React from 'react'
import { SearchResultItem } from './SearchResultItem'
-import type { SearchResultRecord } from 'types/index'
+import {
+ testApplicationResult,
+ testArticleResultNoLabels,
+ testDocumentationResult,
+ testLandingPageResult,
+} from '__fixtures__/data/searchResults'
-const testApplicationResult: SearchResultRecord = {
- id: 'testBookmark123',
- type: 'Bookmark',
- title: 'MyFSS',
- preview:
- 'How is Air Force Information Management System abbreviated? AFIMS stands for Air Force Information Management System. For those who have seen the Earth from space, and for the hundreds and perhaps thousands more who will, the experience most certainly changes your perspective.',
- permalink: 'https://www.url.com/myfss',
-}
+describe('SearchResultItem component', () => {
+ test('renders an Application result with no a11y violations', async () => {
+ const { container } = render(
+
+ )
-const testArticleResult: SearchResultRecord = {
- id: 'testArticle123',
- type: 'Article',
- title:
- 'Physical training: Everything you need to know about the update in requirements',
- preview:
- 'As a steward of almost 9 million acres encompassing forests, prairies, deserts, wetlands, and coastal habitats, the Department of the Air Force recognizes the importance of protecting and sustaining the natural environment.',
- permalink:
- 'https://localhost:3000/articles/physical-training-everything-you-need-to-know',
- date: '2022-05-17T13:44:39.796Z',
-}
+ expect(screen.queryByRole('img')).not.toBeInTheDocument()
+ expect(screen.queryAllByRole('link')).toHaveLength(1)
+ expect(screen.queryAllByRole('link')[0]).toHaveAttribute(
+ 'href',
+ testApplicationResult.permalink
+ )
+ expect(screen.queryByRole('heading', { level: 3 })).toHaveTextContent(
+ testApplicationResult.title
+ )
+ expect(
+ screen.queryByText(testApplicationResult.preview)
+ ).toBeInTheDocument()
+ expect(screen.queryByText('Application')).toHaveClass('usa-tag')
-describe('SearchResultItem component', () => {
- it('renders an Application result with no a11y violations', async () => {
// Bug with NextJS Link + axe :(
// https://github.com/nickcolley/jest-axe/issues/95#issuecomment-758921334
await act(async () => {
- const { container } = render(
- ,
- { legacyRoot: true }
- )
+ expect(await axe(container)).toHaveNoViolations()
+ })
+ })
- expect(screen.queryByRole('img')).not.toBeInTheDocument()
- expect(screen.queryAllByRole('link')).toHaveLength(1)
- expect(screen.queryAllByRole('link')[0]).toHaveAttribute(
- 'href',
- testApplicationResult.permalink
- )
- expect(screen.queryByRole('heading', { level: 3 })).toHaveTextContent(
- testApplicationResult.title
- )
- expect(
- screen.queryByText(testApplicationResult.preview)
- ).toBeInTheDocument()
- expect(screen.queryByText('Application')).toHaveClass('usa-tag')
+ test('renders an Article result with no a11y violations', async () => {
+ const { container } = render(
+
+ )
+ expect(screen.queryByText('May')).toBeInTheDocument()
+ expect(screen.queryByText('17')).toBeInTheDocument()
+
+ expect(screen.queryByRole('img')).not.toBeInTheDocument()
+ expect(screen.queryAllByRole('link')).toHaveLength(1)
+ expect(screen.queryAllByRole('link')[0]).toHaveAttribute(
+ 'href',
+ testArticleResultNoLabels.permalink
+ )
+ expect(screen.queryByRole('heading', { level: 3 })).toHaveTextContent(
+ testArticleResultNoLabels.title
+ )
+ expect(
+ screen.queryByText(testArticleResultNoLabels.preview)
+ ).toBeInTheDocument()
+ expect(screen.queryByText('USSF News')).toHaveClass('usa-tag')
+
+ // Bug with NextJS Link + axe :(
+ // https://github.com/nickcolley/jest-axe/issues/95#issuecomment-758921334
+ await act(async () => {
expect(await axe(container)).toHaveNoViolations()
})
})
- it('renders an Article result with no a11y violations', async () => {
+ test('renders a Documentation result with no a11y violations', async () => {
+ const { container } = render(
+
+ )
+
+ expect(screen.queryByRole('img')).not.toBeInTheDocument()
+ expect(screen.queryAllByRole('link')).toHaveLength(1)
+ expect(screen.queryAllByRole('link')[0]).toHaveAttribute(
+ 'href',
+ testDocumentationResult.permalink
+ )
+ expect(screen.queryByRole('heading', { level: 3 })).toHaveTextContent(
+ testDocumentationResult.title
+ )
+ expect(
+ screen.queryByText(testDocumentationResult.preview)
+ ).toBeInTheDocument()
+ expect(screen.queryByText('USSF Documentation')).toHaveClass('usa-tag')
+
// Bug with NextJS Link + axe :(
// https://github.com/nickcolley/jest-axe/issues/95#issuecomment-758921334
await act(async () => {
- const { container } = render(
- ,
- { legacyRoot: true }
- )
+ expect(await axe(container)).toHaveNoViolations()
+ })
+ })
- expect(screen.queryByText('May')).toBeInTheDocument()
- expect(screen.queryByText('17')).toBeInTheDocument()
+ test('renders a Landing Page result with no a11y violations', async () => {
+ const { container } = render(
+
+ )
- expect(screen.queryByRole('img')).not.toBeInTheDocument()
- expect(screen.queryAllByRole('link')).toHaveLength(1)
- expect(screen.queryAllByRole('link')[0]).toHaveAttribute(
- 'href',
- testArticleResult.permalink
- )
- expect(screen.queryByRole('heading', { level: 3 })).toHaveTextContent(
- testArticleResult.title
- )
- expect(screen.queryByText(testArticleResult.preview)).toBeInTheDocument()
- expect(screen.queryByText('USSF News')).toHaveClass('usa-tag')
+ expect(screen.queryByRole('img')).not.toBeInTheDocument()
+ expect(screen.queryAllByRole('link')).toHaveLength(1)
+ expect(screen.queryAllByRole('link')[0]).toHaveAttribute(
+ 'href',
+ testLandingPageResult.permalink
+ )
+ expect(screen.queryByRole('heading', { level: 3 })).toHaveTextContent(
+ testLandingPageResult.title
+ )
+ expect(
+ screen.queryByText(testLandingPageResult.preview)
+ ).toBeInTheDocument()
+ expect(screen.queryByText('Landing Page')).toHaveClass('usa-tag')
+ // Bug with NextJS Link + axe :(
+ // https://github.com/nickcolley/jest-axe/issues/95#issuecomment-758921334
+ await act(async () => {
expect(await axe(container)).toHaveNoViolations()
})
})
diff --git a/src/components/SearchResultItem/SearchResultItem.tsx b/src/components/SearchResultItem/SearchResultItem.tsx
index d8fb276c7..52c349f2c 100644
--- a/src/components/SearchResultItem/SearchResultItem.tsx
+++ b/src/components/SearchResultItem/SearchResultItem.tsx
@@ -21,6 +21,12 @@ export const SearchResultItem = ({ item }: { item: SearchResultRecord }) => {
itemIcon = dateObj &&
break
}
+ case 'Documentation':
+ itemCategory = CONTENT_CATEGORIES.DOCUMENTATION
+ break
+ case 'LandingPage':
+ itemCategory = CONTENT_CATEGORIES.LANDING_PAGE
+ break
}
return (
@@ -34,7 +40,7 @@ export const SearchResultItem = ({ item }: { item: SearchResultRecord }) => {
-
{preview}
+ {preview}
{itemCategory &&
}
diff --git a/src/constants/index.ts b/src/constants/index.ts
index b950c3a1b..1c301910a 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -44,6 +44,10 @@ export const CONTENT_CATEGORIES = {
value: 'Documentation',
label: 'USSF Documentation',
},
+ LANDING_PAGE: {
+ value: 'LandingPage',
+ label: 'Landing Page',
+ },
APPLICATION: {
value: 'Application',
label: 'Application',
diff --git a/src/helpers/index.test.ts b/src/helpers/index.test.ts
index f7f4b2ac8..d9824be7c 100644
--- a/src/helpers/index.test.ts
+++ b/src/helpers/index.test.ts
@@ -7,6 +7,7 @@ import {
isCmsUser,
getYouTubeEmbedId,
handleRedirectTo,
+ formatDisplayDate,
} from './index'
import type { RSSNewsItem, PublishableItemType } from 'types'
@@ -217,3 +218,11 @@ describe('handleRedirectTo', () => {
expect(handleRedirectTo(mockReq)).toEqual('/redirect?redirectPath=/users')
})
})
+
+describe('formatDisplayDate', () => {
+ test('returns formatted date string', () => {
+ const testDate = new Date('2021-05-17T13:44:39.796Z')
+ const expectedDate = 'May 17, 2021'
+ expect(formatDisplayDate(testDate)).toEqual(expectedDate)
+ })
+})
diff --git a/src/helpers/index.ts b/src/helpers/index.ts
index 21a922cd0..b4ff9add3 100644
--- a/src/helpers/index.ts
+++ b/src/helpers/index.ts
@@ -124,3 +124,11 @@ export const handleRedirectTo = (req: PassportRequest) => {
return '/'
}
}
+
+export const formatDisplayDate = (date: Date) => {
+ return new Date(date).toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ })
+}
diff --git a/src/operations/cms/queries/getLandingPage.ts b/src/operations/cms/queries/getLandingPage.ts
index 4a19c4287..1bd246256 100644
--- a/src/operations/cms/queries/getLandingPage.ts
+++ b/src/operations/cms/queries/getLandingPage.ts
@@ -14,6 +14,7 @@ export const GET_LANDING_PAGE = gql`
slug
status
publishedDate
+ updatedAt
documents {
title
document {
diff --git a/src/pages/landing/[landingPage]/index.tsx b/src/pages/landing/[landingPage]/index.tsx
index 0d7992781..c82726e8b 100644
--- a/src/pages/landing/[landingPage]/index.tsx
+++ b/src/pages/landing/[landingPage]/index.tsx
@@ -17,7 +17,7 @@ import { GET_LANDING_PAGE } from 'operations/cms/queries/getLandingPage'
import { CMSBookmark, CollectionRecord } from 'types'
import { isPdf, handleOpenPdfLink } from 'helpers/openDocumentLink'
import { getSession } from 'lib/session'
-import { isCmsUser, isPublished } from 'helpers/index'
+import { formatDisplayDate, isCmsUser, isPublished } from 'helpers/index'
type DocumentsType = {
title: string
@@ -155,6 +155,14 @@ const LandingPage = ({
{articles.length >= 1 && (
)}
+ {isPublished(landingPage) && (
+
+ Last updated:{' '}
+ {landingPage.updatedAt >= landingPage.publishedDate
+ ? formatDisplayDate(landingPage.updatedAt)
+ : formatDisplayDate(landingPage.publishedDate)}
+
+ )}
>
)
}
diff --git a/src/pages/search.tsx b/src/pages/search.tsx
index 983c58f56..a0529a63f 100644
--- a/src/pages/search.tsx
+++ b/src/pages/search.tsx
@@ -131,9 +131,6 @@ export default Search
Search.getLayout = (page: React.ReactNode) => withArticleLayout(page)
export const getServerSideProps: GetServerSideProps = async (context) => {
- // Need absolute URL
- const origin = process.env.NEXT_PUBLIC_PORTAL_URL
-
// get search terms from URL params
const { q } = context.query
@@ -163,22 +160,10 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
variables: { query: q },
})) as unknown as { data: { search: SearchResultRecord[] } }
- // Add full URL to articles (TODO do this on the CMS end by generating permalinks)
- const results =
- search?.map((i) => {
- return {
- ...i,
- permalink:
- i.type === 'Article'
- ? `${origin}/articles/${i.permalink}`
- : i.permalink,
- }
- }) || []
-
return {
props: {
query: q,
- results,
+ results: search ? search : [],
pageTitle: `${q} Search Results`,
labels,
},
diff --git a/src/stories/searchresults.stories.tsx b/src/stories/searchresults.stories.tsx
index 5e8f0d6dd..5d6319e18 100644
--- a/src/stories/searchresults.stories.tsx
+++ b/src/stories/searchresults.stories.tsx
@@ -2,40 +2,17 @@ import React from 'react'
import type { Meta } from '@storybook/react'
import { SearchResultItem } from 'components/SearchResultItem/SearchResultItem'
-import type { SearchResultRecord } from 'types/index'
+import {
+ testApplicationResult,
+ testArticleResult,
+ testDocumentationResult,
+ testLandingPageResult,
+} from '__fixtures__/data/searchResults'
export default {
title: 'Components/SearchResults',
} as Meta
-const testApplicationResult: SearchResultRecord = {
- id: 'testBookmark123',
- type: 'Bookmark',
- title: 'MyFSS',
- preview:
- 'How is Air Force Information Management System abbreviated? AFIMS stands for Air Force Information Management System. For those who have seen the Earth from space, and for the hundreds and perhaps thousands more who will, the experience most certainly changes your perspective.',
- permalink: 'https://www.url.com/myfss',
-}
-
-const testArticleResult: SearchResultRecord = {
- id: 'testArticle123',
- type: 'Article',
- title:
- 'Physical training: Everything you need to know about the update in requirements',
- preview:
- 'As a steward of almost 9 million acres encompassing forests, prairies, deserts, wetlands, and coastal habitats, the Department of the Air Force recognizes the importance of protecting and sustaining the natural environment.',
- permalink:
- 'https://localhost:3000/articles/physical-training-everything-you-need-to-know',
- date: '2022-05-17T13:44:39.796Z',
- labels: [
- {
- id: 'testLabel',
- name: 'All Guardians',
- type: 'Audience',
- },
- ],
-}
-
export const SearchResults = () => {
return (
<>
@@ -51,8 +28,9 @@ export const SearchResults = () => {
'https://localhost:3000/articles/physical-training-everything-you-need-to-know?asfljaslfkjlkajrlakjsflkajsflasfmaaslkfjalsfjaklsjlasfksfljaslfkjlkajrlakjsflkajsflasfmaaslkfjalsfjaklsjlasfk',
}}
/>
-
+
+
>
)
}
diff --git a/src/types/index.ts b/src/types/index.ts
index dbcd21686..dcfe51f11 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -128,7 +128,11 @@ export type LabelRecord = {
}
/* Search Results (from Keystone) */
-export type SearchResultType = 'Article' | 'Bookmark'
+export type SearchResultType =
+ | 'Article'
+ | 'Bookmark'
+ | 'Documentation'
+ | 'LandingPage'
export type SearchResultRecord = {
id: string