Skip to content

Commit

Permalink
feat(@dpc-sdp/ripple-tide-landing-page): moved data driven components…
Browse files Browse the repository at this point in the history
… feature into core
  • Loading branch information
jeffdowdle committed Dec 11, 2024
1 parent 1cbf987 commit 39f0cc3
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 2 deletions.
19 changes: 19 additions & 0 deletions examples/nuxt-app/layers/example-data-driven-component/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## About this layer

An example of setting up a data driven component for testing purposes

Data driven components can be registered in the Nuxt `app.config` file:

```ts
export default defineAppConfig({
ripple: {
dataDrivenComponents: {
// add key of field_data_driven_component and value of component name to render
// eg: find_a_council_map: 'VicCouncilLookup'
example_ddc: 'ExampleDDC'
}
}
})
```

Note that the vue component (e.g. ExampleDDC) must be declared globally for this to work, see https://nuxt.com/docs/guide/directory-structure/components.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default defineAppConfig({
ripple: {
featureFlags: {
contentCollectionSearchConnector: 'elasticsearch'
},
dataDrivenComponents: {
// add key of field_data_driven_component and value of component name to render
// eg: find_a_council_map: 'VicCouncilLookup'
example_ddc: 'ExampleDDC'
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<h3>{{ title }}</h3>
<div v-html="description" />
<p>{{ testCustomProp }}</p>
</template>

<script setup lang="ts">
interface Props {
title: string
description: string
testCustomProp: string
}
defineProps<Props>()
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { defineNuxtConfig } from 'nuxt/config'

export default defineNuxtConfig({})
3 changes: 2 additions & 1 deletion examples/nuxt-app/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export default defineNuxtConfig({
'./layers/example-components',
'./layers/fixture-api',
'./layers/map-features',
'./layers/ripple-ui-forms-ext'
'./layers/ripple-ui-forms-ext',
'./layers/example-data-driven-component'
],
// Nuxt devtools
sourcemap: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,9 @@ Feature: Home page
Then the dataLayer should include the following events
| event | element_id | element_text | label | file_name | file_extension | type | component |
| file_download | page-component-1951 | Download it | Complex image | medium.png | png | image | rpl-media-embed |

@mockserver
Scenario: Page component - Data driven component
Then a custom data driven component with ID "3553540" should exist with title "Test data driven title" and have the properties
| description | testCustomProp |
| Test data driven desc | testCustomValue |
12 changes: 12 additions & 0 deletions examples/nuxt-app/test/fixtures/landingpage/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,18 @@
"allowFullscreen": true,
"showTitle": true
}
},
{
"uuid": "0aa14648-604d-4aab-833a-bbce065433f4",
"component": "ExampleDDC",
"id": "3553540",
"props": {
"title": "Test data driven title",
"description": "<p>Test data driven desc</p>",
"field": "example_ddc",
"component": "ExampleDDC",
"testCustomProp": "testCustomValue"
}
}
],
"meta": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Then, DataTable } from '@badeball/cypress-cucumber-preprocessor'

Then(
'a custom data driven component with ID {string} should exist with title {string} and have the properties',
(id: string, title: string, dataTable: DataTable) => {
const data = dataTable.hashes()[0]

cy.get(`[data-component-id="${id}"]`).as('component')
cy.get('@component').should('exist')
cy.get(`@component`).should(
'have.attr',
'data-component-type',
'ExampleDDC'
)
cy.get('@component').within(() => {
cy.get(`h3`).should('have.text', title)
})

cy.get('@component').should('contain', data.description)
cy.get('@component').should('contain', data.testCustomProp)
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ import './category-grid'
import './content-collection'
import './custom-collection'
import './social-share'
import './data-driven-component'
4 changes: 4 additions & 0 deletions packages/ripple-tide-landing-page/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ export default defineAppConfig({
ripple: {
featureFlags: {
contentCollectionSearchConnector: 'elasticsearch'
},
dataDrivenComponents: {
// add key of field_data_driven_component and value of component name to render
// eg: find_a_council_map: 'VicCouncilLookup'
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<template>
<DevOnly>
<div class="rpl-callout callout-error">
<h3>Data driven component {{ component }} not found</h3>
<p>Check the component mapping for {{ field }} in app.config</p>
</div>
</DevOnly>
</template>

<script setup lang="ts">
interface Props {
component: string
field: string
}
defineProps<Props>()
</script>

<style>
.callout-error {
--rpl-clr-accent: var(--rpl-clr-error);
--rpl-clr-accent-alt: var(--rpl-clr-error-light);
}
</style>
4 changes: 3 additions & 1 deletion packages/ripple-tide-landing-page/mapping/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import complexImageMapping from './components/complex-image/complex-image-mappin
import dataTableMapping from './components/data-table/data-table-mapping'
import compactCardsMapping from './components/compact-cards/compact-cards-mapping'
import openFormsMapping from './components/openforms/openforms-mapping'
import dataDrivenComponentMapping from './components/data-driven-component/data-driven-component-mapping'

const mappings: {
[key: string]: {
Expand All @@ -45,7 +46,8 @@ const mappings: {
'paragraph--complex_image': complexImageMapping,
'paragraph--data_table': dataTableMapping,
'paragraph--compact_card_collection': compactCardsMapping,
'paragraph--form_embed_openforms': openFormsMapping
'paragraph--form_embed_openforms': openFormsMapping,
'paragraph--data_driven_component': dataDrivenComponentMapping
}

// Add reusable include on whitelisted paragraph types
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* eslint-disable no-prototype-builtins */
import type { TideDynamicPageComponent } from '@dpc-sdp/ripple-tide-api/types'
import { logger } from '@dpc-sdp/ripple-tide-api'
import { useAppConfig } from '#imports'

export interface ITideDataDrivenComponent {
component?: string
description: string
title: string
field?: string
data?: unknown
}

interface IDDCAppConfig {
ripple?: {
dataDrivenComponents?: Record<string, string>
}
}

export const dataDrivenComponentMapping = (
field: any
): TideDynamicPageComponent<ITideDataDrivenComponent> => {
const getComponent = (field: any) => {
const appConfig = useAppConfig() as IDDCAppConfig
if (
appConfig?.ripple?.dataDrivenComponents?.hasOwnProperty(
field.field_data_driven_component
)
) {
return appConfig.ripple.dataDrivenComponents[
field.field_data_driven_component
]
}
return 'TideLandingPageDataDrivenCmpError'
}
let dataProps = {}
try {
dataProps = JSON.parse(field.field_configuration)
} catch (error) {
logger.error(`Error parsing data driven component extra data`, error)
}

return {
component: getComponent(field),
id: `${field.drupal_internal__id}`,
props: {
title: field.field_paragraph_title,
description: field.field_paragraph_body?.processed,
field: field.field_data_driven_component,
component: getComponent(field),
...dataProps
}
}
}

export default {
includes: [],
mapping: dataDrivenComponentMapping,
contentTypes: ['landing_page']
}

0 comments on commit 39f0cc3

Please sign in to comment.