{t('enrolment:enrolmentForm.studyGroup.titleGroup')}
diff --git a/src/domain/enrolment/enrolmentForm/IsPartOfCulturalRouteField.tsx b/src/domain/enrolment/enrolmentForm/IsPartOfCulturalRouteField.tsx
new file mode 100644
index 00000000..c6741693
--- /dev/null
+++ b/src/domain/enrolment/enrolmentForm/IsPartOfCulturalRouteField.tsx
@@ -0,0 +1,62 @@
+import { Link } from '@city-of-helsinki/react-helsinki-headless-cms';
+import { useField } from 'formik';
+import { RadioButton, SelectionGroup } from 'hds-react';
+import { Trans, useTranslation } from 'next-i18next';
+import React from 'react';
+
+import { IsPartOfCulturalRoute, nameToLabelPath } from './constants';
+import type { I18nNamespace } from '../../../types';
+
+type Props = {
+ formikFieldName: string;
+};
+
+/**
+ * React component for "Is part of cultural route?" field in the enrolment form,
+ * with choices of "No / I don't know" and "Yes".
+ */
+const IsPartOfCulturalRouteField: React.FC
= ({ formikFieldName }) => {
+ const { t } = useTranslation();
+ const [field, meta] = useField(formikFieldName);
+ const errorText = meta.touched && meta.error ? t(meta.error) : undefined;
+ const readMoreUrl = t('enrolment:enrolmentForm.culturalRoute.readMoreUrl');
+
+ return (
+ }}
+ />
+ }
+ >
+
+
+
+ );
+};
+
+export default IsPartOfCulturalRouteField;
diff --git a/src/domain/enrolment/enrolmentForm/ValidationSchema.tsx b/src/domain/enrolment/enrolmentForm/ValidationSchema.tsx
index 7fbcfd69..c63443ac 100644
--- a/src/domain/enrolment/enrolmentForm/ValidationSchema.tsx
+++ b/src/domain/enrolment/enrolmentForm/ValidationSchema.tsx
@@ -1,5 +1,6 @@
import * as Yup from 'yup';
+import { IsPartOfCulturalRoute } from './constants';
import { VALIDATION_MESSAGE_KEYS } from '../../app/forms/constants';
type EnrolmentFormValidationSchemaProps = {
@@ -14,6 +15,12 @@ export default function getValidationSchema({
isQueueEnrolment,
}: EnrolmentFormValidationSchemaProps) {
return Yup.object().shape({
+ isPartOfCulturalRoute: Yup.string()
+ .oneOf(
+ [IsPartOfCulturalRoute.NO_OR_UNKNOWN, IsPartOfCulturalRoute.YES],
+ VALIDATION_MESSAGE_KEYS.STRING_REQUIRED
+ )
+ .required(VALIDATION_MESSAGE_KEYS.STRING_REQUIRED),
hasEmailNotification: Yup.bool().oneOf(
[true],
'enrolment:enrolmentForm.validation.hasEmailNotification'
diff --git a/src/domain/enrolment/enrolmentForm/__tests__/EnrolmentForm.test.tsx b/src/domain/enrolment/enrolmentForm/__tests__/EnrolmentForm.test.tsx
index 5b0d460d..225eac71 100644
--- a/src/domain/enrolment/enrolmentForm/__tests__/EnrolmentForm.test.tsx
+++ b/src/domain/enrolment/enrolmentForm/__tests__/EnrolmentForm.test.tsx
@@ -23,7 +23,10 @@ import {
within,
sleep,
} from '../../../../utils/testUtils';
-import { defaultEnrolmentInitialValues } from '../constants';
+import {
+ defaultEnrolmentInitialValues,
+ IsPartOfCulturalRoute,
+} from '../constants';
import EnrolmentForm, { Props } from '../EnrolmentForm';
configure({ defaultHidden: true });
@@ -113,6 +116,14 @@ test('renders form and user can fill it and submit and form is saved to local st
// // close dropdown
+ // Answer "Is part of cultural route?" question
+ const culturalRouteGroup = await screen.findByRole('group', {
+ name: /käynti sisältyy kulttuuripolkuun/i,
+ });
+ await userEvent.click(
+ within(culturalRouteGroup).getByRole('radio', { name: /kyllä/i })
+ );
+
await userEvent.click(screen.getByRole('combobox', { name: /luokka-aste/i }));
await userEvent.type(screen.getByLabelText(/lapsia/i), '10');
@@ -411,6 +422,7 @@ if (isFeatureEnabled('FORMIK_PERSIST')) {
isSameResponsiblePerson: true,
isSharingDataAccepted: false,
isMandatoryAdditionalInformationRequired: false,
+ isPartOfCulturalRoute: IsPartOfCulturalRoute.NO_OR_UNKNOWN,
language: '',
studyGroup: {
person: {
@@ -504,6 +516,23 @@ if (isFeatureEnabled('FORMIK_PERSIST')) {
expect(
screen.getByRole('combobox', { name: /luokka-aste/i })
).toHaveTextContent('1. luokka');
+
+ // Test that "Is part of cultural route?" question is not answered,
+ // because this field should not be restored from local storage:
+ const culturalRouteGroup = await screen.findByRole('group', {
+ name: /käynti sisältyy kulttuuripolkuun/i,
+ });
+ const isNotPartOfCulturalRoute = within(culturalRouteGroup).getByRole(
+ 'radio',
+ { name: /ei \/ en tiedä/i }
+ );
+ const isPartOfCulturalRoute = within(culturalRouteGroup).getByRole(
+ 'radio',
+ { name: /kyllä/i }
+ );
+ expect(isNotPartOfCulturalRoute).not.toBeChecked();
+ expect(isPartOfCulturalRoute).not.toBeChecked();
+
const childrenCountInput = screen.getByRole('spinbutton', {
name: /lapsia \*/i,
});
diff --git a/src/domain/enrolment/enrolmentForm/__tests__/IsPartOfCulturalRouteField.test.tsx b/src/domain/enrolment/enrolmentForm/__tests__/IsPartOfCulturalRouteField.test.tsx
new file mode 100644
index 00000000..65063cc8
--- /dev/null
+++ b/src/domain/enrolment/enrolmentForm/__tests__/IsPartOfCulturalRouteField.test.tsx
@@ -0,0 +1,124 @@
+import { Formik } from 'formik';
+import * as React from 'react';
+
+import {
+ render,
+ screen,
+ userEvent,
+ within,
+ configure,
+ waitFor,
+} from '../../../../utils/testUtils';
+import { IsPartOfCulturalRoute } from '../constants';
+import IsPartOfCulturalRouteField from '../IsPartOfCulturalRouteField';
+import getValidationSchema from '../ValidationSchema';
+
+configure({ defaultHidden: true });
+
+const renderComponent = (initialValue: IsPartOfCulturalRoute | '' = '') =>
+ render(
+
+ {({ submitForm }) => (
+ <>
+
+
+ Submit
+
+ >
+ )}
+
+ );
+
+const getGroup = () =>
+ screen.findByRole('group', { name: /käynti sisältyy kulttuuripolkuun/i });
+
+const getNoOrUnknownRadio = (group: HTMLElement) =>
+ within(group).getByRole('radio', { name: /ei \/ en tiedä/i });
+
+const getYesRadio = (group: HTMLElement) =>
+ within(group).getByRole('radio', { name: /kyllä/i });
+
+describe('IsPartOfCulturalRouteField', () => {
+ it('renders the selection group with both radio options', async () => {
+ renderComponent();
+ const group = await getGroup();
+ expect(getNoOrUnknownRadio(group)).toBeInTheDocument();
+ expect(getYesRadio(group)).toBeInTheDocument();
+ });
+
+ it('has no radio checked when initial value is empty', async () => {
+ renderComponent('');
+ const group = await getGroup();
+ expect(getNoOrUnknownRadio(group)).not.toBeChecked();
+ expect(getYesRadio(group)).not.toBeChecked();
+ });
+
+ it('checks "No / I don\'t know" when initial value is NO_OR_UNKNOWN', async () => {
+ renderComponent(IsPartOfCulturalRoute.NO_OR_UNKNOWN);
+ const group = await getGroup();
+ expect(getNoOrUnknownRadio(group)).toBeChecked();
+ expect(getYesRadio(group)).not.toBeChecked();
+ });
+
+ it('checks "Yes" when initial value is YES', async () => {
+ renderComponent(IsPartOfCulturalRoute.YES);
+ const group = await getGroup();
+ expect(getNoOrUnknownRadio(group)).not.toBeChecked();
+ expect(getYesRadio(group)).toBeChecked();
+ });
+
+ it('checks only "Yes" radio after clicking it', async () => {
+ renderComponent('');
+ const group = await getGroup();
+ await userEvent.click(getYesRadio(group));
+ expect(getYesRadio(group)).toBeChecked();
+ expect(getNoOrUnknownRadio(group)).not.toBeChecked();
+ });
+
+ it('checks only "No / I don\'t know" radio after clicking it', async () => {
+ renderComponent('');
+ const group = await getGroup();
+ await userEvent.click(getNoOrUnknownRadio(group));
+ expect(getNoOrUnknownRadio(group)).toBeChecked();
+ expect(getYesRadio(group)).not.toBeChecked();
+ });
+
+ it('renders a "read more" link with correct href', async () => {
+ renderComponent();
+ const group = await getGroup();
+ const link = within(group).getByRole('link', {
+ name: /lue lisää kulttuuripoluista/i,
+ });
+ expect(link).toHaveAttribute(
+ 'href',
+ '/fi/cms-page/kulttuurikasvatus/kulttuuripolulla-kulttuuria-kaikille'
+ );
+ });
+
+ it.each([IsPartOfCulturalRoute.NO_OR_UNKNOWN, IsPartOfCulturalRoute.YES])(
+ 'shows no error text when submitted with valid value %p',
+ async (validValue) => {
+ renderComponent(validValue);
+
+ await userEvent.click(screen.getByRole('button', { name: /submit/i }));
+
+ await waitFor(() =>
+ expect(
+ screen.queryByText(/tämä kenttä on pakollinen/i)
+ ).not.toBeInTheDocument()
+ );
+ }
+ );
+
+ it('shows error text when the field is submitted without a selection', async () => {
+ renderComponent('');
+
+ await userEvent.click(screen.getByRole('button', { name: /submit/i }));
+
+ await screen.findByText(/tämä kenttä on pakollinen/i);
+ });
+});
diff --git a/src/domain/enrolment/enrolmentForm/__tests__/__snapshots__/EnrolmentForm.test.tsx.snap b/src/domain/enrolment/enrolmentForm/__tests__/__snapshots__/EnrolmentForm.test.tsx.snap
index b5e128fd..9ed4b96e 100644
--- a/src/domain/enrolment/enrolmentForm/__tests__/__snapshots__/EnrolmentForm.test.tsx.snap
+++ b/src/domain/enrolment/enrolmentForm/__tests__/__snapshots__/EnrolmentForm.test.tsx.snap
@@ -10,6 +10,7 @@ exports[`renders form and user can fill it and submit and form is saved to local
"hasEmailNotification": true,
"hasSmsNotification": false,
"isMandatoryAdditionalInformationRequired": false,
+ "isPartOfCulturalRoute": "",
"isSameResponsiblePerson": true,
"isSharingDataAccepted": false,
"language": "",
@@ -42,6 +43,7 @@ exports[`renders form and user can fill it and submit and form is saved to local
"hasEmailNotification": true,
"hasSmsNotification": true,
"isMandatoryAdditionalInformationRequired": true,
+ "isPartOfCulturalRoute": true,
"isSameResponsiblePerson": true,
"isSharingDataAccepted": true,
"language": true,
@@ -76,6 +78,7 @@ exports[`renders form and user can fill it and submit and form is saved to local
"hasEmailNotification": true,
"hasSmsNotification": true,
"isMandatoryAdditionalInformationRequired": false,
+ "isPartOfCulturalRoute": "YES",
"isSameResponsiblePerson": true,
"isSharingDataAccepted": true,
"language": "FI",
@@ -112,6 +115,7 @@ exports[`renders form and user can fill it and submit and form is saved to local
"hasEmailNotification": true,
"hasSmsNotification": true,
"isMandatoryAdditionalInformationRequired": false,
+ "isPartOfCulturalRoute": "YES",
"isSameResponsiblePerson": true,
"isSharingDataAccepted": true,
"language": "FI",
diff --git a/src/domain/enrolment/enrolmentForm/constants.ts b/src/domain/enrolment/enrolmentForm/constants.ts
index 968b06dd..f0c32030 100644
--- a/src/domain/enrolment/enrolmentForm/constants.ts
+++ b/src/domain/enrolment/enrolmentForm/constants.ts
@@ -1,3 +1,8 @@
+export enum IsPartOfCulturalRoute {
+ NO_OR_UNKNOWN = 'NO_OR_UNKNOWN',
+ YES = 'YES',
+}
+
export type EnrolmentFormFields = {
hasEmailNotification: boolean;
hasSmsNotification: boolean;
@@ -5,6 +10,7 @@ export type EnrolmentFormFields = {
isSharingDataAccepted: boolean;
isMandatoryAdditionalInformationRequired: boolean;
language: string;
+ isPartOfCulturalRoute: IsPartOfCulturalRoute | '';
person: {
name: string;
phoneNumber: string;
@@ -34,6 +40,7 @@ export const defaultEnrolmentInitialValues: EnrolmentFormFields = {
isSharingDataAccepted: false,
isMandatoryAdditionalInformationRequired: false,
language: '',
+ isPartOfCulturalRoute: '',
person: {
name: '',
phoneNumber: '',
@@ -85,4 +92,5 @@ export const nameToLabelPath: Record = {
'enrolment:enrolmentForm.studyGroup.person.labelPhoneNumber',
'person.emailAddress':
'enrolment:enrolmentForm.studyGroup.person.labelEmailAddress',
+ isPartOfCulturalRoute: 'enrolment:enrolmentForm.culturalRoute.labelIsPartOf',
};
diff --git a/src/domain/enrolment/query.ts b/src/domain/enrolment/query.ts
index 279e8f11..21bf737f 100644
--- a/src/domain/enrolment/query.ts
+++ b/src/domain/enrolment/query.ts
@@ -3,6 +3,7 @@ import { gql } from 'graphql-tag';
export const QUERY_ENROLMENT = gql`
fragment enrolmentFields on EnrolmentNode {
id
+ isPartOfCulturalRoute
notificationType
enrolmentTime
status
diff --git a/src/domain/enrolment/utils.ts b/src/domain/enrolment/utils.ts
index 716ec139..b526f3a7 100644
--- a/src/domain/enrolment/utils.ts
+++ b/src/domain/enrolment/utils.ts
@@ -1,4 +1,7 @@
-import { EnrolmentFormFields } from './enrolmentForm/constants';
+import {
+ EnrolmentFormFields,
+ IsPartOfCulturalRoute,
+} from './enrolmentForm/constants';
import {
EnrolEventQueueMutationInput,
EnrolOccurrenceMutationInput,
@@ -6,6 +9,22 @@ import {
NotificationType,
} from '../../generated/graphql';
+/**
+ * Converts IsPartOfCulturalRoute.YES to true,
+ * IsPartOfCulturalRoute.NO_OR_UNKNOWN to false,
+ * and raises an error on everything else.
+ */
+export const validIsPartOfCulturalRouteToBoolean = (
+ isPart: unknown
+): boolean => {
+ if (isPart === IsPartOfCulturalRoute.YES) {
+ return true;
+ } else if (isPart === IsPartOfCulturalRoute.NO_OR_UNKNOWN) {
+ return false;
+ }
+ throw new Error(`Invalid isPartOfCulturalRoute value ${isPart}`);
+};
+
const getNotificationType = (values: EnrolmentFormFields): NotificationType => {
return values.hasEmailNotification &&
values.studyGroup.person.phoneNumber &&
@@ -18,6 +37,9 @@ export const getEnrolmentPayloadBase = (
values: EnrolmentFormFields
): Omit => {
return {
+ isPartOfCulturalRoute: validIsPartOfCulturalRouteToBoolean(
+ values.isPartOfCulturalRoute
+ ),
notificationType: getNotificationType(values),
person: values.isSameResponsiblePerson
? undefined
diff --git a/src/domain/event/__tests__/__snapshots__/enrolmentFormIntegration.test.tsx.snap b/src/domain/event/__tests__/__snapshots__/enrolmentFormIntegration.test.tsx.snap
index 72d64452..6ab00061 100644
--- a/src/domain/event/__tests__/__snapshots__/enrolmentFormIntegration.test.tsx.snap
+++ b/src/domain/event/__tests__/__snapshots__/enrolmentFormIntegration.test.tsx.snap
@@ -10,6 +10,7 @@ exports[`user can select multiple occurrences and enrol to them with enrolment f
"hasEmailNotification": true,
"hasSmsNotification": false,
"isMandatoryAdditionalInformationRequired": false,
+ "isPartOfCulturalRoute": "",
"isSameResponsiblePerson": true,
"isSharingDataAccepted": false,
"language": "FI",
@@ -42,6 +43,7 @@ exports[`user can select multiple occurrences and enrol to them with enrolment f
"hasEmailNotification": true,
"hasSmsNotification": true,
"isMandatoryAdditionalInformationRequired": true,
+ "isPartOfCulturalRoute": true,
"isSameResponsiblePerson": true,
"isSharingDataAccepted": true,
"language": true,
@@ -76,6 +78,7 @@ exports[`user can select multiple occurrences and enrol to them with enrolment f
"hasEmailNotification": true,
"hasSmsNotification": true,
"isMandatoryAdditionalInformationRequired": false,
+ "isPartOfCulturalRoute": "NO_OR_UNKNOWN",
"isSameResponsiblePerson": true,
"isSharingDataAccepted": true,
"language": "FI",
@@ -116,6 +119,7 @@ exports[`user can select single occurrences and enrol to it with enrolment form
"hasEmailNotification": true,
"hasSmsNotification": false,
"isMandatoryAdditionalInformationRequired": true,
+ "isPartOfCulturalRoute": "",
"isSameResponsiblePerson": true,
"isSharingDataAccepted": false,
"language": "FI",
@@ -148,6 +152,7 @@ exports[`user can select single occurrences and enrol to it with enrolment form
"hasEmailNotification": true,
"hasSmsNotification": true,
"isMandatoryAdditionalInformationRequired": true,
+ "isPartOfCulturalRoute": true,
"isSameResponsiblePerson": true,
"isSharingDataAccepted": true,
"language": true,
@@ -182,6 +187,7 @@ exports[`user can select single occurrences and enrol to it with enrolment form
"hasEmailNotification": true,
"hasSmsNotification": true,
"isMandatoryAdditionalInformationRequired": true,
+ "isPartOfCulturalRoute": "NO_OR_UNKNOWN",
"isSameResponsiblePerson": true,
"isSharingDataAccepted": true,
"language": "FI",
diff --git a/src/domain/event/__tests__/enrolmentFormIntegration.test.tsx b/src/domain/event/__tests__/enrolmentFormIntegration.test.tsx
index de67f598..82109958 100644
--- a/src/domain/event/__tests__/enrolmentFormIntegration.test.tsx
+++ b/src/domain/event/__tests__/enrolmentFormIntegration.test.tsx
@@ -221,6 +221,7 @@ test('user can select single occurrences and enrol to it with enrolment form', a
variables: {
input: {
captchaKey: 'captcha-token',
+ isPartOfCulturalRoute: false,
notificationType: 'EMAIL_SMS',
occurrenceIds: ['123321'],
person: undefined,
@@ -308,6 +309,7 @@ test('user can select multiple occurrences and enrol to them with enrolment form
variables: {
input: {
captchaKey: 'captcha-token',
+ isPartOfCulturalRoute: false,
notificationType: 'EMAIL_SMS',
occurrenceIds: ['123321', '321123'],
person: undefined,
@@ -416,6 +418,15 @@ async function fillForm({
);
// close dropdown
await user.click(gradeButton);
+
+ // Answer "Is part of cultural route?" question
+ const culturalRouteGroup = await screen.findByRole('group', {
+ name: /käynti sisältyy kulttuuripolkuun/i,
+ });
+ await userEvent.click(
+ within(culturalRouteGroup).getByRole('radio', { name: /ei \/ en tiedä/i })
+ );
+
await user.type(await enrolmentForm.findByLabelText(/lapsia/i), '10');
await user.type(await enrolmentForm.findByLabelText(/aikuisia/i), '2');
diff --git a/src/domain/eventQueueEnrolment/query.ts b/src/domain/eventQueueEnrolment/query.ts
index 0fd9da23..4369551f 100644
--- a/src/domain/eventQueueEnrolment/query.ts
+++ b/src/domain/eventQueueEnrolment/query.ts
@@ -3,6 +3,7 @@ import { gql } from 'graphql-tag';
export const QUERY_EVENT_QUEUE_ENROLMENT = gql`
fragment eventQueueEnrolmentFields on EventQueueEnrolmentNode {
id
+ isPartOfCulturalRoute
notificationType
enrolmentTime
status
diff --git a/src/domain/headless-cms/components/__tests__/CmsPage.test.tsx b/src/domain/headless-cms/components/__tests__/CmsPage.test.tsx
index af4a29a1..b169b0c2 100644
--- a/src/domain/headless-cms/components/__tests__/CmsPage.test.tsx
+++ b/src/domain/headless-cms/components/__tests__/CmsPage.test.tsx
@@ -3,6 +3,7 @@ import {
ConfigProvider as RHHCConfigProvider,
defaultConfig as rhhcDefaultConfig,
} from '@city-of-helsinki/react-helsinki-headless-cms';
+import { ButtonPresetTheme, ButtonVariant } from 'hds-react';
import * as React from 'react';
import {
@@ -110,8 +111,8 @@ test('renders with sidebar layout when sidebar has content', async () => {
openInExternalDomainAriaLabel: 'Avautuu uudella sivustolla.',
},
customCopy: {
- loadMoreButtonVariant: 'primary',
- loadMoreButtonTheme: 'coat',
+ loadMoreButtonVariant: ButtonVariant.Primary,
+ loadMoreButtonTheme: ButtonPresetTheme.Coat,
},
internalHrefOrigins,
utils: {
diff --git a/src/generated/graphql.tsx b/src/generated/graphql.tsx
index 235e8848..1743a29a 100644
--- a/src/generated/graphql.tsx
+++ b/src/generated/graphql.tsx
@@ -261,6 +261,8 @@ export type EnrolEventQueueMutationInput = {
/** The user response token provided by the reCAPTCHA client-side integration */
captchaKey?: InputMaybe;
clientMutationId?: InputMaybe;
+ /** Is the enrolment part of a cultural route? False = No / I don't know, True = Yes. */
+ isPartOfCulturalRoute: Scalars['Boolean']['input'];
notificationType?: InputMaybe;
/** The event that a group would like to queue to */
pEventId: Scalars['ID']['input'];
@@ -280,6 +282,8 @@ export type EnrolOccurrenceMutationInput = {
/** The user response token provided by the reCAPTCHA client-side integration */
captchaKey?: InputMaybe;
clientMutationId?: InputMaybe;
+ /** Is the enrolment part of a cultural route? False = No / I don't know, True = Yes. */
+ isPartOfCulturalRoute: Scalars['Boolean']['input'];
notificationType?: InputMaybe;
/** Occurrence ids of event */
occurrenceIds: Array>;
@@ -302,6 +306,8 @@ export type EnrolmentNode = Node & {
enrolmentTime: Scalars['DateTime']['output'];
/** The ID of the object */
id: Scalars['ID']['output'];
+ /** Is enrolment part of a cultural route? True means yes, False means no, I don't know or unanswered. */
+ isPartOfCulturalRoute: Scalars['Boolean']['output'];
notificationType?: Maybe;
occurrence: OccurrenceNode;
person?: Maybe;
@@ -411,6 +417,8 @@ export type EventQueueEnrolmentNode = Node & {
enrolmentTime: Scalars['DateTime']['output'];
/** The ID of the object */
id: Scalars['ID']['output'];
+ /** Is enrolment part of a cultural route? True means yes, False means no, I don't know or unanswered. */
+ isPartOfCulturalRoute: Scalars['Boolean']['output'];
notificationType?: Maybe;
pEvent: PalvelutarjotinEventNode;
person?: Maybe;
@@ -1092,7 +1100,7 @@ export enum OrganisationTypeEnum {
export enum OrganisationsOrganisationTypeChoices {
/** Provider */
Provider = 'PROVIDER',
- /** Käyttäjä */
+ /** User */
User = 'USER'
}
@@ -1894,6 +1902,7 @@ export type UnpublishEventMutation = {
export type UpdateEnrolmentMutationInput = {
clientMutationId?: InputMaybe;
enrolmentId: Scalars['ID']['input'];
+ isPartOfCulturalRoute?: InputMaybe;
notificationType?: InputMaybe;
/** Leave blank if the contact person is the same with group contact person */
person?: InputMaybe;
@@ -2140,9 +2149,9 @@ export type EnrolOccurrenceMutationVariables = Exact<{
}>;
-export type EnrolOccurrenceMutation = { __typename?: 'Mutation', enrolOccurrence?: { __typename?: 'EnrolOccurrenceMutationPayload', enrolments?: Array<{ __typename?: 'EnrolmentNode', id: string, notificationType?: NotificationType | null, enrolmentTime: any, status?: EnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } } | null> | null } | null };
+export type EnrolOccurrenceMutation = { __typename?: 'Mutation', enrolOccurrence?: { __typename?: 'EnrolOccurrenceMutationPayload', enrolments?: Array<{ __typename?: 'EnrolmentNode', id: string, isPartOfCulturalRoute: boolean, notificationType?: NotificationType | null, enrolmentTime: any, status?: EnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } } | null> | null } | null };
-export type EnrolmentFieldsFragment = { __typename?: 'EnrolmentNode', id: string, notificationType?: NotificationType | null, enrolmentTime: any, status?: EnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } };
+export type EnrolmentFieldsFragment = { __typename?: 'EnrolmentNode', id: string, isPartOfCulturalRoute: boolean, notificationType?: NotificationType | null, enrolmentTime: any, status?: EnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } };
export type PEventFieldsFragment = { __typename?: 'PalvelutarjotinEventNode', autoAcceptance: boolean, id: string, enrolmentEndDays?: number | null, enrolmentStart?: any | null, externalEnrolmentUrl?: string | null, neededOccurrences: number, contactPhoneNumber: string, contactEmail: string, isQueueingAllowed: boolean, mandatoryAdditionalInformation: boolean, nextOccurrenceDatetime?: any | null, lastOccurrenceDatetime?: any | null, organisation?: { __typename?: 'OrganisationNode', id: string, name: string } | null, contactPerson?: { __typename?: 'PersonNode', id: string, name: string } | null, occurrences?: { __typename?: 'OccurrenceNodeConnection', edges: Array<{ __typename?: 'OccurrenceNodeEdge', node?: { __typename?: 'OccurrenceNode', id: string, amountOfSeats: number, seatsTaken: number, seatType: OccurrencesOccurrenceSeatTypeChoices, remainingSeats: number, minGroupSize?: number | null, maxGroupSize?: number | null, cancelled: boolean, startTime: any, endTime: any, placeId: string, pEvent?: { __typename?: 'PalvelutarjotinEventNode', id: string } | null, languages: { __typename?: 'LanguageNodeConnection', edges: Array<{ __typename?: 'LanguageNodeEdge', node?: { __typename?: 'LanguageNode', id: string, name: string } | null } | null> } } | null } | null> } | null, nextOccurrence?: { __typename?: 'OccurrenceNodeConnection', edges: Array<{ __typename?: 'OccurrenceNodeEdge', node?: { __typename?: 'OccurrenceNode', id: string, startTime: any, endTime: any } | null } | null> } | null };
@@ -2166,9 +2175,9 @@ export type EnrolEventQueueMutationVariables = Exact<{
}>;
-export type EnrolEventQueueMutation = { __typename?: 'Mutation', enrolEventQueue?: { __typename?: 'EnrolEventQueueMutationPayload', eventQueueEnrolment?: { __typename?: 'EventQueueEnrolmentNode', id: string, notificationType?: NotificationType | null, enrolmentTime: any, status?: EventQueueEnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } } | null } | null };
+export type EnrolEventQueueMutation = { __typename?: 'Mutation', enrolEventQueue?: { __typename?: 'EnrolEventQueueMutationPayload', eventQueueEnrolment?: { __typename?: 'EventQueueEnrolmentNode', id: string, isPartOfCulturalRoute: boolean, notificationType?: NotificationType | null, enrolmentTime: any, status?: EventQueueEnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } } | null } | null };
-export type EventQueueEnrolmentFieldsFragment = { __typename?: 'EventQueueEnrolmentNode', id: string, notificationType?: NotificationType | null, enrolmentTime: any, status?: EventQueueEnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } };
+export type EventQueueEnrolmentFieldsFragment = { __typename?: 'EventQueueEnrolmentNode', id: string, isPartOfCulturalRoute: boolean, notificationType?: NotificationType | null, enrolmentTime: any, status?: EventQueueEnrolmentStatus | null, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null, studyGroup: { __typename?: 'StudyGroupNode', id: string, unitId?: string | null, unitName: string, groupSize: number, amountOfAdult: number, groupName: string, extraNeeds: string, unit?: { __typename?: 'ExternalPlace', name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | { __typename?: 'Place', internalId: string, id?: string | null, name?: { __typename?: 'LocalisedObject', en?: string | null, fi?: string | null, sv?: string | null } | null } | null, studyLevels: { __typename?: 'StudyLevelNodeConnection', edges: Array<{ __typename?: 'StudyLevelNodeEdge', node?: { __typename?: 'StudyLevelNode', id: string, label?: string | null, level: number, translations: Array<{ __typename?: 'StudyLevelTranslationType', languageCode: Language, label: string }> } | null } | null> }, person?: { __typename?: 'PersonNode', id: string, emailAddress: string, name: string, phoneNumber: string, language: Language } | null } };
export type MetaFieldsFragment = { __typename?: 'Meta', count?: number | null, next?: string | null, previous?: string | null };
@@ -2409,6 +2418,7 @@ ${PersonFieldsFragmentDoc}`;
export const EnrolmentFieldsFragmentDoc = gql`
fragment enrolmentFields on EnrolmentNode {
id
+ isPartOfCulturalRoute
notificationType
enrolmentTime
status
@@ -2633,6 +2643,7 @@ ${VenueFieldsFragmentDoc}`;
export const EventQueueEnrolmentFieldsFragmentDoc = gql`
fragment eventQueueEnrolmentFields on EventQueueEnrolmentNode {
id
+ isPartOfCulturalRoute
notificationType
enrolmentTime
status
diff --git a/src/playwright/mocks.ts b/src/playwright/mocks.ts
index cdb5aab3..f108a1fb 100644
--- a/src/playwright/mocks.ts
+++ b/src/playwright/mocks.ts
@@ -412,6 +412,7 @@ export const MOCK_ENROL_OCCURRENCE_MUTATION_RESPONSE: EnrolOccurrenceMutation =
enrolments: [
{
id: 'RW5yb2xtZW50Tm9kZTo5ODI=',
+ isPartOfCulturalRoute: true,
notificationType: NotificationType.Email,
enrolmentTime: '2025-05-06T10:49:07.076077+00:00',
status: EnrolmentStatus.Pending,
diff --git a/src/playwright/pages/event.page.ts b/src/playwright/pages/event.page.ts
index 1c6b7810..ae5aa6ec 100644
--- a/src/playwright/pages/event.page.ts
+++ b/src/playwright/pages/event.page.ts
@@ -48,11 +48,21 @@ const TRANS = {
sv: /^Grupp \*/,
en: /^Group name \*/,
},
+ isPartOfCulturalRoute: {
+ fi: /^Käynti sisältyy kulttuuripolkuun \*/,
+ sv: /^Besöket ingår i kulturstigen \*/,
+ en: /^The visit is part of the cultural route \*/,
+ },
name: {
fi: /^Nimi \*/,
sv: /^Namn \*/,
en: /^Name \*/,
},
+ noOrUnknown: {
+ fi: 'Ei / en tiedä',
+ sv: 'Nej / jag vet inte',
+ en: "No / I don't know",
+ },
phoneNumber: {
fi: 'Puhelinnumero *',
sv: 'Telefonnummer *',
@@ -98,6 +108,11 @@ const TRANS = {
sv: 'Skicka anmälan',
en: 'Submit enquiry',
},
+ yes: {
+ fi: 'Kyllä',
+ sv: 'Ja',
+ en: 'Yes',
+ },
} as const satisfies Record;
type TranslationsOf =
@@ -247,6 +262,23 @@ export class EventPage extends BasePage {
await this.hasVisibleHeading(TRANS.reservationEnquirySent[lang]);
}
+ /**
+ * Select a radio button answer to "Is part of cultural route?" question.
+ * @param lang Language
+ * @param value False to select "No / I don't know", true to select "Yes".
+ */
+ async selectIsPartOfCulturalRoute(lang: Language, value: boolean) {
+ const isPartOfCulturalRouteGroup = this.enrolmentForm.getByRole('group', {
+ name: TRANS.isPartOfCulturalRoute[lang],
+ });
+ const radioButtonName = value ? TRANS.yes[lang] : TRANS.noOrUnknown[lang];
+ const radioButtonLabel = isPartOfCulturalRouteGroup.getByText(
+ radioButtonName,
+ { exact: true }
+ );
+ await radioButtonLabel.click();
+ }
+
/**
* Wait for study group unit list to load with at least a single option.
*/
diff --git a/src/playwright/pages/searchCapable.page.ts b/src/playwright/pages/searchCapable.page.ts
index 3c1603a9..b4baf2f3 100644
--- a/src/playwright/pages/searchCapable.page.ts
+++ b/src/playwright/pages/searchCapable.page.ts
@@ -7,7 +7,10 @@ type ZeroToTwoYears = '0-2 vuotiaat' | '0-2 år' | '0-2 years';
type TargetGroupOption = ZeroToTwoYears;
type SearchOption = TargetGroupOption;
type SearchEvents = 'Hae tapahtumia' | 'Sök evenemang' | 'Search events';
-type AdvancedSearch = 'Tarkennettu haku' | 'Redigera sökning' | 'Edit search';
+type AdvancedSearch =
+ | 'Tarkennettu haku'
+ | 'Detaljerad sökning'
+ | 'Advanced search';
type SearchButton = SearchEvents | AdvancedSearch;
type SearchTextBox = SearchEvents | TargetGroupButton;
type TargetGroupField = TargetGroupButton;
diff --git a/src/playwright/tests/eventEnrolling.spec.ts b/src/playwright/tests/eventEnrolling.spec.ts
index 361a0527..1cbef66a 100644
--- a/src/playwright/tests/eventEnrolling.spec.ts
+++ b/src/playwright/tests/eventEnrolling.spec.ts
@@ -28,6 +28,7 @@ LANGUAGES.forEach((lang) => {
await eventPage.selectDaycareKamppiForStudyGroupUnit(lang);
await eventPage.fillStudyGroupName(lang, 'Testiryhmä');
await eventPage.selectPreschoolForStudyLevel(lang);
+ await eventPage.selectIsPartOfCulturalRoute(lang, true);
await eventPage.selectNumberOfChildren(lang, '8');
await eventPage.selectNumberOfAdults(lang, '2');
await eventPage.fillAdditionalInfo(lang, 'Neurokirjon ryhmä');
diff --git a/src/utils/mockDataUtils.ts b/src/utils/mockDataUtils.ts
index d8af54c4..3fe3a592 100644
--- a/src/utils/mockDataUtils.ts
+++ b/src/utils/mockDataUtils.ts
@@ -155,6 +155,7 @@ export const fakeEnrolments = (
export const fakeEnrolment = (
overrides?: Partial
): EnrolmentNode => ({
+ isPartOfCulturalRoute: faker.datatype.boolean(),
enrolmentTime: '2020-08-18T06:37:40.755109+00:00',
updatedAt: '2020-08-18T06:37:40.755109+00:00',
id: faker.string.uuid(),