Skip to content

Commit

Permalink
VACMS-19386 Add SecondaryButtonGroup and RelatedLinks common componen…
Browse files Browse the repository at this point in the history
…ts (#814)
  • Loading branch information
randimays authored Nov 21, 2024
1 parent b560102 commit 9c897e6
Show file tree
Hide file tree
Showing 8 changed files with 278 additions and 6 deletions.
13 changes: 7 additions & 6 deletions additional.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ declare module 'debug'

declare namespace JSX {
interface IntrinsicElements {
'va-alert'
'va-link'
'va-icon'
'va-button'
'va-breadcrumbs'
'va-accordion'
'va-accordion-item'
'va-on-this-page'
'va-alert'
'va-back-to-top'
'va-breadcrumbs'
'va-button'
'va-icon'
'va-link'
'va-link-action'
'va-on-this-page'
}
}
64 changes: 64 additions & 0 deletions src/templates/common/relatedLinks/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { render } from '@testing-library/react'
import { RelatedLinks } from '.'
import { FormattedRelatedLinks } from '@/types/formatted/relatedLinks'

describe('RelatedLinks Component', () => {
test('renders the correct number of links when there are multiple', () => {
const relatedLinks: FormattedRelatedLinks = {
links: [
{
uri: 'https://va.gov/burials-memorials/eligibility',
title: 'Eligibility for burial in a VA national cemetery',
summary:
'Here is a summary for this URL so you can see how it displays underneath.',
},
{
uri: 'https://va.gov/burials-memorials/schedule-a-burial',
title: 'Schedule a burial for a Veteran or family member',
summary: null,
},
],
sectionTitle: 'Related information',
}

const { container } = render(<RelatedLinks {...relatedLinks} />)

expect(container.innerHTML).toContain(
'Eligibility for burial in a VA national cemetery'
)
expect(container.innerHTML).toContain(
'href="https://va.gov/burials-memorials/eligibility"'
)
expect(container.innerHTML).toContain(
'Here is a summary for this URL so you can see how it displays underneath.'
)
expect(container.innerHTML).toContain(
'Schedule a burial for a Veteran or family member'
)
expect(container.innerHTML).toContain(
'href="https://va.gov/burials-memorials/schedule-a-burial"'
)
})

test('renders link correctly when there is only one', () => {
const oneLink: FormattedRelatedLinks = {
links: [
{
uri: 'https://va.gov/burials-memorials/schedule-a-burial',
title: 'Schedule a burial for a Veteran or family member',
summary: null,
},
],
sectionTitle: 'VA benefits',
}

const { container } = render(<RelatedLinks {...oneLink} />)

expect(container.innerHTML).toContain(
'Schedule a burial for a Veteran or family member'
)
expect(container.innerHTML).toContain(
'href="https://va.gov/burials-memorials/schedule-a-burial"'
)
})
})
51 changes: 51 additions & 0 deletions src/templates/common/relatedLinks/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { isEmpty } from 'lodash'
import { FormattedRelatedLinks } from '@/types/formatted/relatedLinks'

// General component used for one or more links with a line of descriptive text underneath
// Does not map directly to any one Drupal type; it is simply a shared UI component
export const RelatedLinks = ({
links,
sectionTitle,
}: FormattedRelatedLinks): JSX.Element => {
if (isEmpty(links)) {
return null
}

let link
const renderLink = (uri, title, summary) => (
<>
<p className="vads-u-margin--0">
<strong>
<va-link href={uri} text={title} />
</strong>
</p>
{summary && <p className="vads-u-margin--0">{summary}</p>}
</>
)

if (links.length === 1) {
link = links[0]
}

return (
<section className="vads-u-margin-bottom--3 vads-u-display--flex vads-u-flex-direction--column">
{sectionTitle && (
<h2 className="vads-u-margin-top--0 vads-u-margin-bottom--2 vads-u-font-size--h3">
{sectionTitle}
</h2>
)}

{links.length > 1 && (
<ul className="usa-unstyled-list">
{links.map((link, index) => (
<li className="vads-u-margin-bottom--2" key={index}>
{renderLink(link.uri, link.title, link?.summary)}
</li>
))}
</ul>
)}

{links.length === 1 && renderLink(link.uri, link.title, link?.summary)}
</section>
)
}
30 changes: 30 additions & 0 deletions src/templates/common/relatedLinks/relatedLinks.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Meta, StoryObj } from '@storybook/react'

