Skip to content

Commit

Permalink
Add events query/formatter/layout (#264)
Browse files Browse the repository at this point in the history
  • Loading branch information
jtmst authored Dec 12, 2023
1 parent 0256251 commit e4ddfaa
Show file tree
Hide file tree
Showing 19 changed files with 1,470 additions and 5 deletions.
22 changes: 22 additions & 0 deletions playwright/tests/event.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const { test, expect } = require('../utils/next-test')

test.describe('Event Page', () => {
test('Event page renders with correct title and details', async ({
page,
}) => {
await page.goto('/central-iowa-health-care/events/52265/')
await expect(page.locator('h1')).toHaveText('Pickleball Club') // Replace with actual event title
await expect(page.locator('.va-introtext')).toContainText('Pickleball') // Replace with actual event description
})

test('Should render without a11y errors', async ({
page,
makeAxeBuilder,
}) => {
await page.goto('/central-iowa-health-care/events/52265/')

const accessibilityScanResults = await makeAxeBuilder().analyze()

expect(accessibilityScanResults.violations).toEqual([])
})
})
4 changes: 4 additions & 0 deletions src/assets/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ body {
margin-top: 0;
padding-top: 1.25rem;
}

.recurring-event {
max-width: 140px;
}
86 changes: 86 additions & 0 deletions src/data/queries/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import {
QueryData,
QueryFormatter,
QueryOpts,
QueryParams,
} from 'next-drupal-query'
import { drupalClient } from '@/lib/drupal/drupalClient'
import { queries } from '.'
import { NodeEvent } from '@/types/dataTypes/drupal/node'
import { Event } from '@/types/dataTypes/formatted/event'
import { GetServerSidePropsContext } from 'next'
import { MediaImage } from '@/types/dataTypes/formatted/media'

export const params: QueryParams<null> = () => {
return queries
.getParams()
.addInclude([
'field_media',
'field_media.image',
'field_listing',
'field_administration',
'field_facility_location',
])
}

// Define the option types for the data loader.
export type EventDataOpts = QueryOpts<{
id: string
context?: GetServerSidePropsContext
}>

export const data: QueryData<EventDataOpts, NodeEvent> = async (
opts
): Promise<NodeEvent> => {
const entity = opts?.context?.preview
? // need to use getResourceFromContext for unpublished revisions
await drupalClient.getResourceFromContext<NodeEvent>(
'node--event',
opts.context,
{
params: params().getQueryObject(),
}
)
: // otherwise just lookup by uuid
await drupalClient.getResource<NodeEvent>('node--event', opts.id, {
params: params().getQueryObject(),
})
return entity
}

export const formatter: QueryFormatter<NodeEvent, Event> = (
entity: NodeEvent
) => {
return {
id: entity.id,
entityId: entity.drupal_internal__nid,
entityPath: entity.path.alias,
type: entity.type,
published: entity.status,
title: entity.title,
image: queries.formatData('media--image', {
entity: entity.field_media,
cropType: '2_1_large',
}) as MediaImage,
date: entity.created,
breadcrumbs: entity.breadcrumbs,
socialLinks: {
path: entity.path.alias,
title: entity.title,
},
metatags: entity.metatag,
listing: entity.field_listing.path.alias,
additionalInfo: entity.field_additional_information_abo,
address: entity.field_address,
locationHumanReadable: entity.field_location_humanreadable,
eventCTA: entity.field_event_cta,
cost: entity.field_event_cost,
datetimeRange: entity.field_datetime_range_timezone,
facilityLocation: entity.field_facility_location,
body: entity.field_body,
locationType: entity.field_location_type,
description: entity.field_description,
link: entity.field_link,
urlOfOnlineEvent: entity.field_url_of_an_online_event,
}
}
2 changes: 2 additions & 0 deletions src/data/queries/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import * as Wysiwyg from './wysiwyg'
import * as StaticPathResources from './staticPathResources'
import * as HeaderFooter from './headerFooter'
import * as PromoBlock from './promoBlock'
import * as Event from './event'
import { RESOURCE_TYPES } from '@/lib/constants/resourceTypes'

export const QUERIES_MAP = {
Expand All @@ -25,6 +26,7 @@ export const QUERIES_MAP = {
'node--news_story--teaser': NewsStoryTeaser,
'node--story_listing': StoryListing,
'node--q_a': QuestionAnswer,
'node--event': Event,
'node--person_profile': PersonProfile,
'node--landing_page': BenefitsHub, // "Benefits Hub Landing Page"
'paragraph--audience_topics': AudienceTopics,
Expand Down
91 changes: 91 additions & 0 deletions src/data/queries/tests/__snapshots__/event.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`node--event formatData outputs formatted data 1`] = `
{
"additionalInfo": null,
"address": {
"address_line1": "9000 Douglas Ave",
"address_line2": "",
"administrative_area": "IA",
"country_code": "US",
"langcode": "en",
"locality": "Urbandale",
},
"body": {
"format": "rich_text",
"processed": "<p>Pickleball Club</p>
<p>Meets Thursdays from 9 to 11 a.m. </p>
<p>Contact Kay Queck (515) 214-4578</p>",
"value": "<p>Pickleball Club</p>
<p>Meets Thursdays from 9 to 11 a.m.&nbsp;</p>
<p>Contact Kay Queck (515) 214-4578</p>
",
},
"breadcrumbs": [
{
"options": [],
"title": "Home",
"uri": "https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/",
},
{
"options": [],
"title": "VA Central Iowa health care",
"uri": "https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/central-iowa-health-care",
},
{
"options": [],
"title": "Events",
"uri": "https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/central-iowa-health-care/events",
},
{
"options": [],
"title": "Pickleball Club",
"uri": "https://content-build-medc0xjkxm4jmpzxl3tfbcs7qcddsivh.ci.cms.va.gov/central-iowa-health-care/events/52265",
},
],
"cost": "Free",
"date": "2022-12-30T14:49:05+00:00",
"datetimeRange": [
{
"duration": 120,
"end_value": "2023-09-07T16:00:00+00:00",
"rrule": 180,
"rrule_index": 1,
"timezone": "America/Chicago",
"value": "2023-09-07T14:00:00+00:00",
},
{
"duration": 120,
"end_value": "2023-09-14T16:00:00+00:00",
"rrule": 180,
"rrule_index": 2,
"timezone": "America/Chicago",
"value": "2023-09-14T14:00:00+00:00",
},
],
"description": "Pickleball ",
"entityId": 52265,
"entityPath": "/central-iowa-health-care/events/52265",
"eventCTA": null,
"facilityLocation": null,
"id": "16349f16-be65-46e3-9660-1d3d598a4a0b",
"image": null,
"link": null,
"listing": "/central-iowa-health-care/events",
"locationHumanReadable": "Walker Johnston Park",
"locationType": "non_facility",
"metatags": null,
"published": true,
"socialLinks": {
"path": "/central-iowa-health-care/events/52265",
"title": "Pickleball Club",
},
"title": "Pickleball Club",
"type": "node--event",
"urlOfOnlineEvent": null,
}
`;
23 changes: 23 additions & 0 deletions src/data/queries/tests/event.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { NodeEvent } from '@/types/dataTypes/drupal/node'
import { queries } from '@/data/queries'
import mockData from '@/mocks/event.mock.json'

const nodeEventMock: NodeEvent = mockData

describe('node--event formatData', () => {
let windowSpy

beforeEach(() => {
windowSpy = jest.spyOn(window, 'window', 'get')
})

afterEach(() => {
windowSpy.mockRestore()
})

test('outputs formatted data', () => {
windowSpy.mockImplementation(() => undefined)
const formattedData = queries.formatData('node--event', nodeEventMock)
expect(formattedData).toMatchSnapshot()
})
})
1 change: 1 addition & 0 deletions src/lib/constants/resourceTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const RESOURCE_TYPES = {
STORY_LISTING: 'node--story_listing',
STORY: 'node--news_story',
EVENT: 'node--event',
// QA: 'node--q_a',
} as const

Expand Down
1 change: 0 additions & 1 deletion src/lib/drupal/staticProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ export async function getStaticPropsResource(
context
)
}

// All others
return getDefaultStaticPropsResource(resourceType, pathInfo, context)
}
78 changes: 78 additions & 0 deletions src/lib/utils/date.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import {
parseSeconds,
parseDate,
getDateParts,
formatDateObject,
deriveMostRecentDate,
deriveFormattedTimestamp,
isEventInPast,
} from './date'

