diff --git a/src/Context.js b/src/Context.js index d6dc386f3..5272d7ecc 100644 --- a/src/Context.js +++ b/src/Context.js @@ -10,6 +10,7 @@ const FormContext = React.createContext({ introductionPageContent: '', loginRequired: false, loginOptions: [], + cosignLoginOptions: [], maintenanceMode: false, showProgressIndicator: true, showSummaryProgress: false, diff --git a/src/components/Button/OFButton.mdx b/src/components/Button/OFButton.mdx index 68e09c49d..6bfc521f1 100644 --- a/src/components/Button/OFButton.mdx +++ b/src/components/Button/OFButton.mdx @@ -16,33 +16,25 @@ aria attribute instead. More information on the Utrecht buttons can be found [here](https://nl-design-system.github.io/themes/?path=/docs/button--gemeente-utrecht). - - - - - - + + + + ### Links that look like buttons - - - - - + + + ### Button that looks like a link - - - + ## Icon buttons - - - - + + ## Disabled state diff --git a/src/components/CoSign/CoSign.stories.jsx b/src/components/CoSign/CoSign.stories.jsx index da5afda48..93942c86e 100644 --- a/src/components/CoSign/CoSign.stories.jsx +++ b/src/components/CoSign/CoSign.stories.jsx @@ -1,7 +1,7 @@ import CosignDone from './CosignDone'; export default { - title: 'Views / Co-sign done', + title: 'Views / Cosign / Done', component: CosignDone, args: { reportDownloadUrl: '#', @@ -9,5 +9,5 @@ export default { }; export const CoSignDone = { - name: 'Co-sign done', + name: 'CosignDone', }; diff --git a/src/components/CoSign/Cosign.jsx b/src/components/CoSign/Cosign.jsx index 6b22bbe95..ea371fd38 100644 --- a/src/components/CoSign/Cosign.jsx +++ b/src/components/CoSign/Cosign.jsx @@ -9,6 +9,7 @@ import {CosignSummary} from 'components/Summary'; import useFormContext from 'hooks/useFormContext'; import CosignDone from './CosignDone'; +import CosignStart from './CosignStart'; const initialState = { submission: null, @@ -60,6 +61,7 @@ const Cosign = () => { return ( + } /> { + const form = useFormContext(); + + const outagePluginId = useDetectAuthenticationOutage(); + const authErrors = useDetectAuthErrorMessages(); + + if (!form.active) { + throw new UnprocessableEntity('Unprocessable Entity', 422, 'Form not active', 'form-inactive'); + } + + const userIsFormDesigner = IsFormDesigner.getValue(); + if (!userIsFormDesigner && form.maintenanceMode) { + return ; + } + + if (outagePluginId) { + const loginOption = form.cosignLoginOptions.find( + option => option.identifier === outagePluginId + ); + if (!loginOption) throw new Error('Unknown login plugin identifier'); + return ( + + } + > + + + ); + } + + return ( + + + {userIsFormDesigner && form.maintenanceMode && } + + {!!authErrors ? : null} + + + + + + {}} + isolateCosignOptions={false} + /> + + + ); +}; + +export default CosignStart; diff --git a/src/components/CoSign/CosignStart.stories.js b/src/components/CoSign/CosignStart.stories.js new file mode 100644 index 000000000..fa481b98f --- /dev/null +++ b/src/components/CoSign/CosignStart.stories.js @@ -0,0 +1,51 @@ +import {withRouter} from 'storybook-addon-remix-react-router'; + +import {buildForm} from 'api-mocks'; +import {withForm} from 'story-utils/decorators'; + +import CosignStart from './CosignStart'; + +export default { + title: 'Views / Cosign / Start', + component: CosignStart, + decorators: [withForm, withRouter], + parameters: { + formContext: { + form: buildForm({ + loginRequired: true, + loginOptions: [ + { + identifier: 'digid', + label: 'DigiD', + url: '#', + logo: { + title: 'DigiD simulatie', + imageSrc: './digid.png', + href: 'https://www.digid.nl/', + appearance: 'dark', + }, + isForGemachtigde: false, + }, + ], + cosignLoginOptions: [ + { + identifier: 'digid', + label: 'DigiD', + url: 'http://localhost:8000/auth/digid/?next=http://localhost:8000/cosign&code=123', + logo: { + title: 'DigiD simulatie', + imageSrc: './digid.png', + href: 'https://www.digid.nl/', + appearance: 'dark', + }, + isForGemachtigde: false, + }, + ], + }), + }, + }, +}; + +export const Default = { + name: 'CosignStart', +}; diff --git a/src/components/FormStart/index.jsx b/src/components/FormStart/index.jsx index e229c9d8d..d0713c563 100644 --- a/src/components/FormStart/index.jsx +++ b/src/components/FormStart/index.jsx @@ -125,7 +125,13 @@ const FormStart = ({form, submission, onFormStart, onDestroySession, initialData isAuthenticated={isAuthenticated} /> ) : ( - + )} diff --git a/src/components/LoginOptions/LoginOptions.stories.jsx b/src/components/LoginOptions/LoginOptions.stories.jsx index e2526a15a..96a8789bf 100644 --- a/src/components/LoginOptions/LoginOptions.stories.jsx +++ b/src/components/LoginOptions/LoginOptions.stories.jsx @@ -1,4 +1,5 @@ import {expect, fn, userEvent, waitFor, within} from '@storybook/test'; +import {withRouter} from 'storybook-addon-remix-react-router'; import {buildForm} from 'api-mocks'; import {LiteralDecorator} from 'story-utils/decorators'; @@ -9,7 +10,10 @@ import LoginOptionsDisplay from './LoginOptionsDisplay'; export default { title: 'Composites / Login Options', component: LoginOptions, - decorators: [LiteralDecorator], + decorators: [LiteralDecorator, withRouter], + args: { + onFormStart: fn(), + }, argTypes: { form: {table: {disable: true}}, }, @@ -239,7 +243,7 @@ export const WithCoSignOption = { { identifier: 'digid', label: 'DigiD', - url: '#', + url: 'http://localhost:8000/auth/digid/?next=http://localhost:3000/form?_start=1', logo: { title: 'DigiD simulatie', imageSrc: './digid.png', diff --git a/src/components/LoginOptions/LoginOptionsDisplay.jsx b/src/components/LoginOptions/LoginOptionsDisplay.jsx index 0a2c3ecaa..2526fe6a2 100644 --- a/src/components/LoginOptions/LoginOptionsDisplay.jsx +++ b/src/components/LoginOptions/LoginOptionsDisplay.jsx @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import {FormattedMessage} from 'react-intl'; +import Body from 'components/Body'; import LoginButton from 'components/LoginButton'; import FormattedLoginOption from 'types/FormattedLoginOption'; import {getBEMClassName} from 'utils'; @@ -10,6 +11,7 @@ const LoginOptionsDisplay = ({ loginAsYourselfOptions, loginAsGemachtigdeOptions, cosignLoginOptions, + isolateCosignOptions = true, }) => { return (
@@ -37,13 +39,26 @@ const LoginOptionsDisplay = ({ )} {cosignLoginOptions?.length > 0 && ( -
-

- -

+
+ {isolateCosignOptions && ( + <> +

+ +

+ + + + + )}
{cosignLoginOptions.map(option => ( @@ -60,6 +75,7 @@ LoginOptionsDisplay.propTypes = { loginAsYourselfOptions: PropTypes.arrayOf(FormattedLoginOption).isRequired, loginAsGemachtigdeOptions: PropTypes.arrayOf(FormattedLoginOption).isRequired, cosignLoginOptions: PropTypes.arrayOf(FormattedLoginOption), + isolateCosignOptions: PropTypes.bool, }; export default LoginOptionsDisplay; diff --git a/src/components/LoginOptions/index.jsx b/src/components/LoginOptions/index.jsx index 32a742150..fc20ca24b 100644 --- a/src/components/LoginOptions/index.jsx +++ b/src/components/LoginOptions/index.jsx @@ -4,13 +4,15 @@ import {FormattedMessage} from 'react-intl'; import {ConfigContext} from 'Context'; import Literal from 'components/Literal'; -import {getLoginUrl} from 'components/utils'; +import {getCosignLoginUrl, getLoginUrl} from 'components/utils'; +import useQuery from 'hooks/useQuery'; import Types from 'types'; import LoginOptionsDisplay from './LoginOptionsDisplay'; -const LoginOptions = ({form, onFormStart, extraNextParams = {}}) => { +const LoginOptions = ({form, onFormStart, extraNextParams = {}, isolateCosignOptions = true}) => { const config = useContext(ConfigContext); + const queryParams = useQuery(); const loginAsYourselfOptions = []; const loginAsGemachtigdeOptions = []; @@ -35,9 +37,12 @@ const LoginOptions = ({form, onFormStart, extraNextParams = {}}) => { }); if (form.cosignLoginOptions) { + const cosignCode = queryParams.get('code'); form.cosignLoginOptions.forEach(option => { + const loginUrl = getCosignLoginUrl(option, cosignCode ? {code: cosignCode} : undefined); cosignLoginOptions.push({ ...option, + url: loginUrl, label: ( { e.preventDefault(); onFormStart(e, true); }, + 'data-testid': 'start-form', }; return ( @@ -73,6 +79,7 @@ const LoginOptions = ({form, onFormStart, extraNextParams = {}}) => { loginAsYourselfOptions={loginAsYourselfOptions} loginAsGemachtigdeOptions={loginAsGemachtigdeOptions} cosignLoginOptions={cosignLoginOptions} + isolateCosignOptions={isolateCosignOptions} /> ); @@ -83,6 +90,7 @@ LoginOptions.propTypes = { onFormStart: PropTypes.func.isRequired, extraParams: PropTypes.object, extraNextParams: PropTypes.object, + isolateCosignOptions: PropTypes.bool, }; export default LoginOptions; diff --git a/src/components/LoginOptions/tests.spec.jsx b/src/components/LoginOptions/tests.spec.jsx index 0c1cbddee..1e947afbe 100644 --- a/src/components/LoginOptions/tests.spec.jsx +++ b/src/components/LoginOptions/tests.spec.jsx @@ -1,56 +1,56 @@ -import {fireEvent} from '@testing-library/react'; +import {render, screen} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import messagesNL from 'i18n/compiled/nl.json'; import React from 'react'; -import {createRoot} from 'react-dom/client'; -import {act} from 'react-dom/test-utils'; import {IntlProvider} from 'react-intl'; +import {RouterProvider, createMemoryRouter} from 'react-router-dom'; import {buildForm} from 'api-mocks'; import {LiteralsProvider} from 'components/Literal'; import LoginOptions from './index'; -let container = null; -let root = null; -beforeEach(() => { - // setup a DOM element as a render target - container = document.createElement('div'); - document.body.appendChild(container); - root = createRoot(container); -}); - -afterEach(() => { - // cleanup on exiting - act(() => { - root.unmount(); - container.remove(); - root = null; - container = null; - }); -}); +const Wrapper = ({form, onFormStart}) => { + const router = createMemoryRouter( + [ + { + path: '/', + element: , + }, + ], + { + initialEntries: ['/'], + initialIndex: 0, + } + ); + + return ( + + + + + + ); +}; -it('Login not required, options wrapped in form tag', () => { +it('Login not required, options wrapped in form tag', async () => { + const user = userEvent.setup(); const form = buildForm({loginRequired: false, loginOptions: [], cosignLoginOptions: []}); const onFormStart = jest.fn(e => e.preventDefault()); - act(() => { - root.render( - - - - ); - }); + render(); - expect(container.firstChild.nodeName).toEqual('FORM'); - const anonymousStartButton = container.getElementsByTagName('button')[0]; - expect(anonymousStartButton).not.toBeUndefined(); + expect(await screen.findByTestId('start-form')).toBeInTheDocument(); - fireEvent.click(anonymousStartButton); + const anonymousStartButton = screen.getByRole('button', {name: 'Begin Form'}); + expect(anonymousStartButton).toBeVisible(); + + await user.click(anonymousStartButton); expect(onFormStart).toHaveBeenCalled(); }); -it('Login required, options not wrapped in form tag', () => { +it('Login required, options not wrapped in form tag', async () => { const form = buildForm({ loginRequired: true, loginOptions: [ @@ -77,28 +77,22 @@ it('Login required, options not wrapped in form tag', () => { href: 'https://open-forms.nl/digid-form/', }; - act(() => { - root.render( - - - - ); - }); + render(); const expectedUrl = new URL(form.loginOptions[0].url); expectedUrl.searchParams.set('next', 'https://open-forms.nl/digid-form/?_start=1'); - expect(container.firstChild.nodeName).toEqual('DIV'); - const anonymousStartButton = container.getElementsByTagName('button')[0]; - expect(anonymousStartButton).toBeUndefined(); + const digidLoginLink = await screen.findByRole('link', {name: 'Inloggen met DigiD'}); + expect(digidLoginLink).toBeVisible(); + expect(digidLoginLink.href).toEqual(expectedUrl.toString()); - const digidLoginButton = container.getElementsByTagName('a')[0]; - expect(digidLoginButton.href).toEqual(expectedUrl.toString()); + expect(screen.queryByTestId('start-form')).not.toBeInTheDocument(); + expect(screen.queryAllByRole('button')).toHaveLength(0); window.location = location; }); -it('Login button has the right URL after cancelling log in', () => { +it('Login button has the right URL after cancelling log in', async () => { const form = buildForm({ loginRequired: true, loginOptions: [ @@ -126,23 +120,14 @@ it('Login button has the right URL after cancelling log in', () => { href: 'https://open-forms.nl/digid-form/?_start=1&_digid-message=login-cancelled', }; - act(() => { - root.render( - - - - ); - }); + render(); const expectedUrl = new URL(form.loginOptions[0].url); expectedUrl.searchParams.set('next', 'https://open-forms.nl/digid-form/?_start=1'); - expect(container.firstChild.nodeName).toEqual('DIV'); - const anonymousStartButton = container.getElementsByTagName('button')[0]; - expect(anonymousStartButton).toBeUndefined(); - - const digidLoginButton = container.getElementsByTagName('a')[0]; - expect(digidLoginButton.href).toEqual(expectedUrl.toString()); + const digidLoginLink = await screen.findByRole('link', {name: 'Inloggen met DigiD'}); + expect(digidLoginLink).toBeVisible(); + expect(digidLoginLink.href).toEqual(expectedUrl.toString()); window.location = location; }); diff --git a/src/components/PostCompletionViews/ConfirmationView.jsx b/src/components/PostCompletionViews/ConfirmationView.jsx index 4b73d251c..fcf20653c 100644 --- a/src/components/PostCompletionViews/ConfirmationView.jsx +++ b/src/components/PostCompletionViews/ConfirmationView.jsx @@ -44,8 +44,13 @@ const ConfirmationViewDisplay = ({downloadPDFText}) => { const paymentStatus = location?.state?.status; const userAction = location?.state?.userAction; - const {publicReference, reportDownloadUrl, confirmationPageContent, mainWebsiteUrl} = - useContext(SubmissionStatusContext); + const { + publicReference, + reportDownloadUrl, + confirmationPageTitle, + confirmationPageContent, + mainWebsiteUrl, + } = useContext(SubmissionStatusContext); const paymentStatusMessage = STATUS_MESSAGES[paymentStatus]; let Wrapper = React.Fragment; @@ -80,11 +85,13 @@ const ConfirmationViewDisplay = ({downloadPDFText}) => { defaultMessage: 'Confirmation', })} header={ - + confirmationPageTitle || ( + + ) } body={body} mainWebsiteUrl={mainWebsiteUrl} diff --git a/src/components/PostCompletionViews/ConfirmationViewCosign.stories.js b/src/components/PostCompletionViews/ConfirmationViewCosign.stories.js new file mode 100644 index 000000000..6e3f7e3be --- /dev/null +++ b/src/components/PostCompletionViews/ConfirmationViewCosign.stories.js @@ -0,0 +1,73 @@ +import {withRouter} from 'storybook-addon-remix-react-router'; + +import {buildForm} from 'api-mocks'; +import {AnalyticsToolsDecorator, withForm, withSubmissionPollInfo} from 'story-utils/decorators'; + +import {ConfirmationViewDisplay} from './ConfirmationView'; + +export default { + title: 'Views / Cosign / Submission completed', + component: ConfirmationViewDisplay, + decorators: [withForm, AnalyticsToolsDecorator, withSubmissionPollInfo, withRouter], + args: { + publicReference: 'OF-1234', + reportDownloadUrl: '/dummy', + confirmationPageTitle: 'Request incomplete', + confirmationPageContent: ` +

Your request is not yet complete.

+

Cosigning required

+

+ You can start the cosigning immediately by clicking the button below. +

+

+ + + +

+

Alternative instructions

+

+ We've sent an email with a cosign request to + info@example.com. Once the submission has + been cosigned we will start processing your request. +

+

+ If you need to contact us about this submission, you can use the reference + OF-1234. +

+ `, + mainWebsiteUrl: 'https://example.com', + paymentUrl: '', + }, + argTypes: { + paymentUrl: {control: false}, + }, + parameters: { + formContext: { + form: buildForm({ + cosignLoginOptions: [ + { + identifier: 'digid', + label: 'DigiD', + url: 'http://localhost:8000/auth/digid/?next=http://localhost:8000/cosign&code=123', + logo: { + title: 'DigiD simulatie', + imageSrc: './digid.png', + href: 'https://www.digid.nl/', + appearance: 'dark', + }, + isForGemachtigde: false, + }, + ], + }), + }, + reactRouter: { + location: {state: {}}, + }, + }, +}; + +export const Default = { + name: 'Submission completed', +}; diff --git a/src/components/PostCompletionViews/PostCompletionView.jsx b/src/components/PostCompletionViews/PostCompletionView.jsx index a3a9de15e..648a08ab9 100644 --- a/src/components/PostCompletionViews/PostCompletionView.jsx +++ b/src/components/PostCompletionViews/PostCompletionView.jsx @@ -42,7 +42,7 @@ const PostCompletionView = ({ - + { @@ -74,6 +81,7 @@ const StatusUrlPoller = ({statusUrl, onFailure, onConfirmed, children}) => { paymentUrl, publicReference, reportDownloadUrl, + confirmationPageTitle, confirmationPageContent, mainWebsiteUrl, } = statusResponse; @@ -88,6 +96,7 @@ const StatusUrlPoller = ({statusUrl, onFailure, onConfirmed, children}) => { publicReference, paymentUrl, reportDownloadUrl, + confirmationPageTitle, confirmationPageContent, mainWebsiteUrl, }} diff --git a/src/components/routingActions.jsx b/src/components/routingActions.jsx index 32a94b68f..b3cadb727 100644 --- a/src/components/routingActions.jsx +++ b/src/components/routingActions.jsx @@ -7,6 +7,12 @@ */ export const getRedirectParams = (action, actionParams) => { switch (action) { + case 'cosign-init': { + return { + path: 'cosign/start', + query: new URLSearchParams(actionParams), + }; + } case 'cosign': return { path: 'cosign/check', diff --git a/src/components/utils/index.jsx b/src/components/utils/index.jsx index 33c904405..86695ce91 100644 --- a/src/components/utils/index.jsx +++ b/src/components/utils/index.jsx @@ -43,6 +43,14 @@ const getLoginUrl = (loginOption, extraParams = {}, extraNextParams = {}) => { return loginUrl.toString(); }; +const getCosignLoginUrl = (loginOption, extraParams = {}) => { + const loginUrl = new URL(loginOption.url); + const nextUrl = new URL(loginUrl.searchParams.get('next')); + Object.entries(extraParams).forEach(([key, value]) => nextUrl.searchParams.set(key, value)); + loginUrl.searchParams.set('next', nextUrl.toString()); + return loginUrl.toString(); +}; + const getLoginRedirectUrl = form => { // Automatically redirect the user to a specific login option (if configured) if (form.autoLoginAuthenticationBackend) { @@ -72,5 +80,6 @@ export { isLastStep, getLoginRedirectUrl, getLoginUrl, + getCosignLoginUrl, eventTriggeredBySubmitButton, }; diff --git a/src/i18n/compiled/en.json b/src/i18n/compiled/en.json index 26079fe83..faeda5988 100644 --- a/src/i18n/compiled/en.json +++ b/src/i18n/compiled/en.json @@ -231,6 +231,26 @@ "value": "." } ], + "7v8PR6": [ + { + "type": 0, + "value": "Your session has expired. " + }, + { + "children": [ + { + "type": 0, + "value": "Click here to restart" + } + ], + "type": 8, + "value": "link" + }, + { + "type": 0, + "value": "." + } + ], "8DHd4/": [ { "type": 0, @@ -881,6 +901,12 @@ "value": "isApplicable" } ], + "LSB7FE": [ + { + "type": 0, + "value": "Did you receive an email with a request to cosign? Start the cosigning by logging in." + } + ], "LiRh7j": [ { "type": 0, @@ -1327,26 +1353,6 @@ "value": "No" } ], - "abtbgK": [ - { - "type": 0, - "value": "Your session has expired. " - }, - { - "children": [ - { - "type": 0, - "value": "Click here to restart" - } - ], - "type": 8, - "value": "link" - }, - { - "type": 0, - "value": "." - } - ], "ay8sO5": [ { "type": 0, @@ -1395,6 +1401,12 @@ "value": "Back to form start" } ], + "eAmrdi": [ + { + "type": 0, + "value": "Loading..." + } + ], "eO6Ysb": [ { "type": 0, diff --git a/src/i18n/compiled/nl.json b/src/i18n/compiled/nl.json index 3140a37ca..9588f3c5c 100644 --- a/src/i18n/compiled/nl.json +++ b/src/i18n/compiled/nl.json @@ -231,6 +231,26 @@ "value": "." } ], + "7v8PR6": [ + { + "type": 0, + "value": "Your session has expired. " + }, + { + "children": [ + { + "type": 0, + "value": "Click here to restart" + } + ], + "type": 8, + "value": "link" + }, + { + "type": 0, + "value": "." + } + ], "8DHd4/": [ { "type": 0, @@ -881,6 +901,12 @@ "value": "isApplicable" } ], + "LSB7FE": [ + { + "type": 0, + "value": "Heb je een e-mail ontvangen om mede te ondertekenen? Start het mede-ondertekenen door in te loggen." + } + ], "LiRh7j": [ { "type": 0, @@ -1331,26 +1357,6 @@ "value": "Nee" } ], - "abtbgK": [ - { - "type": 0, - "value": "Je sessie is verlopen. " - }, - { - "children": [ - { - "type": 0, - "value": "Klik hier om opnieuw te beginnen" - } - ], - "type": 8, - "value": "link" - }, - { - "type": 0, - "value": "." - } - ], "ay8sO5": [ { "type": 0, @@ -1399,6 +1405,12 @@ "value": "Terug naar begin" } ], + "eAmrdi": [ + { + "type": 0, + "value": "Laden..." + } + ], "eO6Ysb": [ { "type": 0, diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 589574630..d3349f361 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -124,6 +124,11 @@ "description": "ZOD 'invalid_enum_value' error message", "originalDefault": "Invalid enum value. Expected {expected}, received {received}." }, + "7v8PR6": { + "defaultMessage": "Your session has expired. Click here to restart.", + "description": "Session expired error message", + "originalDefault": "Your session has expired. Click here to restart." + }, "8DHd4/": { "defaultMessage": "Array must contain {exact, select, true {exactly} other {{inclusive, select, true {at most} other {less than}}} } {maximum, plural, one {{maximum} item} other {{maximum} items}}.", "description": "ZOD 'too_big' error message, for arrays", @@ -429,6 +434,11 @@ "description": "Step label in progress indicator", "originalDefault": "{isApplicable, select, false {{label} (n/a)} other {{label}} }" }, + "LSB7FE": { + "defaultMessage": "Did you receive an email with a request to cosign? Start the cosigning by logging in.", + "description": "Cosign start explanation message", + "originalDefault": "Did you receive an email with a request to cosign? Start the cosigning by logging in." + }, "LiRh7j": { "defaultMessage": "Confirmation: {reference}", "description": "Confirmation page title", @@ -639,11 +649,6 @@ "description": "'False' display", "originalDefault": "No" }, - "abtbgK": { - "defaultMessage": "Your session has expired. Click here to restart.", - "description": "Session expired error message", - "originalDefault": "Your session has expired. Click here to restart." - }, "ay8sO5": { "defaultMessage": "Contact details", "description": "Appointments: contact details step title", diff --git a/src/i18n/messages/nl.json b/src/i18n/messages/nl.json index 7f37c38b7..b0f07e185 100644 --- a/src/i18n/messages/nl.json +++ b/src/i18n/messages/nl.json @@ -126,6 +126,11 @@ "description": "ZOD 'invalid_enum_value' error message", "originalDefault": "Invalid enum value. Expected {expected}, received {received}." }, + "7v8PR6": { + "defaultMessage": "Your session has expired. Click here to restart.", + "description": "Session expired error message", + "originalDefault": "Your session has expired. Click here to restart." + }, "8DHd4/": { "defaultMessage": "Er mogen {exact, select, true {precies} other {{inclusive, select, true {maximaal} other {minder dan}}} } {maximum, plural, one {{maximum} element} other {{maximum} elementen}} in de lijst zijn.", "description": "ZOD 'too_big' error message, for arrays", @@ -434,6 +439,11 @@ "description": "Step label in progress indicator", "originalDefault": "{isApplicable, select, false {{label} (n/a)} other {{label}} }" }, + "LSB7FE": { + "defaultMessage": "Heb je een e-mail ontvangen om mede te ondertekenen? Start het mede-ondertekenen door in te loggen.", + "description": "Cosign start explanation message", + "originalDefault": "Did you receive an email with a request to cosign? Start the cosigning by logging in." + }, "LiRh7j": { "defaultMessage": "Bevestiging: {reference}", "description": "Confirmation page title", @@ -648,11 +658,6 @@ "description": "'False' display", "originalDefault": "No" }, - "abtbgK": { - "defaultMessage": "Je sessie is verlopen. Klik hier om opnieuw te beginnen.", - "description": "Session expired error message", - "originalDefault": "Your session has expired. Click here to restart." - }, "ay8sO5": { "defaultMessage": "Je gegevens", "description": "Appointments: contact details step title", diff --git a/src/story-utils/decorators.jsx b/src/story-utils/decorators.jsx index 8a78481d9..418692e59 100644 --- a/src/story-utils/decorators.jsx +++ b/src/story-utils/decorators.jsx @@ -158,6 +158,7 @@ export const withSubmissionPollInfo = (Story, {parameters, args}) => { publicReference: args.publicReference, paymentUrl: args.paymentUrl, reportDownloadUrl: args.reportDownloadUrl, + confirmationPageTitle: args.confirmationPageTitle, confirmationPageContent: args.confirmationPageContent, mainWebsiteUrl: args.mainWebsiteUrl, }} diff --git a/src/types/Form.js b/src/types/Form.js index 594910331..567642906 100644 --- a/src/types/Form.js +++ b/src/types/Form.js @@ -20,6 +20,7 @@ const Form = PropTypes.shape({ loginRequired: PropTypes.bool.isRequired, loginOptions: PropTypes.arrayOf(LoginOption).isRequired, cosignLoginOptions: PropTypes.arrayOf(LoginOption), + cosignHasLinkInEmail: PropTypes.bool, product: PropTypes.string, slug: PropTypes.string.isRequired, url: PropTypes.string.isRequired,