Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OF#180] Add GovMetric #634

Merged
merged 7 commits into from
Jan 30, 2024
14 changes: 13 additions & 1 deletion src/Context.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ const FormContext = React.createContext({
});
FormContext.displayName = 'FormContext';

const AnalyticsToolsConfigContext = React.createContext({
govmetricSourceId: '',
govmetricSecureGuid: '',
enableGovmetricAnalytics: false,
});

const ConfigContext = React.createContext({
baseUrl: '',
clientBaseUrl: window.location.href,
Expand All @@ -43,4 +49,10 @@ FormioTranslations.displayName = 'FormioTranslations';
const SubmissionContext = React.createContext({submission: null});
SubmissionContext.displayName = 'SubmissionContext';

export {FormContext, ConfigContext, FormioTranslations, SubmissionContext};
export {
FormContext,
ConfigContext,
FormioTranslations,
SubmissionContext,
AnalyticsToolsConfigContext,
};
15 changes: 15 additions & 0 deletions src/api-mocks/analytics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {rest} from 'msw';

import {BASE_URL} from './base';

export const mockAnalyticsToolConfigGet = (overrides = {}) =>
rest.get(`${BASE_URL}analytics/analytics_tools_config_info`, (req, res, ctx) =>
res(
ctx.json({
govmetricSourceId: '',
govmetricSecureGuid: '',
enableGovmetricAnalytics: false,
...overrides,
})
)
);
1 change: 1 addition & 0 deletions src/api-mocks/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export {BASE_URL} from './base';
export {buildForm, mockFormGet} from './forms';
export {buildSubmission} from './submissions';
export {mockAnalyticsToolConfigGet} from './analytics';
66 changes: 66 additions & 0 deletions src/components/AbortionButton/AbortionButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import PropTypes from 'prop-types';
import React, {useContext} from 'react';
import {FormattedMessage, useIntl} from 'react-intl';

import {AnalyticsToolsConfigContext} from 'Context';
import {OFButton} from 'components/Button';
import {buildGovMetricUrl} from 'components/analytics/utils';
import useFormContext from 'hooks/useFormContext';

const AbortionButton = ({isAuthenticated, onDestroySession}) => {
const intl = useIntl();
const analyticsToolsConfig = useContext(AnalyticsToolsConfigContext);
const form = useFormContext();

const confirmationMessage = isAuthenticated
? intl.formatMessage({
description: 'log out confirmation prompt',
defaultMessage: 'Are you sure that you want to logout?',
})
: intl.formatMessage({
description: 'Abort confirmation prompt',
defaultMessage:
'Are you sure that you want to abort this submission? You will lose your progress if you continue.',
});

const callback = async event => {
event.preventDefault();

Check warning on line 27 in src/components/AbortionButton/AbortionButton.js

View check run for this annotation

Codecov / codecov/patch

src/components/AbortionButton/AbortionButton.js#L27

Added line #L27 was not covered by tests

if (!window.confirm(confirmationMessage)) return;

await onDestroySession();

Check warning on line 31 in src/components/AbortionButton/AbortionButton.js

View check run for this annotation

Codecov / codecov/patch

src/components/AbortionButton/AbortionButton.js#L31

Added line #L31 was not covered by tests

if (analyticsToolsConfig.enableGovmetricAnalytics) {
const govmetricUrl = buildGovMetricUrl(

Check warning on line 34 in src/components/AbortionButton/AbortionButton.js

View check run for this annotation

Codecov / codecov/patch

src/components/AbortionButton/AbortionButton.js#L34

Added line #L34 was not covered by tests
analyticsToolsConfig.govmetricSourceId,
form.slug,
analyticsToolsConfig.govmetricSecureGuid
);

window.open(govmetricUrl);

Check warning on line 40 in src/components/AbortionButton/AbortionButton.js

View check run for this annotation

Codecov / codecov/patch

src/components/AbortionButton/AbortionButton.js#L40

Added line #L40 was not covered by tests
}
};

const message = isAuthenticated ? (
<FormattedMessage description="Log out button text" defaultMessage="Log out" />
) : (
<FormattedMessage
description="Button label to abort submission"
defaultMessage="Abort submission"
/>
);

if (!isAuthenticated && !analyticsToolsConfig.enableGovmetricAnalytics) return null;

return (
<OFButton appearance="primary-action-button" hint="danger" name="abort" onClick={callback}>
{message}
</OFButton>
);
};

AbortionButton.propTypes = {
isAuthenticated: PropTypes.bool.isRequired,
onDestroySession: PropTypes.func.isRequired,
};
export default AbortionButton;
35 changes: 35 additions & 0 deletions src/components/AbortionButton/AbortionButton.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {ArgTypes, Canvas, Meta, Story} from '@storybook/blocks';

import * as AbortionButtonStories from './AbortionButton.stories';

<Meta of={AbortionButtonStories} />

# Abortion Button

The abortion button can be used to abort a submission whether the user is authenticated or not.

- If the user is authenticated, then the button will have the text 'Log out' to comply with Logius
directives that whenever a user is logged in with DigiD a 'Log out' option must be available. When
GovMetric is enabled, a new window will open where the user can give feedback.
- If the analytics tool 'GovMetric' is enabled, aborting the submission will open a new window where
the user can give feedback about why they decided to not fill the form until the end.

<Canvas>
<Story of={AbortionButtonStories.Authenticated} />
</Canvas>

<Canvas>
<Story of={AbortionButtonStories.GovMetricEnabled} />
</Canvas>

<Canvas>
<Story of={AbortionButtonStories.AuthenticatedAndGovmetric} />
</Canvas>

<Canvas>
<Story of={AbortionButtonStories.NotAuthenticatedNoGovMetric} />
</Canvas>

## Props

<ArgTypes of={AbortionButtonStories} />
80 changes: 80 additions & 0 deletions src/components/AbortionButton/AbortionButton.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {expect} from '@storybook/jest';
import {waitFor, within} from '@storybook/testing-library';

import {AnalyticsToolsDecorator} from 'story-utils/decorators';

import AbortionButton from './AbortionButton';

export default {
title: 'Private API / Abortion button',
component: AbortionButton,
decorators: [AnalyticsToolsDecorator],
};

export const Authenticated = {
args: {
isAuthenticated: true,
},
play: async ({canvasElement}) => {
const canvas = within(canvasElement);

const abortButton = await canvas.findByRole('button', {name: 'Uitloggen'});
await expect(abortButton).toBeVisible();
},
};

export const GovMetricEnabled = {
args: {
isAuthenticated: false,
},
parameters: {
analyticsToolsParams: {
SilviaAmAm marked this conversation as resolved.
Show resolved Hide resolved
govmetricSourceId: '1234',
govmetricSecureGuid: '',
enableGovmetricAnalytics: true,
},
},
play: async ({canvasElement}) => {
const canvas = within(canvasElement);

await waitFor(async () => {
SilviaAmAm marked this conversation as resolved.
Show resolved Hide resolved
const abortButton = await canvas.queryByRole('button', {name: 'Abort submission'});
await expect(abortButton).toBeVisible();
});
},
};

export const AuthenticatedAndGovmetric = {
args: {
isAuthenticated: true,
},
parameters: {
analyticsToolsParams: {
govmetricSourceId: '1234',
govmetricSecureGuid: '',
enableGovmetricAnalytics: true,
},
},
play: async ({canvasElement}) => {
const canvas = within(canvasElement);

await waitFor(async () => {
const abortButton = await canvas.queryByRole('button', {name: 'Uitloggen'});
await expect(abortButton).toBeVisible();
});
},
};

export const NotAuthenticatedNoGovMetric = {
args: {
isAuthenticated: false,
},
play: async ({canvasElement}) => {
const canvas = within(canvasElement);

await waitFor(async () => {
const abortButton = await canvas.queryByRole('button');
await expect(abortButton).toBeNull();
});
},
};
3 changes: 3 additions & 0 deletions src/components/AbortionButton/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import AbortionButton from './AbortionButton';

export default AbortionButton;
4 changes: 3 additions & 1 deletion src/components/App.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {userEvent, waitForElementToBeRemoved, within} from '@storybook/testing-l
import {RouterProvider, createMemoryRouter} from 'react-router-dom';

import {FormContext} from 'Context';
import {BASE_URL} from 'api-mocks';
import {BASE_URL, mockAnalyticsToolConfigGet} from 'api-mocks';
import {buildForm} from 'api-mocks';
import {
mockSubmissionCheckLogicPost,
Expand Down Expand Up @@ -79,6 +79,7 @@ export default {
{code: 'en', name: 'English'},
]),
mockLanguageChoicePut,
mockAnalyticsToolConfigGet(),
],
},
},
Expand Down Expand Up @@ -189,6 +190,7 @@ export const ActiveSubmission = {
{code: 'en', name: 'English'},
]),
mockLanguageChoicePut,
mockAnalyticsToolConfigGet(),
],
},
},
Expand Down
6 changes: 0 additions & 6 deletions src/components/ButtonsToolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {OFButton} from 'components/Button';
import Link from 'components/Link';
import {Literal, LiteralsProvider} from 'components/Literal';
import Loader from 'components/Loader';
import LogoutButton from 'components/LogoutButton';
import {Toolbar, ToolbarList} from 'components/Toolbar';
import {SUBMISSION_ALLOWED} from 'components/constants';

