diff --git a/.env.benefit-applicant.example b/.env.benefit-applicant.example
index 7c1e45befc..635f2f73a7 100644
--- a/.env.benefit-applicant.example
+++ b/.env.benefit-applicant.example
@@ -37,3 +37,5 @@ NEXTJS_SENTRY_DEBUG=true
NEXTJS_SENTRY_TRACING=true
NEXT_PUBLIC_SENTRY_ATTACH_STACKTRACE=
NEXT_PUBLIC_SENTRY_MAX_BREADCRUMBS=
+
+NEXT_PUBLIC_ASKEM_API_KEY=
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
index 7628968ef2..dea8ddffa3 100644
--- a/frontend/Dockerfile
+++ b/frontend/Dockerfile
@@ -83,6 +83,7 @@ ARG SENTRY_PROJECT
ARG SENTRY_AUTH_TOKEN
ARG SENTRY_URL
ARG SENTRY_RELEASE
+ARG NEXT_PUBLIC_ASKEM_API_KEY
# Use non-root user
USER appuser
diff --git a/frontend/benefit/applicant/src/components/applications/Applications.sc.ts b/frontend/benefit/applicant/src/components/applications/Applications.sc.ts
index 896b402afc..6ebef41a93 100644
--- a/frontend/benefit/applicant/src/components/applications/Applications.sc.ts
+++ b/frontend/benefit/applicant/src/components/applications/Applications.sc.ts
@@ -49,3 +49,24 @@ export const $SpinnerContainer = styled.div`
`;
export const $Empty = styled.div``;
+
+export const $AskemContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ min-height: 129px;
+ margin: 0;
+ padding-left: ${(props) => props.theme.spacing.l};
+ padding-right: ${(props) => props.theme.spacing.l};
+ ${respondAbove('sm')`
+ flex-direction: row;
+
+ `}
+`;
+
+export const $AskemItem = styled.div`
+ display: flex;
+ flex-flow: column;
+ ${respondAbove('sm')`
+ min-width: 13%;
+ `}
+`;
diff --git a/frontend/benefit/applicant/src/components/applications/pageContent/PageContent.tsx b/frontend/benefit/applicant/src/components/applications/pageContent/PageContent.tsx
index ce05e0661a..88c363ebe0 100644
--- a/frontend/benefit/applicant/src/components/applications/pageContent/PageContent.tsx
+++ b/frontend/benefit/applicant/src/components/applications/pageContent/PageContent.tsx
@@ -12,7 +12,9 @@ import ApplicationFormStep3 from 'benefit/applicant/components/applications/form
import ApplicationFormStep4 from 'benefit/applicant/components/applications/forms/application/step4/ApplicationFormStep4';
import ApplicationFormStep5 from 'benefit/applicant/components/applications/forms/application/step5/ApplicationFormStep5';
import ApplicationFormStep6 from 'benefit/applicant/components/applications/forms/application/step6/ApplicationFormStep6';
+import { $Hr } from 'benefit/applicant/components/pages/Pages.sc';
import { SUBMITTED_STATUSES } from 'benefit/applicant/constants';
+import { useAskem } from 'benefit/applicant/hooks/useAnalytics';
import { IconInfoCircleFill, LoadingSpinner, Stepper } from 'hds-react';
import { useRouter } from 'next/router';
import React, { useEffect } from 'react';
@@ -24,6 +26,7 @@ import { useTheme } from 'styled-components';
import ErrorPage from '../../errorPage/ErrorPage';
import { $Notification } from '../../Notification/Notification.sc';
import NotificationView from '../../notificationView/NotificationView';
+import { $AskemContainer, $AskemItem } from '../Applications.sc';
import { usePageContent } from './usePageContent';
const stepperCss = {
@@ -49,8 +52,12 @@ const PageContent: React.FC = () => {
} = usePageContent();
const theme = useTheme();
-
const router = useRouter();
+ const canShowAskem = useAskem(
+ router.locale,
+ isSubmittedApplication,
+ isLoading
+ );
useEffect(() => {
if (isReadOnly) document.title = t('common:pageTitles.viewApplication');
@@ -83,16 +90,30 @@ const PageContent: React.FC = () => {
if (isSubmittedApplication) {
return (
-
+ <>
+
+ {canShowAskem && (
+
+ <$Hr />
+ <$AskemContainer>
+ <$AskemItem />
+ <$AskemItem>
+
+ $AskemItem>
+ $AskemContainer>
+ <$Hr />
+
+ )}
+ >
);
}
diff --git a/frontend/benefit/applicant/src/components/cookieConsent/CookieConsent.tsx b/frontend/benefit/applicant/src/components/cookieConsent/CookieConsent.tsx
index d3959ca4c5..c60284410a 100644
--- a/frontend/benefit/applicant/src/components/cookieConsent/CookieConsent.tsx
+++ b/frontend/benefit/applicant/src/components/cookieConsent/CookieConsent.tsx
@@ -2,14 +2,12 @@ import useLocale from 'benefit/applicant/hooks/useLocale';
import { BackendEndpoint } from 'benefit-shared/backend-api/backend-api';
import { CookieModal } from 'hds-react';
import { useRouter } from 'next/router';
-import { useTranslation } from 'next-i18next';
import React from 'react';
import useBackendAPI from 'shared/hooks/useBackendAPI';
const CookieConsent: React.FC = () => {
const locale = useLocale();
const router = useRouter();
- const { t } = useTranslation();
const { axios } = useBackendAPI();
const { pathname, asPath, query } = router;
@@ -23,14 +21,58 @@ const CookieConsent: React.FC = () => {
});
};
+ const askemHostname = 'reactandshare.com';
+
+ type CookieTexts = {
+ title: { fi: string; sv: string; en: string };
+ askemDescription: { fi: string; sv: string; en: string };
+ };
+
+ const text: CookieTexts = {
+ title: {
+ fi: 'Helsinki-lisä',
+ sv: 'Helsingforstillägg',
+ en: 'Helsinki benefit',
+ },
+ askemDescription: {
+ fi: 'Askem-reaktionappien toimintaan liittyvä tietue.',
+ sv: 'En post relaterad till driften av reaktionsknappen Askem.',
+ en: 'A record related to the operation of the Askem react buttons.',
+ },
+ };
+
+ const askemDescription = text.askemDescription[locale];
+
const contentSource = {
- siteName: t('common:appName'),
+ siteName: text.title[locale],
currentLanguage: locale,
optionalCookies: {
- cookies: [
+ groups: [
{
commonGroup: 'statistics',
- commonCookie: 'matomo',
+ cookies: [
+ {
+ id: 'rns',
+ name: 'rnsbid',
+ hostName: askemHostname,
+ description: askemDescription,
+ expiration: '-',
+ },
+ {
+ id: 'rnsbid_ts',
+ name: 'rnsbid_ts',
+ hostName: askemHostname,
+ description: askemDescription,
+ expiration: '-',
+ },
+ {
+ id: 'rns_reaction',
+ name: 'rns_reaction_*',
+ hostName: askemHostname,
+ description: askemDescription,
+ expiration: '-',
+ },
+ ],
},
],
},
@@ -38,11 +80,6 @@ const CookieConsent: React.FC = () => {
onLanguageChange,
},
focusTargetSelector: '#focused-element-after-cookie-consent-closed',
- onAllConsentsGiven: (consents: { matomo: boolean }) => {
- if (!consents.matomo) {
- console.log('stop matomo');
- }
- },
};
return ;
diff --git a/frontend/benefit/applicant/src/components/notificationView/NotificatinsView.sc.ts b/frontend/benefit/applicant/src/components/notificationView/NotificatinsView.sc.ts
index 5689ede132..fb46df5c7e 100644
--- a/frontend/benefit/applicant/src/components/notificationView/NotificatinsView.sc.ts
+++ b/frontend/benefit/applicant/src/components/notificationView/NotificatinsView.sc.ts
@@ -5,14 +5,13 @@ import styled from 'styled-components';
export const $Notification = styled.div`
display: flex;
flex-direction: column;
- margin: ${(props) => props.theme.spacing.xl} 0
- ${(props) => props.theme.spacing.xl} 0;
+ margin-top: ${(props) => props.theme.spacing.xl};
padding: ${(props) => props.theme.spacing.l};
background: ${(props) => props.theme.colors.fogLight};
${respondAbove('sm')`
flex-direction: row;
-
+
`}
`;
diff --git a/frontend/benefit/applicant/src/hooks/useAnalytics.ts b/frontend/benefit/applicant/src/hooks/useAnalytics.ts
new file mode 100644
index 0000000000..30df24cc2c
--- /dev/null
+++ b/frontend/benefit/applicant/src/hooks/useAnalytics.ts
@@ -0,0 +1,33 @@
+import { useEffect } from 'react';
+
+import { canShowAskem } from '../utils/cookie';
+
+export const useAskem = (
+ lang: string | undefined,
+ isSubmittedApplication: boolean,
+ isLoading: boolean
+): boolean => {
+ const showAskem = canShowAskem(lang);
+ useEffect(() => {
+ if (!canShowAskem || isLoading) {
+ return () => {};
+ }
+
+ const script = document.createElement('script');
+ // eslint-disable-next-line scanjs-rules/assign_to_src
+ script.src = 'https://cdn.reactandshare.com/plugin/rns.js';
+ script.type = 'text/javascript';
+
+ window.rnsData = {
+ apiKey: process.env.NEXT_PUBLIC_ASKEM_API_KEY,
+ title: 'Helsinki-lisä',
+ canonicalUrl: window.location.href,
+ };
+
+ document.body.append(script);
+ return () => {
+ script.remove();
+ };
+ }, [lang, isSubmittedApplication, isLoading, showAskem]);
+ return showAskem;
+};
diff --git a/frontend/benefit/applicant/src/types/common.d.ts b/frontend/benefit/applicant/src/types/common.d.ts
index e0b3e66763..bc6edf89fa 100644
--- a/frontend/benefit/applicant/src/types/common.d.ts
+++ b/frontend/benefit/applicant/src/types/common.d.ts
@@ -15,3 +15,22 @@ interface ErrorResponse {
interface ErrorData {
data?: Record;
}
+
+type RNSData = {
+ apiKey: string;
+ title: string;
+ canonicalUrl: string;
+};
+
+export type ConsentsCookie = {
+ 'city-of-helsinki-cookie-consents': boolean;
+ rns: boolean;
+ rnsbid_ts: boolean;
+ rns_reaction: boolean;
+};
+
+declare global {
+ interface Window {
+ rnsData: RNSData;
+ }
+}
diff --git a/frontend/benefit/applicant/src/utils/cookie.ts b/frontend/benefit/applicant/src/utils/cookie.ts
new file mode 100644
index 0000000000..0acf31900a
--- /dev/null
+++ b/frontend/benefit/applicant/src/utils/cookie.ts
@@ -0,0 +1,19 @@
+import { getLastCookieValue } from 'shared/cookies/get-last-cookie-value';
+
+import type { ConsentsCookie } from '../types/common';
+
+const parseConsentsCookie = (): ConsentsCookie | undefined => {
+ const consentsCookieEncoded = getLastCookieValue(
+ 'city-of-helsinki-cookie-consents'
+ );
+ if (!consentsCookieEncoded) {
+ return undefined;
+ }
+ const consentsCookieString = decodeURIComponent(consentsCookieEncoded);
+ return JSON.parse(consentsCookieString) as ConsentsCookie;
+};
+
+export const canShowAskem = (lang: string): boolean => {
+ const consentsCookie = parseConsentsCookie();
+ return consentsCookie && consentsCookie.rns && lang === 'fi';
+};