import { RelatedLinks } from '.'

const meta: Meta<typeof RelatedLinks> = {
title: 'Common/Related Links',
component: RelatedLinks,
}
export default meta

type Story = StoryObj<typeof RelatedLinks>

export const Example: Story = {
args: {
sectionTitle: 'VA benefits',
links: [
{
uri: 'https://va.gov/burials-memorials/eligibility',
title: 'Eligibility for burial in a VA national cemetery',
summary:
'Here is a summary for this URL so you can see how it displays underneath.',
},
{
uri: 'https://va.gov/burials-memorials/schedule-a-burial',
title: 'Schedule a burial for a Veteran or family member',
summary: null,
},
],
},
}
51 changes: 51 additions & 0 deletions src/templates/common/secondaryButtonGroup/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { render } from '@testing-library/react'
import { SecondaryButtonGroup } from './'
import { Button as FormattedButton } from '@/types/formatted/button'
import { ParagraphComponent } from '@/types/formatted/paragraph'

describe('SecondaryButtonGroup Component', () => {
test('renders action links correctly when there are multiple', () => {
const multipleButtons: ParagraphComponent<FormattedButton>[] = [
{
id: '1',
label: 'Button one',
url: 'https://www.va.gov/button-one',
},
{
id: '2',
label: 'Button two',
url: 'https://www.va.gov/button-two',
},
]

const { container } = render(
<SecondaryButtonGroup buttons={multipleButtons} />
)

expect(container.innerHTML).toContain('Button one')
expect(container.innerHTML).toContain(
'href="https://www.va.gov/button-one"'
)
expect(container.innerHTML).toContain('Button two')
expect(container.innerHTML).toContain(
'href="https://www.va.gov/button-two"'
)
})

test('renders action link correctly when there is only one', () => {
const oneButton: ParagraphComponent<FormattedButton>[] = [
{
id: '1',
label: 'Single button',
url: 'https://www.va.gov/single-button',
},
]

const { container } = render(<SecondaryButtonGroup buttons={oneButton} />)

expect(container.innerHTML).toContain('Single button')
expect(container.innerHTML).toContain(
'href="https://www.va.gov/single-button"'
)
})
})
35 changes: 35 additions & 0 deletions src/templates/common/secondaryButtonGroup/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Button as FormattedButton } from '@/types/formatted/button'
import { ParagraphComponent } from '@/types/formatted/paragraph'

// Used for R&S pages; either a single blue CTA link or multiple
export const SecondaryButtonGroup = ({
buttons,
}: {
buttons: ParagraphComponent<FormattedButton>[]
}): JSX.Element => {
if (buttons.length > 1) {
return (
<ul className="vads-u-margin-y--3 usa-unstyled-list">
{buttons?.map((button, index) => (
<li key={index} className="vads-u-margin-bottom--2">
<va-link-action
href={button.url}
text={button.label}
type="secondary"
/>
</li>
))}
</ul>
)
}

const button = buttons[0]

if (button) {
return (
<va-link-action href={button.url} text={button.label} type="secondary" />
)
}

return null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Meta, StoryObj } from '@storybook/react'

import { SecondaryButtonGroup } from '.'

const meta: Meta<typeof SecondaryButtonGroup> = {
title: 'Common/Secondary Button Group',
component: SecondaryButtonGroup,
}
export default meta

type Story = StoryObj<typeof SecondaryButtonGroup>

export const Example: Story = {
args: {
buttons: [
{
id: '1',
type: 'paragraph--button',
url: 'https://www.va.gov/careers-employment/vocational-rehabilitation/eligibility',
label: 'See eligibility for VR&E benefits',
},
{
id: '2',
type: 'paragraph--button',
url: 'https://www.va.gov/careers-employment/vocational-rehabilitation/how-to-apply',
label: 'Find out how to apply for VR&E benefits',
},
],
},
}
10 changes: 10 additions & 0 deletions src/types/formatted/relatedLinks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type RelatedLink = {
title: string
uri: string
summary?: string
}

export type FormattedRelatedLinks = {
sectionTitle: string
links: RelatedLink[]
}

0 comments on commit 9c897e6

Please sign in to comment.