From 7252d7d0be41b4048665916865c1df8b69fa9cec Mon Sep 17 00:00:00 2001 From: Ryan Koch <6863534+ryguyk@users.noreply.github.com> Date: Tue, 2 Jan 2024 13:49:40 -0600 Subject: [PATCH] VACMS-16499: Proper handling of image styles (#312) --- next.config.js | 3 +- src/data/queries/event.ts | 5 +- src/data/queries/mediaImage.ts | 24 +- src/data/queries/newsStory.ts | 5 +- src/data/queries/newsStoryTeaser.ts | 5 +- src/data/queries/personProfile.ts | 2 +- .../__snapshots__/mediaImage.test.tsx.snap | 3 +- .../__snapshots__/newsStory.test.tsx.snap | 3 +- .../__snapshots__/personProfile.test.tsx.snap | 3 +- src/data/queries/tests/mediaImage.test.tsx | 4 +- src/lib/drupal/lovell/tests/mockData.ts | 3 +- src/templates/common/image/image.stories.ts | 20 -- src/templates/common/image/index.test.jsx | 81 ----- src/templates/common/image/index.tsx | 6 - .../common/image/mediaImageIndividual.json | 294 ------------------ .../{image => mediaImage}/customLoader.js | 0 .../common/mediaImage/index.test.tsx | 65 ++-- src/templates/common/mediaImage/index.tsx | 70 ++++- .../common/mediaImage/mockMedia.json | 2 +- src/templates/components/linkTeaser/index.tsx | 2 +- .../components/newsStoryTeaser/index.test.tsx | 3 +- .../newsStoryTeaser.stories.ts | 3 +- .../components/personProfile/index.test.tsx | 15 +- .../personProfile/personProfile.stories.ts | 8 +- src/templates/globals/header/TopNav.tsx | 2 +- src/templates/layouts/event/index.tsx | 8 +- .../layouts/newsStory/index.test.tsx | 3 +- .../layouts/newsStory/newsStory.stories.ts | 3 +- .../layouts/staffProfile/dataService.tsx | 8 +- src/templates/layouts/staffProfile/index.tsx | 1 + .../staffProfile/staffProfile.stories.ts | 10 +- .../staffProfile/staffProfile.test.tsx | 3 +- .../layouts/storyListing/mockFormattedList.js | 70 +++-- src/types/formatted/media.ts | 12 +- 34 files changed, 212 insertions(+), 537 deletions(-) delete mode 100644 src/templates/common/image/image.stories.ts delete mode 100644 src/templates/common/image/index.test.jsx delete mode 100644 src/templates/common/image/index.tsx delete mode 100644 src/templates/common/image/mediaImageIndividual.json rename src/templates/common/{image => mediaImage}/customLoader.js (100%) diff --git a/next.config.js b/next.config.js index 6175f758a..0c98437bd 100644 --- a/next.config.js +++ b/next.config.js @@ -3,8 +3,9 @@ */ const nextConfig = { images: { - loaderFile: './src/templates/common/image/customLoader.js', + loaderFile: './src/templates/common/mediaImage/customLoader.js', loader: 'custom', + unoptimized: true, }, reactStrictMode: true, swcMinify: true, diff --git a/src/data/queries/event.ts b/src/data/queries/event.ts index 5ba070928..36a6d53a1 100644 --- a/src/data/queries/event.ts +++ b/src/data/queries/event.ts @@ -49,10 +49,7 @@ export const formatter: QueryFormatter = ( ) => { return { ...entityBaseFields(entity), - image: queries.formatData('media--image', { - entity: entity.field_media, - cropType: '2_1_large', - }) as MediaImage, + image: queries.formatData('media--image', entity.field_media), //cropType: '2_1_large' date: entity.created, socialLinks: { path: entity.path.alias, diff --git a/src/data/queries/mediaImage.ts b/src/data/queries/mediaImage.ts index b294f6b67..ca789d8b4 100644 --- a/src/data/queries/mediaImage.ts +++ b/src/data/queries/mediaImage.ts @@ -9,11 +9,6 @@ import { DrupalMediaImage } from '@/types/drupal/media' import { drupalClient } from '@/lib/drupal/drupalClient' import { MediaImage } from '@/types/formatted/media' -type DrupalMediaImageData = { - entity: DrupalMediaImage - cropType?: string -} - // Define query params for queryData. export const params: QueryParams = () => { return queries.getParams().addInclude(['image']) @@ -25,9 +20,9 @@ type DataOpts = QueryOpts<{ }> // Implement the data loader. -export const data: QueryData = async ( +export const data: QueryData = async ( opts -): Promise => { +): Promise => { const entity = await drupalClient.getResource( 'media--image', opts.id, @@ -36,25 +31,20 @@ export const data: QueryData = async ( } ) - return { entity, cropType: opts.cropType || '2_1_large' } + return entity } -export const formatter: QueryFormatter = ({ - entity, - cropType = '2_1_large', -}) => { +export const formatter: QueryFormatter = ( + entity: DrupalMediaImage +) => { if (!entity) return null - // TODO: may need more handling here around crop type + image height / width. TBD. - // TODO: `link` has reference to all image styles whereas `url` narrows down based on - // cropType. Which do we want at this layer? return { id: entity.image.id, type: entity.type, - link: entity.image?.links, + links: entity.image?.links, alt: entity.image?.resourceIdObjMeta?.alt, width: entity.image?.resourceIdObjMeta?.width, height: entity.image?.resourceIdObjMeta?.height, title: entity.image?.resourceIdObjMeta?.title, - url: entity.image.links[cropType].href, } } diff --git a/src/data/queries/newsStory.ts b/src/data/queries/newsStory.ts index ff9110963..cfc2ef2e5 100644 --- a/src/data/queries/newsStory.ts +++ b/src/data/queries/newsStory.ts @@ -45,10 +45,7 @@ export const formatter: QueryFormatter = ( ) => { return { ...entityBaseFields(entity), - image: queries.formatData('media--image', { - entity: entity.field_media, - cropType: '2_1_large', - }), + image: queries.formatData('media--image', entity.field_media), caption: entity.field_image_caption, author: entity.field_author, introText: entity.field_intro_text, diff --git a/src/data/queries/newsStoryTeaser.ts b/src/data/queries/newsStoryTeaser.ts index 5623b2f03..edf1e8967 100644 --- a/src/data/queries/newsStoryTeaser.ts +++ b/src/data/queries/newsStoryTeaser.ts @@ -19,10 +19,7 @@ export const formatter: QueryFormatter = ( published: entity.status, headingLevel: 'h2', //@todo fix headingLevel, title: entity.title, - image: queries.formatData('media--image', { - entity: entity.field_media, - cropType: '2_1_large', - }), + image: queries.formatData('media--image', entity.field_media), //cropType: '2_1_large' link: entity.path.alias, introText: entity.field_intro_text, lastUpdated: entity.field_last_saved_by_an_editor || entity.created, diff --git a/src/data/queries/personProfile.ts b/src/data/queries/personProfile.ts index f0dc739a1..cd1f7faf6 100644 --- a/src/data/queries/personProfile.ts +++ b/src/data/queries/personProfile.ts @@ -53,7 +53,7 @@ export const formatter: QueryFormatter = ( description: entity.field_description, introText: entity.field_intro_text, body: entity.field_body?.processed || null, - media: queries.formatData('media--image', { entity: entity.field_media }), + media: queries.formatData('media--image', entity.field_media), //no imageStyle passed completeBiography: entity.field_complete_biography, completeBiographyCreate: entity.field_complete_biography_create, photoAllowHiresDownload: entity.field_photo_allow_hires_download, diff --git a/src/data/queries/tests/__snapshots__/mediaImage.test.tsx.snap b/src/data/queries/tests/__snapshots__/mediaImage.test.tsx.snap index a1b7a6f0a..ee7329789 100644 --- a/src/data/queries/tests/__snapshots__/mediaImage.test.tsx.snap +++ b/src/data/queries/tests/__snapshots__/mediaImage.test.tsx.snap @@ -5,7 +5,7 @@ exports[`Media image returns formatted data outputs formatted data 1`] = ` "alt": null, "height": 304, "id": "e638fd17-9090-442b-a724-5113133b4d0f", - "link": { + "links": { "1_1_square_medium_thumbnail": { "href": "http://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/1_1_square_medium_thumbnail/public/hub_promos/health-care.png", "meta": { @@ -147,7 +147,6 @@ exports[`Media image returns formatted data outputs formatted data 1`] = ` }, "title": null, "type": "media--image", - "url": "http://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/2_1_large/public/hub_promos/health-care.png", "width": 456, } `; diff --git a/src/data/queries/tests/__snapshots__/newsStory.test.tsx.snap b/src/data/queries/tests/__snapshots__/newsStory.test.tsx.snap index 19550d1a5..1478992ef 100644 --- a/src/data/queries/tests/__snapshots__/newsStory.test.tsx.snap +++ b/src/data/queries/tests/__snapshots__/newsStory.test.tsx.snap @@ -217,7 +217,7 @@ exports[`node--news_story formatData outputs formatted data 1`] = ` "alt": null, "height": 304, "id": "c85b7882-f035-4b55-8b71-fcf81fade350", - "link": { + "links": { "1_1_square_medium_thumbnail": { "href": "http://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/1_1_square_medium_thumbnail/public/hub_promos/health-care.png", "meta": { @@ -359,7 +359,6 @@ exports[`node--news_story formatData outputs formatted data 1`] = ` }, "title": null, "type": "media--image", - "url": "http://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/2_1_large/public/hub_promos/health-care.png", "width": 456, }, "introText": "When a hospital has a host of great doctors, honoring just two every year is challenging. ", diff --git a/src/data/queries/tests/__snapshots__/personProfile.test.tsx.snap b/src/data/queries/tests/__snapshots__/personProfile.test.tsx.snap index 697306499..4d57afe50 100644 --- a/src/data/queries/tests/__snapshots__/personProfile.test.tsx.snap +++ b/src/data/queries/tests/__snapshots__/personProfile.test.tsx.snap @@ -18,7 +18,7 @@ exports[`Person profile returns formatted data outputs formatted data 1`] = ` "alt": "Patrick J. Doyle", "height": 129, "id": "5bcbdaee-f93f-4b2f-8af5-963e4a547d93", - "link": { + "links": { "1_1_square_medium_thumbnail": { "href": "http://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/1_1_square_medium_thumbnail/public/2019-08/pat_doyle_0.jpg?h=46bc4a38", "meta": { @@ -160,7 +160,6 @@ exports[`Person profile returns formatted data outputs formatted data 1`] = ` }, "title": "", "type": "media--image", - "url": "http://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/2_1_large/public/2019-08/pat_doyle_0.jpg", "width": 100, }, "office": { diff --git a/src/data/queries/tests/mediaImage.test.tsx b/src/data/queries/tests/mediaImage.test.tsx index 43d69d8fa..b27e93bec 100644 --- a/src/data/queries/tests/mediaImage.test.tsx +++ b/src/data/queries/tests/mediaImage.test.tsx @@ -19,8 +19,6 @@ describe('Media image returns formatted data', () => { test('outputs formatted data', () => { windowSpy.mockImplementation(() => undefined) const formattedData = mediaImageMock - expect( - queries.formatData('media--image', { entity: formattedData }) - ).toMatchSnapshot() + expect(queries.formatData('media--image', formattedData)).toMatchSnapshot() }) }) diff --git a/src/lib/drupal/lovell/tests/mockData.ts b/src/lib/drupal/lovell/tests/mockData.ts index ffc30a767..18349da48 100644 --- a/src/lib/drupal/lovell/tests/mockData.ts +++ b/src/lib/drupal/lovell/tests/mockData.ts @@ -54,10 +54,9 @@ export const newsStoryPartialResource = { alt: 'alt-text', id: 'id', title: 'title', - url: 'image/src', width: 100, height: 100, - link: { + links: { '2_1_large': { href: 'image/src', meta: { diff --git a/src/templates/common/image/image.stories.ts b/src/templates/common/image/image.stories.ts deleted file mode 100644 index 6094bdfdf..000000000 --- a/src/templates/common/image/image.stories.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react' -import Image from './index' - -const meta: Meta = { - title: 'Common/Image', - component: Image, -} -export default meta - -type Story = StoryObj - -export const Example: Story = { - args: { - src: 'http://placekitten.com/200/300', - alt: 'an example image', - title: 'A cute kitten.', - height: '300', - width: '200', - }, -} diff --git a/src/templates/common/image/index.test.jsx b/src/templates/common/image/index.test.jsx deleted file mode 100644 index cbe95535e..000000000 --- a/src/templates/common/image/index.test.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import { axe, render, waitFor } from 'test-utils' -import Image from '.' -import mock_media_image from './mediaImageIndividual.json' - -const getUrl = (data) => - data.included.filter((obj) => obj.type == 'file--file')[0].attributes.uri.url - -const getAltText = (data) => data.data.relationships.image.data.meta.alt - -describe('Image Component', () => { - beforeEach(() => { - jest.spyOn(console, 'error') - jest.spyOn(console, 'warn') - console.error.mockImplementation(() => null) - console.warn.mockImplementation(() => null) - }) - - afterEach(() => { - console.error.mockRestore() - console.warn.mockRestore() - }) - test('throws an error if URL is empty', async () => { - const originalError = console.error - console.error = jest.fn() - // eslint-disable-next-line - expect(() => render()).toThrowError( - /url is not defined/i - ) - console.error = originalError - }) - - test('throws an error if no height/width properties are passed in', async () => { - const originalError = console.error - console.error = jest.fn() - let url = getUrl(mock_media_image) - // eslint-disable-next-line - expect(() => render()).toThrow( - /Image with src "([^"]*)" is missing required "width" property./ - ) - console.error = originalError - }) - - test('triggers an accessibility error if no alt text is passed in', async () => { - let url = getUrl(mock_media_image) - // eslint-disable-next-line - const { container } = render() - await waitFor(async () => - expect(await axe(container)).toEqual( - expect.objectContaining({ - violations: expect.arrayContaining([ - expect.objectContaining({ - help: expect.stringMatching(/images must have alternate text/i), - id: 'image-alt', - impact: 'critical', - }), - ]), - }) - ) - ) - }) - - test('renders if sufficient properties are provided', async () => { - let url = getUrl(mock_media_image) - let altText = getAltText(mock_media_image) - let props = { - alt: altText, - src: url, - width: 600, - height: 400, - } - // eslint-disable-next-line - const { container } = render() - await waitFor(async () => expect(await axe(container)).toHaveNoViolations()) - let imgElement - // Actual element - imgElement = document.querySelector('#testImage') - expect(imgElement).toHaveAttribute('alt', altText) - expect(imgElement).toHaveAttribute('src', expect.any(String)) - expect(imgElement).toHaveAttribute('style', expect.any(String)) - }) -}) diff --git a/src/templates/common/image/index.tsx b/src/templates/common/image/index.tsx deleted file mode 100644 index 6614ae995..000000000 --- a/src/templates/common/image/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import NextImage, { ImageProps } from 'next/image' -import customLoader from './customLoader' - -export default function Image(props: ImageProps) { - return -} diff --git a/src/templates/common/image/mediaImageIndividual.json b/src/templates/common/image/mediaImageIndividual.json deleted file mode 100644 index 3c3cb6d2c..000000000 --- a/src/templates/common/image/mediaImageIndividual.json +++ /dev/null @@ -1,294 +0,0 @@ -{ - "jsonapi": { - "version": "1.0", - "meta": { - "links": { - "self": { - "href": "http://jsonapi.org/format/1.0/" - } - } - } - }, - "data": { - "type": "media--image", - "id": "ffd0a3fd-1a61-4d4e-b275-6af6882168ab", - "links": { - "self": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab?resourceVersion=id%3A15904" - } - }, - "attributes": { - "drupal_internal__mid": 15070, - "drupal_internal__vid": 15904, - "langcode": "en", - "revision_created": "2022-06-23T13:41:05+00:00", - "revision_log_message": null, - "status": true, - "name": "Wilmington VA Mobile Clinic ", - "created": "2022-06-23T13:40:48+00:00", - "changed": "2022-06-23T13:41:05+00:00", - "default_langcode": true, - "revision_translation_affected": true, - "metatag": null, - "path": { - "alias": "/media/image/15070", - "pid": 63231, - "langcode": "en" - }, - "field_description": "Mobile Clinic", - "field_media_in_library": true, - "field_media_submission_guideline": null - }, - "relationships": { - "bundle": { - "data": { - "type": "media_type--media_type", - "id": "92f64a34-81e5-4094-82a9-4fe61d7f2227", - "meta": { - "drupal_internal__target_id": "image" - } - }, - "links": { - "related": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/bundle?resourceVersion=id%3A15904" - }, - "self": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/relationships/bundle?resourceVersion=id%3A15904" - } - } - }, - "revision_user": { - "data": { - "type": "user--user", - "id": "412272ee-6e47-4d26-9e46-b424d1d390d8", - "meta": { - "drupal_internal__target_id": 1486 - } - }, - "links": { - "related": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/revision_user?resourceVersion=id%3A15904" - }, - "self": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/relationships/revision_user?resourceVersion=id%3A15904" - } - } - }, - "uid": { - "data": { - "type": "user--user", - "id": "412272ee-6e47-4d26-9e46-b424d1d390d8", - "meta": { - "drupal_internal__target_id": 1486 - } - }, - "links": { - "related": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/uid?resourceVersion=id%3A15904" - }, - "self": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/relationships/uid?resourceVersion=id%3A15904" - } - } - }, - "thumbnail": { - "data": { - "type": "file--file", - "id": "79e21eb7-9b34-421a-a4b2-7b6626814ce0", - "meta": { - "alt": "Wilmington VA Mobile Clinic ", - "title": null, - "width": 1430, - "height": 950, - "drupal_internal__target_id": 17425 - } - }, - "links": { - "related": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/thumbnail?resourceVersion=id%3A15904" - }, - "self": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/relationships/thumbnail?resourceVersion=id%3A15904" - } - } - }, - "field_owner": { - "data": { - "type": "taxonomy_term--administration", - "id": "f55a34b8-f0cc-41f1-a6a3-8375160003ab", - "meta": { - "drupal_internal__target_id": 188 - } - }, - "links": { - "related": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/field_owner?resourceVersion=id%3A15904" - }, - "self": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/relationships/field_owner?resourceVersion=id%3A15904" - } - } - }, - "image": { - "data": { - "type": "file--file", - "id": "79e21eb7-9b34-421a-a4b2-7b6626814ce0", - "meta": { - "alt": "Wilmington VA Mobile Clinic ", - "title": "", - "width": 1430, - "height": 950, - "drupal_internal__target_id": 17425 - } - }, - "links": { - "related": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/image?resourceVersion=id%3A15904" - }, - "self": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab/relationships/image?resourceVersion=id%3A15904" - } - } - } - } - }, - "included": [ - { - "type": "file--file", - "id": "79e21eb7-9b34-421a-a4b2-7b6626814ce0", - "links": { - "1_1_square_medium_thumbnail": { - "href": "https://prod.cms.va.gov/sites/default/files/styles/1_1_square_medium_thumbnail/public/2022-06/mobile_clinic.jpg", - "meta": { - "width": "240", - "height": "240", - "rel": [ - "drupal://jsonapi/extensions/consumer_image_styles/links/relation-types/#derivative" - ] - } - }, - "2_1_large": { - "href": "https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2022-06/mobile_clinic.jpg", - "meta": { - "width": "1024", - "height": "512", - "rel": [ - "drupal://jsonapi/extensions/consumer_image_styles/links/relation-types/#derivative" - ] - } - }, - "2_1_medium_thumbnail": { - "href": "https://prod.cms.va.gov/sites/default/files/styles/2_1_medium_thumbnail/public/2022-06/mobile_clinic.jpg", - "meta": { - "width": "480", - "height": "240", - "rel": [ - "drupal://jsonapi/extensions/consumer_image_styles/links/relation-types/#derivative" - ] - } - }, - "2_3_medium_thumbnail": { - "href": "https://prod.cms.va.gov/sites/default/files/styles/2_3_medium_thumbnail/public/2022-06/mobile_clinic.jpg", - "meta": { - "width": "320", - "height": "480", - "rel": [ - "drupal://jsonapi/extensions/consumer_image_styles/links/relation-types/#derivative" - ] - } - }, - "3_2_medium_thumbnail": { - "href": "https://prod.cms.va.gov/sites/default/files/styles/3_2_medium_thumbnail/public/2022-06/mobile_clinic.jpg", - "meta": { - "width": "480", - "height": "320", - "rel": [ - "drupal://jsonapi/extensions/consumer_image_styles/links/relation-types/#derivative" - ] - } - }, - "7_2_medium_thumbnail": { - "href": "https://prod.cms.va.gov/sites/default/files/styles/7_2_medium_thumbnail/public/2022-06/mobile_clinic.jpg", - "meta": { - "width": "1050", - "height": "300", - "rel": [ - "drupal://jsonapi/extensions/consumer_image_styles/links/relation-types/#derivative" - ] - } - }, - "full_content_width": { - "href": "https://prod.cms.va.gov/sites/default/files/styles/full_content_width/public/2022-06/mobile_clinic.jpg", - "meta": { - "width": "1400", - "height": "930", - "rel": [ - "drupal://jsonapi/extensions/consumer_image_styles/links/relation-types/#derivative" - ] - } - }, - "large": { - "href": "https://prod.cms.va.gov/sites/default/files/styles/large/public/2022-06/mobile_clinic.jpg", - "meta": { - "width": "480", - "height": "319", - "rel": [ - "drupal://jsonapi/extensions/consumer_image_styles/links/relation-types/#derivative" - ] - } - }, - "self": { - "href": "https://prod.cms.va.gov/jsonapi/file/file/79e21eb7-9b34-421a-a4b2-7b6626814ce0" - }, - "viewport_width": { - "href": "https://prod.cms.va.gov/sites/default/files/styles/viewport_width/public/2022-06/mobile_clinic.jpg", - "meta": { - "width": "1430", - "height": "950", - "rel": [ - "drupal://jsonapi/extensions/consumer_image_styles/links/relation-types/#derivative" - ] - } - } - }, - "attributes": { - "drupal_internal__fid": 17425, - "langcode": "en", - "filename": "mobile_clinic.jpg", - "uri": { - "value": "public://2022-06/mobile_clinic.jpg", - "url": "/sites/default/files/2022-06/mobile_clinic.jpg" - }, - "filemime": "image/jpeg", - "filesize": 370481, - "status": true, - "created": "2022-06-23T13:40:48+00:00", - "changed": "2022-06-23T13:41:05+00:00" - }, - "relationships": { - "uid": { - "data": { - "type": "user--user", - "id": "412272ee-6e47-4d26-9e46-b424d1d390d8", - "meta": { - "drupal_internal__target_id": 1486 - } - }, - "links": { - "related": { - "href": "https://prod.cms.va.gov/jsonapi/file/file/79e21eb7-9b34-421a-a4b2-7b6626814ce0/uid" - }, - "self": { - "href": "https://prod.cms.va.gov/jsonapi/file/file/79e21eb7-9b34-421a-a4b2-7b6626814ce0/relationships/uid" - } - } - } - } - } - ], - "links": { - "self": { - "href": "https://prod.cms.va.gov/jsonapi/media/image/ffd0a3fd-1a61-4d4e-b275-6af6882168ab?include=image" - } - } -} diff --git a/src/templates/common/image/customLoader.js b/src/templates/common/mediaImage/customLoader.js similarity index 100% rename from src/templates/common/image/customLoader.js rename to src/templates/common/mediaImage/customLoader.js diff --git a/src/templates/common/mediaImage/index.test.tsx b/src/templates/common/mediaImage/index.test.tsx index 664cef7cb..1811652d2 100644 --- a/src/templates/common/mediaImage/index.test.tsx +++ b/src/templates/common/mediaImage/index.test.tsx @@ -8,8 +8,7 @@ const mediaImage: FormattedMediaImage = { title: 'Cats or Dogs?', width: 1299, height: 1512, - url: 'http://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/2_1_large/public/2020-08/Raab.jpg?h=d3381009', - link: { + links: { '2_1_large': { href: 'http://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/2_1_large/public/2020-08/Raab.jpg?h=d3381009', meta: { @@ -24,20 +23,24 @@ const mediaImage: FormattedMediaImage = { describe('Media Image component renders', () => { test(' renders', () => { - render() + render() waitFor(() => expect(screen.getByText('Cats or Dogs?')).toBeInTheDocument()) }) test(' renders with new title', () => { mediaImage.title = 'COVID-19 vaccines' - render() + render( + + ) waitFor(() => expect(screen.getByText('COVID-19 vaccines')).toBeInTheDocument() ) }) test('MediaImage renders with correct alt text', () => { - render() + render( + + ) const imgElement = document.querySelector('img[alt=""]') // Loading element waitFor(() => expect(imgElement).toHaveAttribute('alt', '')) @@ -45,39 +48,49 @@ describe('Media Image component renders', () => { expect(screen.getByText('Smiling man in glasses.')).toBeInTheDocument() ) }) +}) - test('MediaImage renders when image style is defined', () => { - render( - +describe('MediaImage component does not render', () => { + let spyConsoleError + + beforeEach(() => { + spyConsoleError = jest.spyOn(console, 'error') + spyConsoleError.mockImplementation(() => null) + }) + + afterEach(() => { + spyConsoleError.mockRestore() + }) + + const expectMissingImageSrc = () => { + expect(spyConsoleError).toHaveBeenCalledWith( + expect.stringMatching(/Image is missing required "src" property/), + expect.any(Object) ) - waitFor(() => expect(screen.getByText('1_1_small')).toBeInTheDocument()) + } + + /*eslint-disable jest/expect-expect*/ + test('MediaImage throws error when imageStyle is not provided', () => { + render() + expectMissingImageSrc() }) - test('MediaImage renders when the image style is not defined', () => { - mediaImage.imageStyle = null + /*eslint-disable jest/expect-expect*/ + test('MediaImage throws error when imageStyle does not exist', () => { render( ) - waitFor(() => - expect(screen.getByText('Smiling man in glasses.')).toBeInTheDocument() - ) + expectMissingImageSrc() }) - test('MediaImage does not render with null data', () => { - mediaImage.link = null + /*eslint-disable jest/expect-expect*/ + test('MediaImage throws error with null data', async () => { + mediaImage.links = null render() - waitFor(() => - expect( - screen.getByText('Smiling man in glasses.') - ).not.toBeInTheDocument() - ) + expectMissingImageSrc() }) }) diff --git a/src/templates/common/mediaImage/index.tsx b/src/templates/common/mediaImage/index.tsx index 94b1b9df4..e9746830c 100644 --- a/src/templates/common/mediaImage/index.tsx +++ b/src/templates/common/mediaImage/index.tsx @@ -1,18 +1,72 @@ -import Image from '../image' import { MediaImage as FormattedMediaImage } from '@/types/formatted/media' +import Image from 'next/image' + +const IMAGE_STYLE_DIMENSIONS = { + '1_1_square_medium_thumbnail': { + width: 240, + height: 240, + }, + '2_1_large': { + width: 1024, + height: 512, + }, + '2_1_medium_thumbnail': { + width: 480, + height: 240, + }, + '2_3_medium_thumbnail': { + width: 320, + height: 480, + }, + '3_2_medium_thumbnail': { + width: 480, + height: 320, + }, + '7_2_medium_thumbnail': { + width: 1050, + height: 300, + }, + large: { + width: 480, + height: 480, + }, +} + +const calcImageStyleHeight = ( + baseImageHeight: number, + baseImageWidth: number, + imageStyle: string +) => + IMAGE_STYLE_DIMENSIONS[imageStyle] || { + width: baseImageWidth, + height: baseImageHeight, + } + +export const MediaImage = ( + props: FormattedMediaImage & { + imageStyle?: string + className?: string + style?: { + [key: string]: string + } + } +) => { + const { width, height } = calcImageStyleHeight( + props.width, + props.height, + props.imageStyle + ) -// TODO: Do we need this component? It appears to be an unnecessary wrapper. -// I think we can probably combine this into Image. We do need a way to use different image styles, though. This currently is not doing that. -export const MediaImage = (props: FormattedMediaImage) => { return ( {props.alt} ) } diff --git a/src/templates/common/mediaImage/mockMedia.json b/src/templates/common/mediaImage/mockMedia.json index b005d304a..91f50cd00 100644 --- a/src/templates/common/mediaImage/mockMedia.json +++ b/src/templates/common/mediaImage/mockMedia.json @@ -7,7 +7,7 @@ "height": 330, "title": "foo bar", "url": "https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/2020-04/040120_FEATURE_MarchFCVet20.png", - "link": { + "links": { "2_1_large": { "href": "https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/2_1_large/public/2020-04/040120_FEATURE_MarchFCVet20.png", "meta": { diff --git a/src/templates/components/linkTeaser/index.tsx b/src/templates/components/linkTeaser/index.tsx index b2e512068..d7a30dd65 100644 --- a/src/templates/components/linkTeaser/index.tsx +++ b/src/templates/components/linkTeaser/index.tsx @@ -1,4 +1,4 @@ -import Image from '@/templates/common/image' +import Image from 'next/image' import { get } from 'lodash' import { recordEvent } from '@/lib/analytics/recordEvent' import { LinkTeaser as FormattedLinkTeaser } from '@/types/formatted/linkTeaser' diff --git a/src/templates/components/newsStoryTeaser/index.test.tsx b/src/templates/components/newsStoryTeaser/index.test.tsx index 7a02ed348..b5c2bd340 100644 --- a/src/templates/components/newsStoryTeaser/index.test.tsx +++ b/src/templates/components/newsStoryTeaser/index.test.tsx @@ -6,7 +6,7 @@ import { NewsStoryTeaser } from '@/templates/components/newsStoryTeaser' const mediaImage: MediaImage = { id: '3d6716b3-fb66-4e63-9b21-bb9c024129d3', - link: { + links: { '2_1_large': { href: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_1_large/public/2019-05/doctor-year2019-decker-480_0.jpg', meta: { @@ -21,7 +21,6 @@ const mediaImage: MediaImage = { title: '', width: 318, height: 159, - url: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_1_large/public/2019-05/doctor-year2019-decker-480_0.jpg', } const teaserData = { diff --git a/src/templates/components/newsStoryTeaser/newsStoryTeaser.stories.ts b/src/templates/components/newsStoryTeaser/newsStoryTeaser.stories.ts index 62819790d..6a5c2eb03 100644 --- a/src/templates/components/newsStoryTeaser/newsStoryTeaser.stories.ts +++ b/src/templates/components/newsStoryTeaser/newsStoryTeaser.stories.ts @@ -5,7 +5,7 @@ import { MediaImage } from '@/types/formatted/media' const mediaImage: MediaImage = { id: '3d6716b3-fb66-4e63-9b21-bb9c024129d3', - link: { + links: { '2_1_large': { href: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_1_large/public/2019-05/doctor-year2019-decker-480_0.jpg', meta: { @@ -20,7 +20,6 @@ const mediaImage: MediaImage = { title: '', width: 318, height: 159, - url: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_1_large/public/2019-05/doctor-year2019-decker-480_0.jpg', } const meta: Meta = { diff --git a/src/templates/components/personProfile/index.test.tsx b/src/templates/components/personProfile/index.test.tsx index 5c1bacadf..f486af936 100644 --- a/src/templates/components/personProfile/index.test.tsx +++ b/src/templates/components/personProfile/index.test.tsx @@ -9,16 +9,17 @@ const mediaImage: MediaImage = { title: 'Heather Steele', width: 151, height: 227, - imageStyle: '2_3_medium_thumbnail', - url: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_3_medium_thumbnail/public/2021-04/Zachary_Sage.jpg', - link: { + links: { + '1_1_square_medium_thumbnail': { + href: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/1_1_square_medium_thumbnail/public/2021-04/Zachary_Sage.jpg', + meta: { + linkParams: {}, + }, + }, '2_3_medium_thumbnail': { href: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_3_medium_thumbnail/public/2021-04/Zachary_Sage.jpg', meta: { - linkParams: { - width: 151, - height: 227, - }, + linkParams: {}, }, }, }, diff --git a/src/templates/components/personProfile/personProfile.stories.ts b/src/templates/components/personProfile/personProfile.stories.ts index c4e96b741..bdcd4c4b4 100644 --- a/src/templates/components/personProfile/personProfile.stories.ts +++ b/src/templates/components/personProfile/personProfile.stories.ts @@ -10,11 +10,9 @@ const mediaImage: MediaImage = { title: 'Raab Steele', width: 151, height: 227, - imageStyle: '2_3_medium_thumbnail', - url: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_3_medium_thumbnail/public/2021-04/Zachary_Sage.jpg', - link: { - '2_3_medium_thumbnail': { - href: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_3_medium_thumbnail/public/2021-04/Zachary_Sage.jpg', + links: { + '1_1_square_medium_thumbnail': { + href: 'https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/1_1_square_medium_thumbnail/public/2021-04/Zachary_Sage.jpg', meta: { linkParams: { width: 151, diff --git a/src/templates/globals/header/TopNav.tsx b/src/templates/globals/header/TopNav.tsx index 7cda374b2..771625503 100644 --- a/src/templates/globals/header/TopNav.tsx +++ b/src/templates/globals/header/TopNav.tsx @@ -1,4 +1,4 @@ -import Image from '@/templates/common/image' +import Image from 'next/image' export const TopNav = () => { return ( diff --git a/src/templates/layouts/event/index.tsx b/src/templates/layouts/event/index.tsx index 16a8bd65d..586f138fe 100644 --- a/src/templates/layouts/event/index.tsx +++ b/src/templates/layouts/event/index.tsx @@ -56,7 +56,13 @@ export const Event = ({

{title}

{/* Image */} - {image && } + {image && ( + + )} {/* Description */} {description &&

{description}

} diff --git a/src/templates/layouts/newsStory/index.test.tsx b/src/templates/layouts/newsStory/index.test.tsx index f5f7324c2..dd3f24101 100644 --- a/src/templates/layouts/newsStory/index.test.tsx +++ b/src/templates/layouts/newsStory/index.test.tsx @@ -4,7 +4,7 @@ import { NewsStory } from './index' const mediaImage: MediaImage = { id: '3', - link: { + links: { '2_1_large': { href: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_1_large/public/2019-05/doctor-year2019-decker-480_0.jpg', meta: { @@ -19,7 +19,6 @@ const mediaImage: MediaImage = { title: '', width: 700, height: 350, - url: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_1_large/public/2019-05/doctor-year2019-decker-480_0.jpg', } const data = { diff --git a/src/templates/layouts/newsStory/newsStory.stories.ts b/src/templates/layouts/newsStory/newsStory.stories.ts index 686aa5d88..58fa7fae5 100644 --- a/src/templates/layouts/newsStory/newsStory.stories.ts +++ b/src/templates/layouts/newsStory/newsStory.stories.ts @@ -4,7 +4,7 @@ import { NewsStory } from './index' const mediaImage: MediaImage = { id: '3d6716b3-fb66-4e63-9b21-bb9c024129d3', - link: { + links: { '2_1_large': { href: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_1_large/public/2019-05/doctor-year2019-decker-480_0.jpg', meta: { @@ -19,7 +19,6 @@ const mediaImage: MediaImage = { title: '', width: 700, height: 350, - url: 'https://s3-us-gov-west-1.amazonaws.com/content.www.va.gov/img/styles/2_1_large/public/2019-05/doctor-year2019-decker-480_0.jpg', } const meta: Meta = { diff --git a/src/templates/layouts/staffProfile/dataService.tsx b/src/templates/layouts/staffProfile/dataService.tsx index a711ca12c..b5f8dff4d 100644 --- a/src/templates/layouts/staffProfile/dataService.tsx +++ b/src/templates/layouts/staffProfile/dataService.tsx @@ -24,10 +24,10 @@ export const transformStaffProfileData = function ( return { id: entity.field_staff_profile.id, name: name, - thumbnail: queries.formatData('media--image', { - entity: entity.field_staff_profile.field_media, - cropType: '2_1_large', // TODO: Which cropType do we want here? - }), + thumbnail: queries.formatData( + 'media--image', + entity.field_staff_profile.field_media + ), linkToBio: entity.field_staff_profile.field_complete_biography_create, path: entity.field_staff_profile.field_entity?.entityUrl.path || null, description: entity.field_staff_profile.field_description, diff --git a/src/templates/layouts/staffProfile/index.tsx b/src/templates/layouts/staffProfile/index.tsx index 2bd0a8975..6d6a02bc3 100644 --- a/src/templates/layouts/staffProfile/index.tsx +++ b/src/templates/layouts/staffProfile/index.tsx @@ -25,6 +25,7 @@ export function StaffProfile({ )} diff --git a/src/templates/layouts/staffProfile/staffProfile.stories.ts b/src/templates/layouts/staffProfile/staffProfile.stories.ts index 21949dc54..ce4afb5fb 100644 --- a/src/templates/layouts/staffProfile/staffProfile.stories.ts +++ b/src/templates/layouts/staffProfile/staffProfile.stories.ts @@ -15,13 +15,19 @@ export const Full: Story = { id: '7783e76f-5aca-4d14-9f5e-fb00cc11e4da', name: 'Mr William Smathers', thumbnail: { - url: 'https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/2019-08/William_W_Smathers.jpg', alt: 'William W Smathers Headshot', title: 'William W Smathers', width: 110, height: 136, id: '', - link: {}, + links: { + '1_1_square_medium_thumbnail': { + href: 'https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/1_1_square_medium_thumbnail/public/2019-08/William_W_Smathers.jpg', + meta: { + linkParams: {}, + }, + }, + }, }, linkToBio: true, path: 'http:va.gov', diff --git a/src/templates/layouts/staffProfile/staffProfile.test.tsx b/src/templates/layouts/staffProfile/staffProfile.test.tsx index 938a5a545..027fd3d72 100644 --- a/src/templates/layouts/staffProfile/staffProfile.test.tsx +++ b/src/templates/layouts/staffProfile/staffProfile.test.tsx @@ -3,13 +3,12 @@ import { StaffProfile } from '@/templates/layouts/staffProfile/index' const thumbnail = { id: 'some-unique-id', - url: 'https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/2019-08/William_W_Smathers.jpg', alt: 'William W Smathers Headshot', title: 'William W Smathers', width: 110, height: 136, styles: {}, - link: { + links: { '2_1_large': { href: 'https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/sites/default/files/styles/1_1_square_medium_thumbnail/public/2019-08/William_W_Smathers.jpg', meta: { diff --git a/src/templates/layouts/storyListing/mockFormattedList.js b/src/templates/layouts/storyListing/mockFormattedList.js index 93c96485f..a2f05b46a 100644 --- a/src/templates/layouts/storyListing/mockFormattedList.js +++ b/src/templates/layouts/storyListing/mockFormattedList.js @@ -8,12 +8,15 @@ export const formattedStories = [ image: { id: 'e4db22b0-5802-405f-a526-a3a436bd4219', type: 'media--image', - link: {}, + links: { + '2_1_large': { + href: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-11/IMG_2876.JPG?h=38f1b9a2', + }, + }, alt: 'Caregiver Support event', width: 6240, height: 4160, title: '', - url: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-11/IMG_2876.JPG?h=38f1b9a2', }, link: '/butler-health-care/stories/celebrating-our-family-caregivers', introText: @@ -28,12 +31,15 @@ export const formattedStories = [ image: { id: 'cd5abddc-ecaa-4a82-bfcb-0eea7477dcc6', type: 'media--image', - link: {}, + links: { + '2_1_large': { + href: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-09/veteran-flu-prevention-toolkit-bulletinboard-v2.jpg?h=c9522600', + }, + }, alt: "Don't Pass Flu On", width: 5104, height: 2871, title: '', - url: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-09/veteran-flu-prevention-toolkit-bulletinboard-v2.jpg?h=c9522600', }, link: '/butler-health-care/stories/its-flu-shot-time', introText: @@ -49,12 +55,15 @@ export const formattedStories = [ image: { id: '33a81ceb-b5f0-4544-8967-d97214b8edaa', type: 'media--image', - link: {}, + links: { + '2_1_large': { + href: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-09/2-okay-to-ask-for-help-desktop-background.jpg?h=88bff24e', + }, + }, alt: 'Suicide Prevention Month', width: 960, height: 540, title: '', - url: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-09/2-okay-to-ask-for-help-desktop-background.jpg?h=88bff24e', }, link: '/butler-health-care/stories/this-suicide-prevention-month-the-butler-va-offers-veterans-support', introText: @@ -69,12 +78,15 @@ export const formattedStories = [ image: { id: 'b38b2e4e-5190-4492-9852-b7f5b21d40d5', type: 'media--image', - link: {}, + links: { + '2_1_large': { + href: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-08/va%20police%20officers%20standing%20-%20one%20male%20and%20one%20female.jpg?h=ec283f65', + }, + }, alt: 'va police officers standing - one male and one female', width: 5934, height: 4470, title: '', - url: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-08/va%20police%20officers%20standing%20-%20one%20male%20and%20one%20female.jpg?h=ec283f65', }, link: '/butler-health-care/stories/in-car-and-body-worn-cameras', introText: @@ -89,12 +101,15 @@ export const formattedStories = [ image: { id: '06013955-467f-46fc-a3a6-f5d85abb1fcb', type: 'media--image', - link: {}, + links: { + '2_1_large': { + href: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-06/IMG_0285.JPG?h=3e68e630', + }, + }, alt: 'telehealth conference', width: 6240, height: 4160, title: '', - url: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-06/IMG_0285.JPG?h=3e68e630', }, link: '/butler-health-care/stories/high-tech-high-touch-health-care', introText: @@ -109,12 +124,15 @@ export const formattedStories = [ image: { id: 'a4a15542-d71d-479c-92da-7a5a460ab71d', type: 'media--image', - link: {}, + links: { + '2_1_large': { + href: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-05/Feature%20Story_Chiro%20and%20Accu%20Team_2.jpg?h=6c1ae47b', + }, + }, alt: "Butler VA's Chiropractors and Acupuncturists", width: 4131, height: 3224, title: '', - url: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-05/Feature%20Story_Chiro%20and%20Accu%20Team_2.jpg?h=6c1ae47b', }, link: '/butler-health-care/stories/all-about-acupuncture-chiropractic-care', introText: @@ -129,12 +147,15 @@ export const formattedStories = [ image: { id: '7c58a640-8580-45c9-96fa-9e1d83c79c4b', type: 'media--image', - link: {}, + links: { + '2_1_large': { + href: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-04/Health%20Tech_Annie%20App%20Vet_1.jpeg', + }, + }, alt: 'Army Veteran Calvin Kasparek', width: 3024, height: 2076, title: '', - url: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-04/Health%20Tech_Annie%20App%20Vet_1.jpeg', }, link: '/butler-health-care/stories/its-a-help-system', introText: @@ -149,12 +170,15 @@ export const formattedStories = [ image: { id: 'ad24c19d-b093-40cb-9e94-55d9aae3ef7e', type: 'media--image', - link: {}, + links: { + '2_1_large': { + href: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-03/Feature%20Story_TeleAudiology%20%281%29_0.jpg?h=e40710da', + }, + }, alt: 'Telehealth appointment', width: 4495, height: 4160, title: '', - url: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-03/Feature%20Story_TeleAudiology%20%281%29_0.jpg?h=e40710da', }, link: '/butler-health-care/stories/tele-audiology-now-available', introText: @@ -169,12 +193,15 @@ export const formattedStories = [ image: { id: 'a5a7a4c7-413e-48b6-a980-d8278d55808d', type: 'media--image', - link: {}, + links: { + '2_1_large': { + href: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-02/Vet%20Chat_Sue.jpg?h=0c60b38b', + }, + }, alt: 'U.S. Army and Army National Guard Veteran Sue Waldoch ', width: 3708, height: 4726, title: '', - url: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-02/Vet%20Chat_Sue.jpg?h=0c60b38b', }, link: '/butler-health-care/stories/living-my-mission-aspiration-and-purpose', introText: @@ -189,12 +216,15 @@ export const formattedStories = [ image: { id: 'c46ec4c9-c47a-47f7-9b49-489a5520feff', type: 'media--image', - link: {}, + links: { + '2_1_large': { + href: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-01/Equine%20Web%20Story.jpg?h=5eb487b6', + }, + }, alt: 'grandfather and granddaughter riding horses together', width: 2687, height: 1839, title: '', - url: 'https://prod.cms.va.gov/sites/default/files/styles/2_1_large/public/2023-01/Equine%20Web%20Story.jpg?h=5eb487b6', }, link: '/butler-health-care/stories/equine-therapy-community-partnerships', introText: diff --git a/src/types/formatted/media.ts b/src/types/formatted/media.ts index 25fef501e..ee6d14b1e 100644 --- a/src/types/formatted/media.ts +++ b/src/types/formatted/media.ts @@ -1,8 +1,8 @@ -export type MediaImageLink = { +export type MediaImageLinks = { [key: string]: { href: string - meta: { - linkParams: { + meta?: { + linkParams?: { width?: number height?: number } @@ -14,11 +14,7 @@ export type MediaImage = { id: string alt: string title: string - url: string width: number height: number - link: MediaImageLink - imageStyle?: string - className?: string - style?: string + links: MediaImageLinks }