Skip to content

Commit

Permalink
Render additional info summary PDF (#1452)
Browse files Browse the repository at this point in the history
* Use form definition instead of schemas when rendering summary PDF

* Render additional information in summary PDF

* Regenerate assets

* Regenerate snapshots

* Extract TermsAndConditions to own component

---------

Co-authored-by: Marek Bodinger <marek.bodinger@gmail.com>
  • Loading branch information
MarekBodingerBA and MarekBodinger authored Sep 24, 2024
1 parent be621d8 commit 631ad4f
Show file tree
Hide file tree
Showing 21 changed files with 82 additions and 30 deletions.
2 changes: 1 addition & 1 deletion forms-shared/src/generated-assets/summaryPdfCss.ts

Large diffs are not rendered by default.

88 changes: 70 additions & 18 deletions forms-shared/src/summary-pdf/SummaryPdf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ import {
} from '../summary-renderer/SummaryRenderer'
import { SummaryJsonForm } from '../summary-json/summaryJsonTypes'
import Markdown from 'react-markdown'
import { generalTermsAndConditions } from '../definitions/termsAndConditions'
import cx from 'classnames'
import { ValidatedSummary } from '../summary-renderer/validateSummary'
import { FormDefinition } from '../definitions/formDefinitionTypes'
import { GenericObjectType } from '@rjsf/utils'
import { renderFormAdditionalInfo } from '../string-templates/renderTemplate'

type SummaryPdfProps = {
formDefinition: FormDefinition
cssToInject: string
formData: GenericObjectType
summaryJson: SummaryJsonForm
validatedSummary: ValidatedSummary
}
Expand Down Expand Up @@ -111,7 +115,69 @@ const ArrayItemRenderer = ({ arrayItem, children }: SummaryArrayItemRendererProp
)
}