Expand All @@ -14,12 +13,10 @@ const ButtonsToolbar = ({
canSubmitStep,
canSubmitForm,
canSuspendForm,
isAuthenticated,
isLastStep,
isCheckingLogic,
onNavigatePrevPage,
onFormSave,
onLogout,
previousPage,
}) => {
const showSubmitButton = !(canSubmitForm === SUBMISSION_ALLOWED.noWithoutOverview && isLastStep);
Expand Down Expand Up @@ -65,7 +62,6 @@ const ButtonsToolbar = ({
</ToolbarList>
</Toolbar>
</LiteralsProvider>
{isAuthenticated ? <LogoutButton onLogout={onLogout} /> : null}
</>
);
};
Expand All @@ -76,11 +72,9 @@ ButtonsToolbar.propTypes = {
canSubmitForm: PropTypes.string.isRequired,
canSuspendForm: PropTypes.bool.isRequired,
isLastStep: PropTypes.bool.isRequired,
isAuthenticated: PropTypes.bool.isRequired,
isCheckingLogic: PropTypes.bool.isRequired,
onNavigatePrevPage: PropTypes.func,
onFormSave: PropTypes.func.isRequired,
onLogout: PropTypes.func.isRequired,
previousPage: PropTypes.string,
};

Expand Down
20 changes: 17 additions & 3 deletions src/components/ExistingSubmissionOptions.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import PropTypes from 'prop-types';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, useIntl} from 'react-intl';
import {useNavigate} from 'react-router-dom';

