diff --git a/packages/fyllut/cypress/e2e/components/currency-and-account.cy.ts b/packages/fyllut/cypress/e2e/components/currency-and-account.cy.ts index ec83b6124..7577dac36 100644 --- a/packages/fyllut/cypress/e2e/components/currency-and-account.cy.ts +++ b/packages/fyllut/cypress/e2e/components/currency-and-account.cy.ts @@ -1,6 +1,8 @@ /* * Tests that "penger og konto" component works as expected */ +import { TEXTS } from '@navikt/skjemadigitalisering-shared-domain'; + describe('Components', () => { describe('Penger og konto', () => { beforeEach(() => { @@ -14,10 +16,16 @@ describe('Components', () => { cy.findByRole('textbox', { name: 'Kontonummer' }).should('exist').type('12345678980'); cy.findByRole('textbox', { name: 'IBAN' }).should('exist').type('AB04RABO8424598490'); cy.clickNextStep(); - cy.findByText('Kontonummer: Dette er ikke et gyldig kontonummer').should('exist'); - cy.findByText( - 'IBAN: Oppgitt IBAN inneholder ugyldig landkode (to store bokstaver i starten av IBAN-koden)', - ).should('exist'); + + cy.findByRole('region', { name: TEXTS.validering.error }) + .should('exist') + .within(() => { + cy.findByRole('link', { name: 'Dette er ikke et gyldig kontonummer' }).should('exist'); + cy.findByRole('link', { + name: 'Oppgitt IBAN inneholder ugyldig landkode (to store bokstaver i starten av IBAN-koden)', + }).should('exist'); + }); + cy.findAllByText('Du må fylle ut: Velg valuta').should('have.length', 2); cy.findAllByText('Du må fylle ut: Beløp').should('have.length', 2); }); diff --git a/packages/fyllut/cypress/e2e/components/date-picker.cy.ts b/packages/fyllut/cypress/e2e/components/date-picker.cy.ts index c12ead80f..47b93a414 100644 --- a/packages/fyllut/cypress/e2e/components/date-picker.cy.ts +++ b/packages/fyllut/cypress/e2e/components/date-picker.cy.ts @@ -2,6 +2,7 @@ * Tests that the datepicker component (react) renders, validates and handles interactions correctly */ +import { TEXTS } from '@navikt/skjemadigitalisering-shared-domain'; import * as moment from 'moment'; describe('NavDatepicker', () => { @@ -57,8 +58,7 @@ describe('NavDatepicker', () => { cy.clickNextStep(); cy.findByRole('heading', { name: 'Oppsummering' }).should('not.exist'); - cy.findAllByText('Du må fylle ut: Tilfeldig dato').should('have.length', 1); - cy.findAllByText('Tilfeldig dato: Du må fylle ut: Tilfeldig dato').should('have.length', 1); + cy.findAllByText('Du må fylle ut: Tilfeldig dato').should('have.length', 2); }); }); @@ -66,10 +66,12 @@ describe('NavDatepicker', () => { it('has focus after clicking validation message link', () => { cy.clickNextStep(); - cy.findAllByText('Du må fylle ut: Tilfeldig dato').should('have.length', 1); - cy.findByRoleWhenAttached('link', { name: 'Tilfeldig dato: Du må fylle ut: Tilfeldig dato' }) + cy.findAllByText('Du må fylle ut: Tilfeldig dato').should('have.length', 2); + cy.findByRole('region', { name: TEXTS.validering.error }) .should('exist') - .click(); + .within(() => { + cy.findByRole('link', { name: 'Du må fylle ut: Tilfeldig dato' }).should('exist').click(); + }); cy.findByRole('textbox', { name: 'Tilfeldig dato' }).should('have.focus').type('02.02.2023'); cy.clickNextStep(); @@ -82,7 +84,7 @@ describe('NavDatepicker', () => { const MY_TEST_DATE = '15.05.2023'; beforeEach(() => { - cy.findByRole('textbox', { name: 'Tilfeldig dato' }).should('be.visible'); + cy.findByRole('textbox', { name: 'Tilfeldig dato' }).should('be.visible').should('not.be.disabled'); cy.findByRole('textbox', { name: 'Tilfeldig dato' }).type(`${MY_TEST_DATE}{esc}`); }); @@ -91,23 +93,24 @@ describe('NavDatepicker', () => { const VALIDATION_TEXT = `Datoen må være senere enn ${MY_TEST_DATE}`; it('fails when date is before', () => { - cy.findByRole('textbox', { name: LABEL }).type('14.05.2023'); + cy.findByRole('textbox', { name: LABEL }).should('not.be.disabled').type('14.05.2023'); cy.clickNextStep(); - cy.findAllByText(VALIDATION_TEXT).should('have.length', 1); + cy.findAllByText(VALIDATION_TEXT).should('have.length', 2); }); it('fails when date is equal', () => { - cy.findByRole('textbox', { name: LABEL }).type('15.05.2023'); + cy.findByRole('textbox', { name: LABEL }).should('not.be.disabled').type('15.05.2023'); cy.clickNextStep(); - cy.findAllByText(VALIDATION_TEXT).should('have.length', 1); + cy.findAllByText(VALIDATION_TEXT).should('have.length', 2); }); it('ok when date is later', () => { - cy.findByRole('textbox', { name: LABEL }).type('16.05.2023'); + cy.findByRole('textbox', { name: LABEL }).should('not.be.disabled').type('16.05.2023'); cy.clickNextStep(); + cy.findByRole('heading', { name: 'Oppsummering' }).should('be.visible'); cy.findAllByText(VALIDATION_TEXT).should('have.length', 0); }); }); @@ -117,23 +120,25 @@ describe('NavDatepicker', () => { const VALIDATION_TEXT = `Datoen kan ikke være tidligere enn ${MY_TEST_DATE}`; it('fails when date is before', () => { - cy.findByRole('textbox', { name: LABEL }).type(`14.05.2023{esc}`); + cy.findByRole('textbox', { name: LABEL }).should('not.be.disabled').type(`14.05.2023{esc}`); cy.clickNextStep(); - cy.findAllByText(VALIDATION_TEXT).should('have.length', 1); + cy.findAllByText(VALIDATION_TEXT).should('have.length', 2); }); it('fails when date is equal', () => { - cy.findByRole('textbox', { name: LABEL }).type('15.05.2023{esc}'); + cy.findByRole('textbox', { name: LABEL }).should('not.be.disabled').type('15.05.2023{esc}'); cy.clickNextStep(); + cy.findByRole('heading', { name: 'Oppsummering' }).should('be.visible'); cy.findAllByText(VALIDATION_TEXT).should('have.length', 0); }); it('ok when date is later', () => { - cy.findByRole('textbox', { name: LABEL }).type('16.05.2023{esc}'); + cy.findByRole('textbox', { name: LABEL }).should('not.be.disabled').type('16.05.2023{esc}'); cy.clickNextStep(); + cy.findByRole('heading', { name: 'Oppsummering' }).should('be.visible'); cy.findAllByText(VALIDATION_TEXT).should('have.length', 0); }); }); @@ -149,7 +154,7 @@ describe('NavDatepicker', () => { cy.findByRole('textbox', { name: LABEL }).type('15.07.2023{esc}'); cy.clickNextStep(); - cy.findAllByText(VALIDATION_TEXT).should('have.length', 1); + cy.findAllByText(VALIDATION_TEXT).should('have.length', 2); }); it("is ok when date is equal to 'earliest date'", () => { @@ -170,7 +175,7 @@ describe('NavDatepicker', () => { cy.findByRole('textbox', { name: LABEL }).type('01.09.2023{esc}'); cy.clickNextStep(); - cy.findAllByText(VALIDATION_TEXT).should('have.length', 1); + cy.findAllByText(VALIDATION_TEXT).should('have.length', 2); }); }); @@ -190,15 +195,13 @@ describe('NavDatepicker', () => { it('fails when date is before the earliest limit', () => { cy.findByRole('textbox', { name: LABEL }).type(plusDays(NOW, EARLIEST_RELATIVE - 1)); cy.clickNextStep(); - console.log('VALIDATION_TEXT', VALIDATION_TEXT); - cy.findAllByText(VALIDATION_TEXT).should('have.length', 1); + cy.findAllByText(VALIDATION_TEXT).should('have.length', 2); }); it('is ok when date is exactly the earliest limit', () => { cy.findByRole('textbox', { name: LABEL }).type(plusDays(NOW, EARLIEST_RELATIVE)); cy.clickNextStep(); - console.log('VALIDATION_TEXT', VALIDATION_TEXT); cy.findAllByText(VALIDATION_TEXT).should('have.length', 0); }); @@ -206,7 +209,6 @@ describe('NavDatepicker', () => { it('is ok when date is exactly the latest limit', () => { cy.findByRole('textbox', { name: LABEL }).type(plusDays(NOW, LATEST_RELATIVE)); cy.clickNextStep(); - console.log('VALIDATION_TEXT', VALIDATION_TEXT); cy.findAllByText(VALIDATION_TEXT).should('have.length', 0); }); @@ -214,9 +216,8 @@ describe('NavDatepicker', () => { it('fails when date is after the earliest limit', () => { cy.findByRole('textbox', { name: LABEL }).type(plusDays(NOW, LATEST_RELATIVE + 1)); cy.clickNextStep(); - console.log('VALIDATION_TEXT', VALIDATION_TEXT); - cy.findAllByText(VALIDATION_TEXT).should('have.length', 1); + cy.findAllByText(VALIDATION_TEXT).should('have.length', 2); }); }); }); diff --git a/packages/fyllut/cypress/e2e/components/driving-list.cy.ts b/packages/fyllut/cypress/e2e/components/driving-list.cy.ts index 147613ea8..89fa38eee 100644 --- a/packages/fyllut/cypress/e2e/components/driving-list.cy.ts +++ b/packages/fyllut/cypress/e2e/components/driving-list.cy.ts @@ -91,9 +91,21 @@ describe('DrivingList', () => { // Should fill out form cy.clickNextStep(); - cy.findByRole('link', { name: `Du må fylle ut: ${PERIOD_TYPE_LABEL}` }).should('exist'); + cy.findByRole('region', { name: TEXTS.validering.error }) + .should('exist') + .within(() => { + cy.findByRole('link', { name: `Du må fylle ut: ${PERIOD_TYPE_LABEL}` }) + .should('exist') + .click(); + }); + + cy.findByRole('group', { name: PERIOD_TYPE_LABEL }) + .should('exist') + .should('have.focus') + .within(() => { + cy.findByRole('radio', { name: 'Ukentlig' }).should('exist').check(); + }); - cy.findByRole('radio', { name: 'Ukentlig' }).should('exist').check(); cy.findByRole('textbox', { name: DATE_PICKER_LABEL }).should('exist').type('15.05.23{esc}'); cy.findByRole('radio', { name: 'Ja' }).should('exist').check(); cy.findByRole('button', { name: '15.05.2023 - 21.05.2023' }).click(); @@ -102,13 +114,26 @@ describe('DrivingList', () => { // Parking expenses should not be over 100 cy.findByRole('textbox', { name: PARKING_EXPENSES_LABEL }).should('exist').type('101'); cy.clickNextStep(); - cy.findByRole('link', { name: TEXTS.validering.parkingExpensesAboveHundred }).should('exist'); + cy.findByRole('region', { name: TEXTS.validering.error }) + .should('exist') + .within(() => { + cy.findByRole('link', { name: TEXTS.validering.parkingExpensesAboveHundred }).should('exist'); + }); // Parking expenses should be a number cy.findByRole('textbox', { name: PARKING_EXPENSES_LABEL }).clear(); cy.findByRole('textbox', { name: PARKING_EXPENSES_LABEL }).type('text'); cy.clickNextStep(); - cy.findByRole('link', { name: TEXTS.validering.validParkingExpenses }).should('exist'); + cy.findByRole('region', { name: TEXTS.validering.error }) + .should('exist') + .within(() => { + cy.findByRole('link', { name: 'Parkeringsutgiftene for 15.05.2023 må være et gyldig beløp' }) + .should('exist') + .click(); + }); + + cy.findByRole('textbox', { name: PARKING_EXPENSES_LABEL }).should('have.focus').type('{selectall}78'); + cy.findByRole('region', { name: TEXTS.validering.error }).should('not.exist'); }); it('should add and remove periods', () => { @@ -224,9 +249,20 @@ describe('DrivingList', () => { cy.wait('@getActivities'); cy.clickSaveAndContinue(); - cy.findByRole('link', { name: `Du må fylle ut: ${ACTIVITIES_LABEL}` }).should('exist'); + cy.findByRole('region', { name: TEXTS.validering.error }) + .should('exist') + .within(() => { + cy.findByRole('link', { name: `Du må fylle ut: ${ACTIVITIES_LABEL}` }) + .should('exist') + .click(); + }); - cy.findByRole('radio', { name: 'Arbeidstrening: 01.01.2024 - 31.08.2024' }).should('exist').check(); + cy.findByRole('group', { name: ACTIVITIES_LABEL }) + .should('exist') + .should('have.focus') + .within(() => { + cy.findByRole('radio', { name: 'Arbeidstrening: 01.01.2024 - 31.08.2024' }).should('exist').check(); + }); // Expenses are higher than the refund limit cy.findByRole('button', { name: '08.01.2024 - 14.01.2024' }).click(); @@ -257,7 +293,11 @@ describe('DrivingList', () => { }); cy.clickSaveAndContinue(); - cy.findByRole('link', { name: `Du må fylle ut: ${ACTIVITIES_LABEL}` }).should('exist'); + cy.findByRole('region', { name: TEXTS.validering.error }) + .should('exist') + .within(() => { + cy.findByRole('link', { name: `Du må fylle ut: ${ACTIVITIES_LABEL}` }).should('exist'); + }); }); }); }); diff --git a/packages/fyllut/cypress/e2e/components/general.cy.ts b/packages/fyllut/cypress/e2e/components/general.cy.ts index d7e446e95..3cc814436 100644 --- a/packages/fyllut/cypress/e2e/components/general.cy.ts +++ b/packages/fyllut/cypress/e2e/components/general.cy.ts @@ -29,9 +29,7 @@ describe('React components', () => { cy.findByRole('textbox', { name: 'Fornavn' }).type('Storm'); cy.findByRole('combobox', { name: 'I hvilket land bor du?' }).click(); - cy.findByRole('combobox', { name: 'I hvilket land bor du?' }).type( - 'Nor{downArrow}{downArrow}{downArrow}{downArrow}{enter}', - ); + cy.findByRole('combobox', { name: 'I hvilket land bor du?' }).type('Norge{enter}'); cy.findByRole('combobox', { name: 'Velg instrument (valgfritt)' }).type('Gitar{enter}'); cy.findByRole('textbox', { name: 'Gyldig fra dato' }).type('01.01.2023{esc}'); cy.clickNextStep(); @@ -126,9 +124,7 @@ describe('React components', () => { cy.findByRole('heading', { name: 'Dine opplysninger' }).should('be.visible'); cy.findByRole('textbox', { name: 'Fornavn' }).should('be.visible'); cy.findByRoleWhenAttached('textbox', { name: 'Fornavn' }).type('Storm'); - cy.findByRole('combobox', { name: 'I hvilket land bor du?' }) - .should('be.visible') - .type('Nor{downArrow}{downArrow}{downArrow}{downArrow}{enter}'); + cy.findByRole('combobox', { name: 'I hvilket land bor du?' }).should('be.visible').type('Norge{enter}'); cy.findByRole('combobox', { name: 'Velg valuta' }).should('be.visible').type('{upArrow}{enter}'); cy.findByRole('combobox', { name: 'Velg instrument (valgfritt)' }).type('Gitar{enter}'); cy.findByRole('textbox', { name: 'Gyldig fra dato' }).type('01.01.2023{esc}'); diff --git a/packages/fyllut/cypress/e2e/digital-submission/mellomlagring.cy.ts b/packages/fyllut/cypress/e2e/digital-submission/mellomlagring.cy.ts index a740f985f..29f8c044d 100644 --- a/packages/fyllut/cypress/e2e/digital-submission/mellomlagring.cy.ts +++ b/packages/fyllut/cypress/e2e/digital-submission/mellomlagring.cy.ts @@ -245,14 +245,13 @@ describe('Mellomlagring', () => { cy.clickSaveAndContinue(); cy.get('@updateMellomlagringSpy').should('not.have.been.called'); - cy.findByRole('heading', { name: TEXTS.validering.error }) + cy.findByRole('region', { name: TEXTS.validering.error }) .should('exist') - .parent() .within(() => { - cy.get('li').should('have.length', 2); + cy.get('a').should('have.length', 2); + cy.findByRole('link', { name: 'Du må fylle ut: Farge' }).should('exist').click(); }); - cy.findByRoleWhenAttached('link', { name: 'Du må fylle ut: Farge' }).should('exist').click(); cy.findByRole('group', { name: 'Farge' }) .should('exist') .should('have.focus') @@ -260,7 +259,12 @@ describe('Mellomlagring', () => { cy.findByLabelText('Rød').click(); }); - cy.findByRoleWhenAttached('link', { name: 'Du må fylle ut: Tekst på kortet' }).should('exist').click(); + cy.findByRole('region', { name: TEXTS.validering.error }) + .should('exist') + .within(() => { + cy.get('a').should('have.length', 1); + cy.findByRole('link', { name: 'Du må fylle ut: Tekst på kortet' }).should('exist').click(); + }); cy.findByLabelText('Tekst på kortet').should('have.focus').type('Takk for hjelpen!'); cy.findByRole('link', { name: 'Oppsummering' }).click(); diff --git a/packages/fyllut/cypress/e2e/form/basic-form.cy.ts b/packages/fyllut/cypress/e2e/form/basic-form.cy.ts index dfb946834..fd814beeb 100644 --- a/packages/fyllut/cypress/e2e/form/basic-form.cy.ts +++ b/packages/fyllut/cypress/e2e/form/basic-form.cy.ts @@ -1,6 +1,8 @@ /* * Tests filling out a basic form with contact information and verifying that the information is displayed in the summary (for both digital/paper) */ +import { TEXTS } from '@navikt/skjemadigitalisering-shared-domain'; + describe('Basic form', () => { beforeEach(() => { cy.defaultIntercepts(); @@ -112,10 +114,12 @@ describe('Basic form', () => { cy.clickNextStep(); cy.clickNextStep(); cy.findByRole('heading', { level: 2, name: 'Dine opplysninger' }); - cy.findByText('For å gå videre må du rette opp følgende:').should('exist'); - - cy.findAllByRole('link', { name: /^Du må fylle ut:/ }).should('have.length', 4); - cy.findByRoleWhenAttached('link', { name: 'Du må fylle ut: Fornavn' }).click(); + cy.findByRole('region', { name: TEXTS.validering.error }) + .should('exist') + .within(() => { + cy.findAllByRole('link', { name: /Du må fylle ut:/ }).should('have.length', 4); + cy.findByRole('link', { name: 'Du må fylle ut: Fornavn' }).click(); + }); cy.findByRole('textbox', { name: 'Fornavn' }).should('have.focus'); }); }); diff --git a/packages/fyllut/cypress/e2e/form/focus-handling.cy.ts b/packages/fyllut/cypress/e2e/form/focus-handling.cy.ts index c75887938..8661ad2c0 100644 --- a/packages/fyllut/cypress/e2e/form/focus-handling.cy.ts +++ b/packages/fyllut/cypress/e2e/form/focus-handling.cy.ts @@ -85,7 +85,7 @@ describe('Focus handling', () => { cy.visit('/fyllut/datagridconditional/levering?sub=paper'); cy.defaultWaits(); cy.clickNextStep(); - cy.findByRole('heading', { name: TEXTS.validering.error }).should('exist').should('have.focus'); + cy.findByRole('region', { name: TEXTS.validering.error }).should('exist').should('have.focus'); }); it('puts focus on correct component when clicking in error summary', () => { @@ -112,9 +112,12 @@ describe('Focus handling', () => { cy.get('li').should('have.length', 2); }); - cy.findByRoleWhenAttached('link', { name: 'Du må fylle ut: Hvilken type bolig bor du i?' }) + cy.findByRole('region', { name: TEXTS.validering.error }) .should('exist') - .click(); + .within(() => { + cy.findByRole('link', { name: 'Du må fylle ut: Hvilken type bolig bor du i?' }).should('exist').click(); + }); + cy.findByRole('group', { name: 'Hvilken type bolig bor du i?' }) .should('exist') .should('have.focus') @@ -123,10 +126,14 @@ describe('Focus handling', () => { cy.findByLabelText('Rekkehus').click(); }); - cy.findByRoleWhenAttached('link', { name: 'Du må fylle ut: Mottakers fornavn' }).should('exist').click(); + cy.findByRole('region', { name: TEXTS.validering.error }) + .should('exist') + .within(() => { + cy.findByRole('link', { name: 'Du må fylle ut: Mottakers fornavn' }).should('exist').click(); + }); cy.findByRole('textbox', { name: 'Mottakers fornavn' }).should('have.focus').type('Max'); - cy.findByRole('heading', { name: TEXTS.validering.error }).should('not.exist'); + cy.findByRole('region', { name: TEXTS.validering.error }).should('not.exist'); cy.clickNextStep(); cy.findByRole('heading', { name: 'Vedlegg' }).should('exist'); diff --git a/packages/shared-components/src/components/activities/NavActivities.tsx b/packages/shared-components/src/components/activities/NavActivities.tsx index 3db91ad75..63d3a6d03 100644 --- a/packages/shared-components/src/components/activities/NavActivities.tsx +++ b/packages/shared-components/src/components/activities/NavActivities.tsx @@ -1,7 +1,7 @@ import { Alert, Checkbox, CheckboxGroup, Radio, RadioGroup, Skeleton } from '@navikt/ds-react'; import { SendInnAktivitet, SubmissionActivity, TEXTS } from '@navikt/skjemadigitalisering-shared-domain'; import { TFunction } from 'i18next'; -import { ReactNode, useEffect, useState } from 'react'; +import { ReactNode, forwardRef, useEffect, useState } from 'react'; import { getActivities } from '../../api/sendinn/sendInnActivities'; import { AppConfigContextType } from '../../context/config/configContext'; import { mapToSubmissionActivity } from '../../formio/components/core/activities/Activities.utils'; @@ -25,7 +25,7 @@ type ActivityDataType = 'aktivitet' | 'vedtak'; // Renders a activity-data from Arena // In some cases it's more relevant to list all 'vedtak' that are part of the activities instead -const NavActivities = (props: Props) => { +const NavActivities = forwardRef((props: Props, ref) => { const [loading, setLoading] = useState(true); const [activitySelections, setActivitySelections] = useState([]); const [showError, setShowError] = useState(false); @@ -83,6 +83,7 @@ const NavActivities = (props: Props) => { className={props.className} error={props.error} tabIndex={-1} + ref={ref} > {props.defaultActivity?.text} @@ -117,6 +118,7 @@ const NavActivities = (props: Props) => { className={props.className} error={props.error} tabIndex={-1} + ref={ref} > {activitySelections?.map((activity: SubmissionActivity) => { return ( @@ -160,6 +162,6 @@ const NavActivities = (props: Props) => { )} ); -}; +}); export default NavActivities; diff --git a/packages/shared-components/src/components/drivinglist/DrivingListFromActivities.tsx b/packages/shared-components/src/components/drivinglist/DrivingListFromActivities.tsx index fc06a6a07..1e08ded97 100644 --- a/packages/shared-components/src/components/drivinglist/DrivingListFromActivities.tsx +++ b/packages/shared-components/src/components/drivinglist/DrivingListFromActivities.tsx @@ -25,7 +25,7 @@ const useDrivinglistStyles = makeStyles({ }); const DrivingListFromActivities = ({ activities }: Props) => { - const { values, updateValues, t, appConfig, getComponentError } = useDrivingList(); + const { values, updateValues, t, appConfig, getComponentError, addRef } = useDrivingList(); const styles = useDrivinglistStyles(); @@ -80,6 +80,7 @@ const DrivingListFromActivities = ({ activities }: Props) => { dataType="vedtak" activities={activities} error={getComponentError('activityRadio')} + ref={(ref) => addRef('activityRadio', ref)} /> {selectedActivity && selectedVedtak && ( <> @@ -88,7 +89,13 @@ const DrivingListFromActivities = ({ activities }: Props) => { vedtak={selectedVedtak} className={styles.marginBottom} /> - + addRef('dates', ref)} + > {selectedVedtak?.betalingsplan .filter((x) => !!x.journalpostId === false) .filter((x) => new Date(x.utgiftsperiode.tom) < new Date()) diff --git a/packages/shared-components/src/components/drivinglist/DrivingListFromDates.tsx b/packages/shared-components/src/components/drivinglist/DrivingListFromDates.tsx index 918666178..0f7963d74 100644 --- a/packages/shared-components/src/components/drivinglist/DrivingListFromDates.tsx +++ b/packages/shared-components/src/components/drivinglist/DrivingListFromDates.tsx @@ -26,7 +26,7 @@ const useDrivinglistStyles = makeStyles({ }); const DrivingListFromDates = () => { - const { values, updateValues, t, locale, getComponentError } = useDrivingList(); + const { values, updateValues, t, locale, getComponentError, addRef } = useDrivingList(); const styles = useDrivinglistStyles(); @@ -132,6 +132,7 @@ const DrivingListFromDates = () => { tabIndex={-1} className={styles.marginBottom} error={getComponentError('periodType')} + ref={(ref) => addRef(drivingListMetadata('periodType').id, ref)} > {t(TEXTS.common.weekly)} {t(TEXTS.common.monthly)} @@ -147,7 +148,7 @@ const DrivingListFromDates = () => { locale={locale} readOnly={false} error={getComponentError('datePicker')} - inputRef={undefined} + inputRef={(ref) => addRef(drivingListMetadata('datePicker').id, ref)} className={styles.marginBottom} toDate={toDate(values)} defaultMonth={toDate(values)} @@ -160,6 +161,7 @@ const DrivingListFromDates = () => { onChange={(value) => onParkingChange(value)} defaultValue={values?.parking} tabIndex={-1} + ref={(ref) => addRef(drivingListMetadata('parkingRadio').id, ref)} className={styles.marginBottom} > {t(TEXTS.common.yes)} @@ -168,7 +170,12 @@ const DrivingListFromDates = () => { )} - + addRef('dates', ref)} + > {renderDrivingPeriodsFromDates()} {allPeriodFieldsSet && values!.periods!.length > 0 && ( diff --git a/packages/shared-components/src/components/drivinglist/DrivingPeriod.tsx b/packages/shared-components/src/components/drivinglist/DrivingPeriod.tsx index 9da87987c..a56a86d33 100644 --- a/packages/shared-components/src/components/drivinglist/DrivingPeriod.tsx +++ b/packages/shared-components/src/components/drivinglist/DrivingPeriod.tsx @@ -25,7 +25,7 @@ const useDrivingPeriodStyles = makeStyles({ }); const DrivingPeriod = ({ periodFrom, periodTo, hasParking, dailyRate, betalingsplan }: DrivingPeriodProps) => { - const { values, updateValues, t, locale, getComponentError } = useDrivingList(); + const { values, updateValues, t, locale, getComponentError, addRef } = useDrivingList(); const styles = useDrivingPeriodStyles(); @@ -125,6 +125,8 @@ const DrivingPeriod = ({ periodFrom, periodTo, hasParking, dailyRate, betalingsp className={`nav-input--s ${styles.parkingTextField}`} value={values?.dates?.find((val) => val.date === date.toISOString())?.parking} onChange={(event) => onChangeParking(date, event.currentTarget.value)} + ref={(ref) => addRef(`dates:${date.toISOString()}:parking`, ref)} + error={getComponentError(`dates:${date.toISOString()}:parking`)} /> ) : null} diff --git a/packages/shared-components/src/components/nav-form/NavForm.jsx b/packages/shared-components/src/components/nav-form/NavForm.jsx index 9764a3d17..8f17f911a 100644 --- a/packages/shared-components/src/components/nav-form/NavForm.jsx +++ b/packages/shared-components/src/components/nav-form/NavForm.jsx @@ -55,6 +55,12 @@ const NavForm = (props) => { [formio], ); + useEffect(() => { + const { fyllutEvents } = props; + fyllutEvents?.on('focusOnComponent', (args) => formio.focusOnComponent(args)); + return () => fyllutEvents?.removeListener('focusOnComponent'); + }, [props.fyllutEvents, formio]); + const createWebformInstance = (srcOrForm) => { const { formioform, formReady, language, i18n } = props; instance = new (formioform || FormioForm)(element, srcOrForm, { @@ -185,6 +191,9 @@ NavForm.propTypes = { onBlur: PropTypes.func, onInitialized: PropTypes.func, onWizardPageSelected: PropTypes.func, + onShowErrors: PropTypes.func, + onErrorSummaryFocus: PropTypes.func, + fyllutEvents: PropTypes.object, formReady: PropTypes.func, submissionReady: PropTypes.func, formioform: PropTypes.any, diff --git a/packages/shared-components/src/formio/components/base/BaseComponent.tsx b/packages/shared-components/src/formio/components/base/BaseComponent.tsx index 6a735ba82..78e9a98f8 100644 --- a/packages/shared-components/src/formio/components/base/BaseComponent.tsx +++ b/packages/shared-components/src/formio/components/base/BaseComponent.tsx @@ -1,6 +1,7 @@ import { Tag } from '@navikt/ds-react'; import { Component, formDiffingTool, navFormUtils } from '@navikt/skjemadigitalisering-shared-domain'; import Field from 'formiojs/components/_classes/field/Field'; +import FormioUtils from 'formiojs/utils'; import { ReactNode } from 'react'; import FormioReactComponent from './FormioReactComponent'; import { blurHandler, focusHandler } from './focus-helpers'; @@ -222,7 +223,10 @@ class BaseComponent extends FormioReactComponent { */ focus(focusData?: any) { this.reactReady.then(() => { - if (this.reactInstance) { + const { elementId } = focusData; + if (elementId) { + this.getRef(elementId)?.focus(); + } else if (this.reactInstance) { this.reactInstance.focus(focusData); } }); @@ -285,18 +289,14 @@ class BaseComponent extends FormioReactComponent { ); } - // MetadataId is used to focus to the correct element when clicking on error summary + // elementId is used to focus to the correct element when clicking on error summary // Message is the error message that is shown in the error summary - addError(metadataId: string, message: string) { + addError(message: string, elementId?: string) { this.componentErrors.push({ - metadataId, message, level: 'error', - path: metadataId, - - // For the error summary (will be removed when the new error summary is implemented) - messages: [{ formattedKeyOrPath: metadataId, message, context: { hasLabel: true } }], - component: { key: metadataId }, + path: FormioUtils.getComponentPath(this.component), + elementId, }); } diff --git a/packages/shared-components/src/formio/components/base/FormioReactComponent.tsx b/packages/shared-components/src/formio/components/base/FormioReactComponent.tsx index f64c8328b..c627b94c0 100644 --- a/packages/shared-components/src/formio/components/base/FormioReactComponent.tsx +++ b/packages/shared-components/src/formio/components/base/FormioReactComponent.tsx @@ -9,7 +9,7 @@ class FormioReactComponent extends (ReactComponent as unknown as IReactComponent rootElement: any; componentErrors: ComponentError[]; _reactRendered = Ready(); - _reactRefs: {} = {}; + _reactRefs: Record = {}; constructor(component, options, data) { super(component, options, data); @@ -96,11 +96,15 @@ class FormioReactComponent extends (ReactComponent as unknown as IReactComponent return Promise.resolve(); } - addRef(name: string, ref: any) { - this._reactRefs[name] = ref; + addRef(name: string, ref: HTMLElement | null) { + if (ref) { + this._reactRefs[name] = ref; + } else { + delete this._reactRefs[name]; + } } - getRef(name: string) { + getRef(name: string): HTMLElement | null { return this._reactRefs[name]; } diff --git a/packages/shared-components/src/formio/components/core/activities/Activities.tsx b/packages/shared-components/src/formio/components/core/activities/Activities.tsx index bc615a541..7ed25dd06 100644 --- a/packages/shared-components/src/formio/components/core/activities/Activities.tsx +++ b/packages/shared-components/src/formio/components/core/activities/Activities.tsx @@ -36,7 +36,7 @@ class Activities extends BaseComponent { } override getError(): string | undefined { - const error = this.componentErrors.find((error) => error.path === this.getId()); + const error = this.componentErrors[0]; if (error) return error.message; } @@ -50,7 +50,7 @@ class Activities extends BaseComponent { if (!componentData) { const requiredError = this.t('required', { field: this.getLabel({ labelTextOnly: true }) }); - super.addError(this.getId(), requiredError); + super.addError(requiredError); } } @@ -88,6 +88,7 @@ class Activities extends BaseComponent { defaultActivity={this.defaultActivity} t={this.t.bind(this)} dataType="aktivitet" + ref={(ref) => this.setReactInstance(ref)} /> , ); diff --git a/packages/shared-components/src/formio/components/core/driving-list/DrivingList.tsx b/packages/shared-components/src/formio/components/core/driving-list/DrivingList.tsx index 1550652ce..71da19871 100644 --- a/packages/shared-components/src/formio/components/core/driving-list/DrivingList.tsx +++ b/packages/shared-components/src/formio/components/core/driving-list/DrivingList.tsx @@ -1,12 +1,12 @@ -import { DrivingListSubmission, DrivingListValues, TEXTS } from '@navikt/skjemadigitalisering-shared-domain'; +import { dateUtils, DrivingListSubmission, DrivingListValues, TEXTS } from '@navikt/skjemadigitalisering-shared-domain'; import NavDrivingList from '../../../../components/drivinglist/NavDrivingList'; import BaseComponent from '../../base/BaseComponent'; import drivingListBuilder from './DrivingList.builder'; import drivingListForm from './DrivingList.form'; import { DrivingListErrorType, - DrivingListMetadataId, drivingListMetadata, + DrivingListMetadataId, isValidParking, requiredError, } from './DrivingList.utils'; @@ -45,18 +45,14 @@ class DrivingList extends BaseComponent { return this.componentErrors; } - override addError(metadataId: DrivingListMetadataId, message: string): void { - super.addError(drivingListMetadata(metadataId).id, message); - } - addErrorOfType(metadataId: DrivingListMetadataId, errorType: DrivingListErrorType) { if (errorType === 'required') { - super.addError(drivingListMetadata(metadataId).id, requiredError(metadataId, this.t.bind(this))); + super.addError(requiredError(metadataId, this.t.bind(this)), drivingListMetadata(metadataId).id); } } - getComponentError(metadataId: DrivingListMetadataId) { - return this.componentErrors.find((error) => error.metadataId === metadataId)?.message; + getComponentError(elementId: string) { + return this.componentErrors.find((error) => error.elementId === elementId)?.message; } override checkValidity(): boolean { @@ -95,13 +91,14 @@ class DrivingList extends BaseComponent { } } - if (componentData?.dates?.some((date) => !isValidParking(date.parking))) { - this.addError('dates', this.t(TEXTS.validering.validParkingExpenses)); - } - - if (componentData?.dates?.some((date) => Number(date.parking) > 100)) { - this.addError('dates', this.t(TEXTS.validering.parkingExpensesAboveHundred)); - } + componentData?.dates?.forEach((date) => { + if (!isValidParking(date.parking)) { + const message = this.t(TEXTS.validering.validParkingExpenses, { dato: dateUtils.toLocaleDate(date.date) }); + this.addError(message, `dates:${date.date}:parking`); + } else if (Number(date.parking) > 100) { + this.addError(this.t(TEXTS.validering.parkingExpensesAboveHundred), `dates:${date.date}:parking`); + } + }); this.rerender(); @@ -125,6 +122,7 @@ class DrivingList extends BaseComponent { t={this.t.bind(this)} locale={this.getLocale()} getComponentError={this.getComponentError.bind(this)} + addRef={this.addRef.bind(this)} > , diff --git a/packages/shared-components/src/formio/components/core/driving-list/DrivingListContext.tsx b/packages/shared-components/src/formio/components/core/driving-list/DrivingListContext.tsx index c7a2e3f74..6e18b1bfb 100644 --- a/packages/shared-components/src/formio/components/core/driving-list/DrivingListContext.tsx +++ b/packages/shared-components/src/formio/components/core/driving-list/DrivingListContext.tsx @@ -2,7 +2,6 @@ import { DrivingListSubmission, DrivingListValues } from '@navikt/skjemadigitali import { TFunction } from 'i18next'; import { createContext, useContext } from 'react'; import { AppConfigContextType } from '../../../../context/config/configContext'; -import { DrivingListMetadataId } from './DrivingList.utils'; interface DrivingListContextContextType { updateValues: (value: DrivingListValues) => void; @@ -10,7 +9,8 @@ interface DrivingListContextContextType { values: DrivingListSubmission; t: TFunction; locale: string; - getComponentError: (metadataId: DrivingListMetadataId) => string | undefined; + getComponentError: (elementId: string) => string | undefined; + addRef: (name: string, ref: HTMLElement | null) => void; } interface DrivingListProviderProps extends DrivingListContextContextType { diff --git a/packages/shared-components/src/formio/components/core/select/Select.test.tsx b/packages/shared-components/src/formio/components/core/select/Select.test.tsx index fd88283f7..732be7257 100644 --- a/packages/shared-components/src/formio/components/core/select/Select.test.tsx +++ b/packages/shared-components/src/formio/components/core/select/Select.test.tsx @@ -122,7 +122,7 @@ describe('NavSelect', () => { nextButton.click(); const errorMessages = await screen.findAllByText('Du må fylle ut: Velg frukt'); - expect(errorMessages).toHaveLength(2); // på toppen av siden, og nedenfor input-feltet + expect(errorMessages).toHaveLength(1); // nedenfor input-feltet }); it('changes language', async () => { diff --git a/packages/shared-components/src/formio/overrides/wizard-overrides.js/focusOnComponent.ts b/packages/shared-components/src/formio/overrides/wizard-overrides.js/focusOnComponent.ts new file mode 100644 index 000000000..00343b87b --- /dev/null +++ b/packages/shared-components/src/formio/overrides/wizard-overrides.js/focusOnComponent.ts @@ -0,0 +1,44 @@ +export type KeyOrFocusComponentId = string | { path: string; elementId?: string }; + +/** + * Overriding wizard's focusOnComponent to allow giving focus to components inside the formio component, + * accounting for complex custom components. + * @param wizard + */ +const focusOnComponent = (wizard) => (keyOrFocusComponentId: KeyOrFocusComponentId) => { + if (!keyOrFocusComponentId) { + return; + } + let pageIndex = 0; + const paramIsString = typeof keyOrFocusComponentId === 'string'; + const key = paramIsString ? keyOrFocusComponentId : keyOrFocusComponentId.path; + const elementId = !paramIsString ? keyOrFocusComponentId.elementId : undefined; + + const [page] = wizard.pages.filter((page, index) => { + let hasComponent = false; + page.getComponent(key, (comp) => { + if (comp.path === key) { + pageIndex = index; + hasComponent = true; + } + }); + return hasComponent; + }); + + if (page && page !== wizard.currentPage) { + return wizard.setPage(pageIndex).then(() => { + wizard.checkValidity(wizard.submission.data, true, wizard.submission.data); + wizard.showErrors(); + const component = wizard.getComponent(key); + if (component) { + component.focus({ elementId }); + } + }); + } + const component = wizard.getComponent(key); + if (component) { + component.focus({ elementId }); + } +}; + +export default focusOnComponent; diff --git a/packages/shared-components/src/formio/overrides/wizard-overrides.js/wizard-overrides.js b/packages/shared-components/src/formio/overrides/wizard-overrides.js/wizard-overrides.js index 7b77dd19f..32aebf696 100644 --- a/packages/shared-components/src/formio/overrides/wizard-overrides.js/wizard-overrides.js +++ b/packages/shared-components/src/formio/overrides/wizard-overrides.js/wizard-overrides.js @@ -1,4 +1,5 @@ -import { Formio } from 'formiojs'; +import { Formio, Utils } from 'formiojs'; +import focusOnComponent from './focusOnComponent'; const Wizard = Formio.Displays.displays.wizard; const WebForm = Formio.Displays.displays.webform; @@ -243,17 +244,8 @@ Wizard.prototype.attachHeader = function () { } else { this.currentPage.components.forEach((comp) => comp.setPristine(false)); - this.showErrors([]); - - if (this.refs.errorRef) { - this.loadRefs(this.element, { - errorRefHeader: 'single', - }); - - this.refs.errorRefHeader?.focus(); - } else { - this.scrollIntoView(this.element); - } + this.showErrors(); + setTimeout(() => this.emit('errorSummaryFocus'), 0); return Promise.reject(this.errors, true); } @@ -312,3 +304,49 @@ Wizard.prototype.rebuild = function () { }; return originalRebuild.call(this).then(setCurrentPage.bind(this)); }; + +const originalOnChange = Wizard.prototype.onChange; +Wizard.prototype.onChange = function (flags, changed, modified, changes) { + originalOnChange.call(this, flags, changed, modified, changes); + /** + * The original onChange function uses this.alert, but that will not be set anymore since we have + * taken control over the error summary, so we use this.hasErrors instead which is set in showErrors. + */ + if (this.hasErrors && !this.submitted) { + // if submitted, invoking checkValidity is handled elsewhere + this.checkValidity(this.localData, false, this.localData, true); + this.showErrors(); + } +}; + +/** + * We take full control of the error summary, so this function does not invoke the original + * showErrors in Webform. + * @returns errors + */ +Wizard.prototype.showErrors = function () { + const errs = this.getComponents() + .reduce((errors, comp) => errors.concat(comp.errors || []), []) + .filter((err) => err.level !== 'hidden') + .map((err) => { + return { + message: err.message || err.messages?.[0]?.message, + path: err.path || Utils.getStringFromComponentPath(err.messages?.[0]?.path), + elementId: err.elementId, + }; + }); + this.hasErrors = errs.length > 0; + this.emit('showErrors', errs); + return errs; +}; + +Wizard.prototype.focusOnComponent = function (arg) { + focusOnComponent(this)(arg); +}; + +const originalOnSubmissionError = Wizard.prototype.onSubmissionError; +Wizard.prototype.onSubmissionError = function (error) { + const result = originalOnSubmissionError.call(this, error); + setTimeout(() => this.emit('errorSummaryFocus'), 0); + return result; +}; diff --git a/packages/shared-components/src/formio/template/templates/navdesign/alert/form.ejs b/packages/shared-components/src/formio/template/templates/navdesign/alert/form.ejs deleted file mode 100644 index 9276ef71e..000000000 --- a/packages/shared-components/src/formio/template/templates/navdesign/alert/form.ejs +++ /dev/null @@ -1,10 +0,0 @@ -
- {{ctx.message}} - {% if (ctx.options.vpat) { %} - {{ctx.t('errorListHotkey')}} - {% } %} -
diff --git a/packages/shared-components/src/formio/template/templates/navdesign/alert/index.js b/packages/shared-components/src/formio/template/templates/navdesign/alert/index.js deleted file mode 100644 index 4d4897d4b..000000000 --- a/packages/shared-components/src/formio/template/templates/navdesign/alert/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import form from './form.ejs'; - -export default { form }; diff --git a/packages/shared-components/src/formio/template/templates/navdesign/errorsList/form.ejs b/packages/shared-components/src/formio/template/templates/navdesign/errorsList/form.ejs deleted file mode 100644 index 87fc1a3ae..000000000 --- a/packages/shared-components/src/formio/template/templates/navdesign/errorsList/form.ejs +++ /dev/null @@ -1,23 +0,0 @@ - -
    - {% ctx.errors.forEach(function(err, i) { %} -
  • - - {{err.message}} - -
  • - {% }) %} -
diff --git a/packages/shared-components/src/formio/template/templates/navdesign/errorsList/index.js b/packages/shared-components/src/formio/template/templates/navdesign/errorsList/index.js deleted file mode 100644 index 4d4897d4b..000000000 --- a/packages/shared-components/src/formio/template/templates/navdesign/errorsList/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import form from './form.ejs'; - -export default { form }; diff --git a/packages/shared-components/src/formio/template/templates/navdesign/index.js b/packages/shared-components/src/formio/template/templates/navdesign/index.js index c7f637645..5615e16eb 100644 --- a/packages/shared-components/src/formio/template/templates/navdesign/index.js +++ b/packages/shared-components/src/formio/template/templates/navdesign/index.js @@ -1,4 +1,3 @@ -import alert from './alert'; import builderComponent from './builderComponent'; import builderEditForm from './builderEditForm'; import builderWizard from './builderWizard'; @@ -10,7 +9,6 @@ import cssClasses from './cssClasses'; import datagrid from './datagrid'; import day from './day'; import dialog from './dialog'; -import errorsList from './errorsList'; import field from './field'; import file from './file'; import html from './html'; @@ -46,7 +44,6 @@ export default { defaultIconset: 'fa', iconClass, cssClasses, - alert, builderComponent, builderEditForm, builderWizard, @@ -57,7 +54,6 @@ export default { datagrid, day, dialog, - errorsList, field, file, html, diff --git a/packages/shared-components/src/pages/fill-in-form/FillInFormPage.tsx b/packages/shared-components/src/pages/fill-in-form/FillInFormPage.tsx index 06ab9eb9e..39b053f50 100644 --- a/packages/shared-components/src/pages/fill-in-form/FillInFormPage.tsx +++ b/packages/shared-components/src/pages/fill-in-form/FillInFormPage.tsx @@ -1,5 +1,13 @@ -import { FyllutState, NavFormType, navFormUtils, Submission, TEXTS } from '@navikt/skjemadigitalisering-shared-domain'; -import { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react'; +import { + ComponentError, + FyllutState, + NavFormType, + navFormUtils, + Submission, + TEXTS, +} from '@navikt/skjemadigitalisering-shared-domain'; +import EventEmitter from 'eventemitter3'; +import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; import ConfirmationModal from '../../components/modal/confirmation/ConfirmationModal'; import NavForm from '../../components/nav-form/NavForm'; @@ -7,12 +15,15 @@ import { useAmplitude } from '../../context/amplitude'; import { useAppConfig } from '../../context/config/configContext'; import { useLanguages } from '../../context/languages'; import { useSendInn } from '../../context/sendInn/sendInnContext'; +import { KeyOrFocusComponentId } from '../../formio/overrides/wizard-overrides.js/focusOnComponent'; import { LoadingComponent } from '../../index'; import { scrollToAndSetFocus } from '../../util/focus-management/focus-management'; import { getPanelSlug } from '../../util/form/form'; import urlUtils from '../../util/url/url'; +import FormErrorSummary from './FormErrorSummary'; type ModalType = 'save' | 'delete' | 'discard'; +type FyllutEvent = 'focusOnComponent'; interface FillInFormPageProps { form: NavFormType; @@ -48,6 +59,9 @@ export const FillInFormPage = ({ form, submission, setSubmission, formUrl }: Fil const mutationObserverRef = useRef(undefined); const formioInstanceRef = useRef(); const [showModal, setShowModal] = useState(); + const [errors, setErrors] = useState([]); + const fyllutEvents = useMemo(() => new EventEmitter(), []); + const errorSummaryRef = useRef(null); const exitUrl = urlUtils.getExitUrl(window.location.href); const deletionDate = submission?.fyllutState?.mellomlagring?.deletionDate ?? ''; @@ -60,6 +74,13 @@ export const FillInFormPage = ({ form, submission, setSubmission, formUrl }: Fil [formUrl, navigate], ); + const focusOnComponent = useCallback<(id: KeyOrFocusComponentId) => void>( + (id: KeyOrFocusComponentId) => { + fyllutEvents.emit('focusOnComponent', id); + }, + [fyllutEvents], + ); + const goToPanelFromUrlParam = useCallback( (formioInstance) => { // We need to get location data from window, since this function runs inside formio @@ -160,6 +181,19 @@ export const FillInFormPage = ({ form, submission, setSubmission, formUrl }: Fil [goToPanelFromUrlParam], ); + const onShowErrors = useCallback( + (errorsFromForm: ComponentError[]) => { + setErrors(errorsFromForm); + }, + [setErrors], + ); + + const onErrorSummaryFocus = useCallback(() => { + if (errorSummaryRef.current) { + errorSummaryRef.current.focus(); + } + }, []); + const getModalTexts = useCallback( (modalType?: ModalType) => { switch (modalType) { @@ -299,6 +333,12 @@ export const FillInFormPage = ({ form, submission, setSubmission, formUrl }: Fil return (
+ (errorSummaryRef.current = ref)} + /> void; +} + +const SPACE = ' '; + +const FormErrorSummary = forwardRef( + ({ heading, errors, focusOnComponent }, ref) => { + if (!errors.length) { + return <>; + } + return ( + + {errors.map((error) => ( + { + event.preventDefault(); + focusOnComponent({ path: error.path, elementId: error.elementId }); + }} + onKeyUp={(event) => { + if (event.key === 'Enter' || event.key === SPACE) { + event.stopPropagation(); + focusOnComponent({ path: error.path, elementId: error.elementId }); + } + }} + key={`${error.path}${error.elementId && `-${error.elementId}`}`} + > + {error.message} + + ))} + + ); + }, +); + +export default FormErrorSummary; diff --git a/packages/shared-components/src/styles/global/errorSummary.ts b/packages/shared-components/src/styles/global/errorSummary.ts index 2e66829ad..3a14561ff 100644 --- a/packages/shared-components/src/styles/global/errorSummary.ts +++ b/packages/shared-components/src/styles/global/errorSummary.ts @@ -1,5 +1,8 @@ const errorSummary = { '.navds-error-summary': { + '@media screen and (min-width: 40rem)': { + maxWidth: '608px', + }, marginBottom: 'var(--a-spacing-10)', '& .navds-link': { cursor: 'pointer', diff --git a/packages/shared-components/src/styles/global/index.ts b/packages/shared-components/src/styles/global/index.ts index 05489d2c1..3963e2e76 100644 --- a/packages/shared-components/src/styles/global/index.ts +++ b/packages/shared-components/src/styles/global/index.ts @@ -61,11 +61,6 @@ const global = { outline: 'none', }, }, - '.nav-form > .alert.alert-danger': { - '@media screen and (min-width: 40rem)': { - maxWidth: '608px', - }, - }, // TODO: Delete this temp class when all components are Aksel '.navds-text-field--error > .navds-text-field__input:not(:hover):not(:disabled), .navds-text-field--error > .navds-text-field__input:focus-visible:not(:hover):not(:disabled)': { diff --git a/packages/shared-domain/src/component/index.ts b/packages/shared-domain/src/component/index.ts index 6a9cd3070..b6e88476d 100644 --- a/packages/shared-domain/src/component/index.ts +++ b/packages/shared-domain/src/component/index.ts @@ -1,9 +1,6 @@ export interface ComponentError { - metadataId: string; + elementId?: string; message: string; path: string; level: 'error'; - - messages: { formattedKeyOrPath: string; message: string; context: { hasLabel: boolean } }[]; - component: { key: string }; } diff --git a/packages/shared-domain/src/texts/validering.js b/packages/shared-domain/src/texts/validering.js index 95f391688..2cf249313 100644 --- a/packages/shared-domain/src/texts/validering.js +++ b/packages/shared-domain/src/texts/validering.js @@ -38,7 +38,7 @@ export const validering = { orgNrCustomError: 'Dette er ikke et gyldig organisasjonsnummer', // driving list - validParkingExpenses: 'Parkeringsutgiftene må være et gyldig beløp', + validParkingExpenses: 'Parkeringsutgiftene for {{dato}} må være et gyldig beløp', parkingExpensesAboveHundred: 'Du kan ikke legge inn parkeringsutgifter over 100 kroner i den elektroniske kjørelisten. Hvis du har parkeringsutgifter over 100 kroner per dag må du sende inn kjøreliste på skjema NAV 00-01.01 og legge ved kvitteringer som dokumenterer utgiften.', };