diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/Examples.tsx index 21f9d6af699..cc800a9ab43 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/Examples.tsx @@ -160,3 +160,35 @@ export const ValidationFunction = () => { ) } + +export const ValidationExtendValidator = () => { + return ( + + {() => { + const bornInApril = (value: string) => + value.substring(2, 4) === '04' + ? { status: 'valid' } + : { status: 'invalid' } + + const myValidator = (value, { validators }) => { + const { dnrValidator, fnrValidator } = validators + const result = bornInApril(value) + if (result.status === 'invalid') { + return new Error('My error') + } + + return [dnrValidator, fnrValidator] + } + + return ( + + ) + }} + + ) +} diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/demos.mdx index 097fd7e3b2e..24a8c45cc02 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/demos.mdx @@ -63,3 +63,9 @@ Below is an example of the error message displayed when there's an invalid D num You can provide your own validation function. + +### Extend validation with custom validation function + +You can [extend the existing validations](/uilib/extensions/forms/create-component/useFieldProps/info/#validators)(`dnrValidator` and `fnrValidator`) with your own validation function. + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/properties.mdx index 40cde507d48..850fb75a587 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/properties.mdx @@ -5,15 +5,13 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { NationalIdentityNumberProperties } from '@dnb/eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumberDocs' ## Properties ### Field-specific props -| Property | Type | Description | -| ---------- | --------- | ------------------------------------------------------------------------------- | -| `validate` | `boolean` | _(optional)_ Using this prop you can disable the default validation. | -| `help` | `object` | _(optional)_ Provide a help button. Object consisting of `title` and `content`. | + ### General props diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumber.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumber.tsx index 9252e43e553..a3cc7ed9d8b 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumber.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumber.tsx @@ -52,7 +52,6 @@ function NationalIdentityNumber(props: Props) { ) { return Error(errorFnr) } - return undefined }, [errorFnr] ) @@ -66,7 +65,6 @@ function NationalIdentityNumber(props: Props) { ) { return Error(errorDnr) } - return undefined }, [errorDnr] ) @@ -94,6 +92,7 @@ function NationalIdentityNumber(props: Props) { validator: validate ? props.validator || dnrAndFnrValidator : undefined, + exportValidators: { dnrValidator, fnrValidator }, } return diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumberDocs.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumberDocs.tsx new file mode 100644 index 00000000000..2445ff8175b --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumberDocs.tsx @@ -0,0 +1,14 @@ +import { PropertiesTableProps } from '../../../../shared/types' + +export const NationalIdentityNumberProperties: PropertiesTableProps = { + validate: { + doc: 'Using this prop you can disable the default validation.', + type: 'boolean', + status: 'optional', + }, + help: { + doc: 'Provide a help button. Object consisting of `title` and `content`.', + type: 'object', + status: 'optional', + }, +} diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/__tests__/NationalIdentityNumber.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/__tests__/NationalIdentityNumber.test.tsx index 1b41434aaef..d89d405f1b0 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/__tests__/NationalIdentityNumber.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/__tests__/NationalIdentityNumber.test.tsx @@ -1,7 +1,7 @@ import React from 'react' import { fireEvent, render, waitFor, screen } from '@testing-library/react' import { Props } from '..' -import { Field, Form } from '../../..' +import { Field, Form, Validator } from '../../..' import nbNO from '../../../constants/locales/nb-NO' const nb = nbNO['nb-NO'] @@ -211,6 +211,38 @@ describe('Field.NationalIdentityNumber', () => { }) }) + it('should not validate extended validator when validate false', async () => { + const invalidFnr = '29040112345' + + const bornInApril = (value: string) => + value.substring(2, 4) === '04' + ? { status: 'valid' } + : { status: 'invalid' } + + const customValidator: Validator = (value, { validators }) => { + const { dnrValidator, fnrValidator } = validators + const result = bornInApril(value) + if (result.status === 'invalid') { + return new Error('custom error') + } + + return [dnrValidator, fnrValidator] + } + + render( + + ) + await expectNever(() => { + // Can't just waitFor and expect not to be in the document, it would approve the first render before the error might appear async. + expect(screen.queryByRole('alert')).toBeInTheDocument() + }) + }) + describe('should validate Norwegian D number', () => { const validDNum = [ '53097248016', @@ -304,4 +336,103 @@ describe('Field.NationalIdentityNumber', () => { } ) }) + + describe('should extend validation using custom validator', () => { + const validFnrNumApril = ['14046512368', '10042223293'] + const validDNumApril = ['51041678171'] + + const validIds = [...validFnrNumApril, ...validDNumApril] + + const invalidFnrNumApril = ['29040112345', '13047248032'] + const invalidDNumApril = ['69040112345', '53047248032'] + + const validFnrNumNotApril = [ + '58081633086', + '53050129159', + '65015439860', + ] + const validDNumNotApril = ['08121312590', '12018503288', '03025742965'] + + const invalidIds = [...validFnrNumNotApril, ...validDNumNotApril] + + const bornInApril = (value: string) => + value.substring(2, 4) === '04' + ? { status: 'valid' } + : { status: 'invalid' } + + const customValidator: Validator = (value, { validators }) => { + const { dnrValidator, fnrValidator } = validators + const result = bornInApril(value) + if (result.status === 'invalid') { + return new Error('custom error') + } + + return [dnrValidator, fnrValidator] + } + + it.each(validIds)('Valid identity number: %s', async (fnrNum) => { + render( + + ) + await expectNever(() => { + // Can't just waitFor and expect not to be in the document, it would approve the first render before the error might appear async. + expect(screen.queryByRole('alert')).toBeInTheDocument() + }) + }) + + it.each(invalidIds)('Invalid identity number: %s', async (id) => { + render( + + ) + await waitFor(() => { + expect(screen.queryByRole('alert')).toBeInTheDocument() + expect(screen.queryByRole('alert')).toHaveTextContent( + 'custom error' + ) + }) + }) + + it.each(invalidDNumApril)('Invalid D number: %s', async (dNum) => { + render( + + ) + await waitFor(() => { + expect(screen.queryByRole('alert')).toBeInTheDocument() + expect(screen.queryByRole('alert')).toHaveTextContent( + nb.NationalIdentityNumber.errorDnr + ) + }) + }) + + it.each(invalidFnrNumApril)( + 'Invalid national identity number(fnr): %s', + async (fnr) => { + render( + + ) + await waitFor(() => { + expect(screen.queryByRole('alert')).toBeInTheDocument() + expect(screen.queryByRole('alert')).toHaveTextContent( + nb.NationalIdentityNumber.errorFnr + ) + }) + } + ) + }) })