describe('isISOString', () => {
Expand Down Expand Up @@ -224,3 +228,77 @@ describe('getDateParts', () => {
})
})
})

describe('formatDateObject', () => {
it('should add startTime, endTime, value, and endValue to each date object', () => {
const datetimeRange = [
{
value: new Date('2023-09-07T14:00:00Z'),
end_value: new Date('2023-09-07T16:00:00Z'),
},
]
const result = formatDateObject(datetimeRange)
expect(result[0]).toHaveProperty('startTime')
expect(result[0]).toHaveProperty('endTime')
expect(result[0]).toHaveProperty('value')
expect(result[0]).toHaveProperty('endValue')
})
})

describe('deriveMostRecentDate', () => {
it('should return the closest future event', () => {
const mockCurrentTime = new Date('2023-08-01T12:00:00Z').getTime()
jest.spyOn(Date, 'now').mockImplementation(() => mockCurrentTime)

const datetimeRange = [
{ value: new Date('2023-07-01T14:00:00Z').getTime() / 1000 }, // Past event
{ value: new Date('2023-09-01T14:00:00Z').getTime() / 1000 }, // Closest future event
{ value: new Date('2023-10-01T14:00:00Z').getTime() / 1000 }, // Later future event
]

const closestEvent = deriveMostRecentDate(datetimeRange)
expect(closestEvent.value).toEqual(datetimeRange[1].value)

jest.restoreAllMocks()
})

it('should return the most recent past event if no future events', () => {
const mockCurrentTime = new Date('2023-12-01T12:00:00Z').getTime()
jest.spyOn(Date, 'now').mockImplementation(() => mockCurrentTime)

const datetimeRange = [
{ value: new Date('2023-07-01T14:00:00Z').getTime() / 1000 }, // Earlier past event
{ value: new Date('2023-11-01T14:00:00Z').getTime() / 1000 }, // Most recent past event
]

const closestEvent = deriveMostRecentDate(datetimeRange)
expect(closestEvent.value).toEqual(datetimeRange[1].value)

jest.restoreAllMocks()
})
})
describe('deriveFormattedTimestamp', () => {
it('should correctly format the event timestamp', () => {
const datetime = {
startTime: new Date('2023-09-07T14:00:00Z'),
endTime: new Date('2023-09-07T16:00:00Z'),
}
const result = deriveFormattedTimestamp(datetime)

expect(result).toMatch(
/Thu, Sep 7, 2023, \d{1,2}:\d{2} [APM]{2} [A-Z]{2,4} – \d{1,2}:\d{2} [APM]{2} [A-Z]{2,4}/
)
})
})

describe('isEventInPast', () => {
it('should return true for past events', () => {
const pastEventTime = new Date('2020-01-01').getTime() / 1000
expect(isEventInPast(pastEventTime)).toBeTruthy()
})

it('should return false for future events', () => {
const futureEventTime = new Date('2099-01-01').getTime() / 1000
expect(isEventInPast(futureEventTime)).toBeFalsy()
})
})
Loading

0 comments on commit e4ddfaa

Please sign in to comment.