import {OFButton} from 'components/Button';
import {Toolbar, ToolbarList} from 'components/Toolbar';
import Types from 'types';

const ExistingSubmissionOptions = ({form, onFormAbort}) => {
const ExistingSubmissionOptions = ({form, onDestroySession}) => {
const navigate = useNavigate();
const intl = useIntl();

const firstStepRoute = `/stap/${form.steps[0].slug}`;
const confirmationMessage = intl.formatMessage({
description: 'Abort confirmation prompt',
defaultMessage:
'Are you sure that you want to abort this submission? You will lose your progress if you continue.',
});

const onFormAbort = async event => {
event.preventDefault();

Check warning on line 22 in src/components/ExistingSubmissionOptions.js

View check run for this annotation

Codecov / codecov/patch

src/components/ExistingSubmissionOptions.js#L22

Added line #L22 was not covered by tests

if (!window.confirm(confirmationMessage)) return;

await onDestroySession();

Check warning on line 26 in src/components/ExistingSubmissionOptions.js

View check run for this annotation

Codecov / codecov/patch

src/components/ExistingSubmissionOptions.js#L26

Added line #L26 was not covered by tests
};

return (
<Toolbar modifiers={['column']}>
Expand All @@ -36,7 +50,7 @@

ExistingSubmissionOptions.propTypes = {
form: Types.Form.isRequired,
onFormAbort: PropTypes.func.isRequired,
onDestroySession: PropTypes.func.isRequired,
};

export default ExistingSubmissionOptions;
Loading