export const SummaryPdf = ({ cssToInject, summaryJson, validatedSummary }: SummaryPdfProps) => {
const SummaryMarkdown = ({ className, children }: { className: string; children: string }) => {
return (
<Markdown
className={className}
components={{
h2: ({ children }) => <h2 className="text-h-xl font-semibold mb-4">{children}</h2>,
h3: ({ children }) => <h3 className="text-h-lg font-semibold mb-3">{children}</h3>,
h4: ({ children }) => <h4 className="text-h-md font-semibold mb-2">{children}</h4>,
h5: ({ children }) => <h5 className="text-h-base font-semibold mb-2">{children}</h5>,
h6: ({ children }) => <h6 className="text-h-xs font-semibold mb-2">{children}</h6>,
p: ({ children }) => <p className="text-p-md font-normal mb-4">{children}</p>,
strong: ({ children }) => <strong className="font-semibold">{children}</strong>,
ol: ({ children }) => <ol className="list-decimal pl-8 mb-4">{children}</ol>,
ul: ({ children }) => <ul className="list-disc pl-8 mb-4">{children}</ul>,
li: ({ children }) => <li className="text-p-md font-normal mb-2">{children}</li>,
a: ({ children, href }) => (
<a href={href} className="font-semibold underline" target="_blank">
{children}
</a>
),
}}
>
{children}
</Markdown>
)
}

const AdditionalInfo = ({
formDefinition,
formData,
}: Pick<SummaryPdfProps, 'formDefinition' | 'formData'>) => {
const additionalInfo = renderFormAdditionalInfo(formDefinition, formData)

if (!additionalInfo) {
return null
}

return (
<div className="flex flex-col gap-4">
<h2 className="text-xl font-semibold">Doplňujúce informácie</h2>
<SummaryMarkdown className="rounded-xl bg-gray-50 p-6">{additionalInfo}</SummaryMarkdown>
</div>
)
}

const TermsAndConditions = ({ formDefinition }: Pick<SummaryPdfProps, 'formDefinition'>) => {
return (
<div className="flex flex-col gap-4">
<h2 className="text-xl font-semibold">Ochrana osobných údajov</h2>
<SummaryMarkdown className="rounded-xl bg-gray-50 p-6">
{formDefinition.termsAndConditions}
</SummaryMarkdown>
</div>
)
}

export const SummaryPdf = ({
formDefinition,
cssToInject,
summaryJson,
validatedSummary,
formData,
}: SummaryPdfProps) => {
return (
<html>
<head>
Expand All @@ -133,22 +199,8 @@ export const SummaryPdf = ({ cssToInject, summaryJson, validatedSummary }: Summa
renderNoneValue={NoneValueRenderer}
renderInvalidValue={InvalidValueRenderer}
/>
<div className="flex flex-col gap-4">
<h2 className="text-xl font-semibold">Ochrana osobných údajov</h2>
<Markdown
className="rounded-xl bg-gray-50 p-6"
components={{
a: ({ children, href }) => (
<a href={href} className="font-semibold underline" target="_blank">
{children}
</a>
),
}}
>
{/* TODO: Use from form definition. */}
{generalTermsAndConditions}
</Markdown>
</div>
<AdditionalInfo formDefinition={formDefinition} formData={formData} />
<TermsAndConditions formDefinition={formDefinition} />
</div>
</body>
</html>
Expand Down
16 changes: 9 additions & 7 deletions forms-shared/src/summary-pdf/renderSummaryPdf.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import type { Browser } from 'playwright'
import { GenericObjectType, RJSFSchema, UiSchema } from '@rjsf/utils'
import { GenericObjectType } from '@rjsf/utils'
import { getSummaryJsonNode } from '../summary-json/getSummaryJsonNode'
import { renderToString } from 'react-dom/server'
import { SummaryPdf } from './SummaryPdf'
Expand All @@ -9,10 +9,10 @@ import { ClientFileInfo } from '../form-files/fileStatus'
import { mergeClientAndServerFilesSummary } from '../form-files/mergeClientAndServerFiles'
import { validateSummary } from '../summary-renderer/validateSummary'
import summaryPdfCss from '../generated-assets/summaryPdfCss'
import { FormDefinition } from '../definitions/formDefinitionTypes'

export type RenderSummaryPdfPayload = {
jsonSchema: RJSFSchema
uiSchema: UiSchema
formDefinition: FormDefinition
formData: GenericObjectType
/**
* Playwright must be installed and managed by the consumer of this function (e.g. in Docker) to run correctly, and is
Expand All @@ -27,23 +27,25 @@ export type RenderSummaryPdfPayload = {
* Renders a summary PDF from the given JSON schema, UI schema and data.
*/
export const renderSummaryPdf = async ({
jsonSchema,
uiSchema,
formDefinition,
formData,
launchBrowser,
clientFiles,
serverFiles,
}: RenderSummaryPdfPayload) => {
const summaryJson = getSummaryJsonNode(jsonSchema, uiSchema, formData)
const { schema, uiSchema } = formDefinition.schemas
const summaryJson = getSummaryJsonNode(schema, uiSchema, formData)

const fileInfos = mergeClientAndServerFilesSummary(clientFiles, serverFiles)
const validatedSummary = validateSummary(jsonSchema, formData, fileInfos)
const validatedSummary = validateSummary(schema, formData, fileInfos)

const renderedString = renderToString(
<SummaryPdf
formDefinition={formDefinition}
cssToInject={summaryPdfCss.toString()}
summaryJson={summaryJson}
validatedSummary={validatedSummary}
formData={formData}
></SummaryPdf>,
)
const browser = await launchBrowser()
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 1 addition & 2 deletions forms-shared/tests/summary-pdf/renderSummaryPdf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ describe('getSummaryJson', () => {
)

const pdfBuffer = await renderSummaryPdf({
jsonSchema: formDefinition.schemas.schema,
uiSchema: formDefinition.schemas.uiSchema,
formDefinition,
formData: exampleForm.formData,
launchBrowser: launchPlaywrightTest,
serverFiles: exampleForm.serverFiles,
Expand Down
3 changes: 1 addition & 2 deletions nest-forms-backend/src/convert/convert.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,7 @@ export default class ConvertService {
let pdfBuffer: Buffer
try {
pdfBuffer = await renderSummaryPdf({
jsonSchema: formDefinition.schemas.schema,
uiSchema: formDefinition.schemas.uiSchema,
formDefinition,
formData: jsonForm as GenericObjectType,
launchBrowser: () => chromium.launch(),
clientFiles,
Expand Down

0 comments on commit 631ad4f

Please sign in to comment.