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 090a11d59ee..b5bfbab93f5 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
@@ -211,3 +211,26 @@ export const ValidationExtendValidatorAdult = () => {
)
}
+
+export const ValidationFnrAdult = () => {
+ return (
+
+ {() => {
+ const myFnrAdultValidator = (value, { validators }) => {
+ const { adultValidator, fnrValidator } = validators
+
+ return [fnrValidator, adultValidator]
+ }
+
+ 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 34fdcd66139..fdd5f59f534 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
@@ -75,3 +75,7 @@ You can [extend the existing validations](/uilib/extensions/forms/create-compone
You can [extend the existing validations](/uilib/extensions/forms/create-component/useFieldProps/info/#validators)(`dnrValidator`, `fnrValidator`, and `dnrAndFnrValidator`) with the `adultValidator`.
+
+### Validate only national identity numbers(fnr) above 18 years old
+
+
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 7b8902a1fee..79e74aaedbb 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
@@ -26,7 +26,7 @@ import { NationalIdentityNumberProperties } from '@dnb/eufemia/src/extensions/fo
- `dnrAndFnrValidator`:
- validates the identification number as a D number when first digit is 4 or greater (because a D number has its first number increased by 4).
- validates the identification number as a national identity number (fødselsnummer) when first digit is 3 or less.
-- `adultValidator`: validates if the identification number has a date of birth that is 18 years or older.
+- `adultValidator`: validates if the identification number has a date of birth that is 18 years or older. It uses only the 9 first digits of an identification number to validate, first 6 digits representing the birth of date, and the next three digits are individual numbers. It does not validate the identification number, therefore it's quite common to use this validator together with one of the validators above (`dnrValidator`, `fnrValidator` or `dnrAndFnrValidator`) to validate the identification number as well.
See the following [example](/uilib/extensions/forms/feature-fields/NationalIdentityNumber/#extend-validation-with-custom-validation-function) on how to extend validation using the exposed validators.
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 b19d97de5bf..c3d0515d0f6 100644
--- a/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumber.tsx
+++ b/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumber.tsx
@@ -26,8 +26,11 @@ function NationalIdentityNumber(props: Props) {
const fnrValidator = useCallback(
(value: string) => {
- // We don't want to validate if the value is undefined
- if (value !== undefined && fnr(value).status === 'invalid') {
+ if (
+ value !== undefined &&
+ (Number.parseInt(value.substring(0, 1)) > 3 ||
+ fnr(value).status === 'invalid')
+ ) {
return Error(errorFnr)
}
},
@@ -36,8 +39,11 @@ function NationalIdentityNumber(props: Props) {
const dnrValidator = useCallback(
(value: string) => {
- // We don't want to validate if the value is undefined
- if (value !== undefined && dnr(value).status === 'invalid') {
+ if (
+ value !== undefined &&
+ (Number.parseInt(value.substring(0, 1)) < 4 ||
+ dnr(value).status === 'invalid')
+ ) {
return Error(errorDnr)
}
},
@@ -58,7 +64,9 @@ function NationalIdentityNumber(props: Props) {
const adultValidator = useCallback(
(value: string) => {
- // We don't want to validate if the value is undefined
+ // if (value !== undefined && value.length < 9) {
+ // return Error(errorAdultPattern)
+ // }
if (value !== undefined && !is18YearsOrOlder(value)) {
return Error(errorAdult)
}
@@ -142,7 +150,9 @@ function is18YearsOrOlder(value: string) {
const year = isBornIn20XX ? `20${yearPart}` : `19${yearPart}`
const month = Number.parseInt(value.substring(2, 4))
- const isDnr = dnr(value).status === 'valid'
+ const differentiatorValue =
+ value.length > 0 ? Number.parseInt(value.substring(0, 1)) : undefined
+ const isDnr = differentiatorValue && differentiatorValue > 3
const day = isDnr
? Number.parseInt(value.substring(0, 2)) - 40
diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/__tests__/NationalIdentityNumberAdultValidator.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/__tests__/NationalIdentityNumberAdultValidator.test.tsx
index 7025d81ce52..8474a8e829b 100644
--- a/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/__tests__/NationalIdentityNumberAdultValidator.test.tsx
+++ b/packages/dnb-eufemia/src/extensions/forms/Field/NationalIdentityNumber/__tests__/NationalIdentityNumberAdultValidator.test.tsx
@@ -15,6 +15,24 @@ describe('Field.NationalIdentityNumber with adultValidator', () => {
return [dnrAndFnrValidator, adultValidator]
}
+ const extendingDnrValidatorWithAdultValidator: Validator = (
+ value,
+ { validators }
+ ) => {
+ const { adultValidator, dnrValidator } = validators
+
+ return [dnrValidator, adultValidator]
+ }
+
+ const extendingFnrValidatorWithAdultValidator: Validator = (
+ value,
+ { validators }
+ ) => {
+ const { adultValidator, fnrValidator } = validators
+
+ return [fnrValidator, adultValidator]
+ }
+
const myAdultValidator: Validator = (value, { validators }) => {
const { adultValidator } = validators
@@ -97,7 +115,6 @@ describe('Field.NationalIdentityNumber with adultValidator', () => {
'07070663990',
'11030699302',
'31010699021',
- '49100651997',
]
const fnr99Years = [
'14102535759',
@@ -404,5 +421,243 @@ describe('Field.NationalIdentityNumber with adultValidator', () => {
}
)
})
+
+ describe('when extending the dnrValidator as validator', () => {
+ it.each(dnr18YearsOldAndOlder)(
+ 'D number is 18 years or older : %s',
+ async (validDnum) => {
+ render(
+
+ )
+
+ await expect(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ }).neverToResolve()
+ }
+ )
+
+ it.each(dnrUnder18YearsOld)(
+ 'D number is not 18 years or older: %s',
+ async (invalidDnum) => {
+ render(
+
+ )
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ expect(screen.queryByRole('alert')).toHaveTextContent(
+ nb.NationalIdentityNumber.errorAdult
+ )
+ })
+ }
+ )
+
+ it.each([...invalidDnums, ...invalidFnrs, ...fnr18YearsOldAndOlder])(
+ 'Invalid d number: %s',
+ async (invalidDnum) => {
+ render(
+
+ )
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ expect(screen.queryByRole('alert')).toHaveTextContent(
+ nb.NationalIdentityNumber.errorDnr
+ )
+ })
+ }
+ )
+ })
+
+ describe('when extending the dnrValidator as onBlurValidator', () => {
+ it.each(dnr18YearsOldAndOlder)(
+ 'D number is 18 years or older : %s',
+ async (validDnum) => {
+ render(
+
+ )
+
+ await expect(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ }).neverToResolve()
+ }
+ )
+
+ it.each(dnrUnder18YearsOld)(
+ 'D number is not 18 years or older: %s',
+ async (invalidDnum) => {
+ render(
+
+ )
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ expect(screen.queryByRole('alert')).toHaveTextContent(
+ nb.NationalIdentityNumber.errorAdult
+ )
+ })
+ }
+ )
+
+ it.each([
+ ...invalidDnums,
+ ...invalidFnrs,
+ ...fnr18YearsOldAndOlder,
+ ...fnrUnder18YearsOld,
+ ])('Invalid d number: %s', async (invalidDnum) => {
+ render(
+
+ )
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ expect(screen.queryByRole('alert')).toHaveTextContent(
+ nb.NationalIdentityNumber.errorDnr
+ )
+ })
+ })
+ })
+
+ describe('when extending the fnrValidator as validator', () => {
+ it.each(fnr18YearsOldAndOlder)(
+ 'Identity number(fnr) is 18 years or older : %s',
+ async (validFnr) => {
+ render(
+
+ )
+
+ await expect(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ }).neverToResolve()
+ }
+ )
+
+ it.each(fnrUnder18YearsOld)(
+ 'Identity number(fnr) is not 18 years or older: %s',
+ async (invalidFnr) => {
+ render(
+
+ )
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ expect(screen.queryByRole('alert')).toHaveTextContent(
+ nb.NationalIdentityNumber.errorAdult
+ )
+ })
+ }
+ )
+
+ it.each([...invalidFnrs, ...invalidDnums, ...dnr18YearsOldAndOlder])(
+ 'Invalid identity number(fnr): %s',
+ async (invalidFnr) => {
+ render(
+
+ )
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ expect(screen.queryByRole('alert')).toHaveTextContent(
+ nb.NationalIdentityNumber.errorFnr
+ )
+ })
+ }
+ )
+ })
+
+ describe('when extending the fnrValidator as onBlurValidator', () => {
+ it.each(fnr18YearsOldAndOlder)(
+ 'Identity number(fnr) is 18 years or older : %s',
+ async (validFnr) => {
+ render(
+
+ )
+
+ await expect(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ }).neverToResolve()
+ }
+ )
+
+ it.each(fnrUnder18YearsOld)(
+ 'Identity number(fnr) is not 18 years or older: %s',
+ async (invalidFnr) => {
+ render(
+
+ )
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ expect(screen.queryByRole('alert')).toHaveTextContent(
+ nb.NationalIdentityNumber.errorAdult
+ )
+ })
+ }
+ )
+
+ it.each([
+ ...invalidFnrs,
+ ...invalidDnums,
+ ...dnr18YearsOldAndOlder,
+ ...dnrUnder18YearsOld,
+ ])('Invalid identity number(fnr): %s', async (invalidFnr) => {
+ render(
+
+ )
+ await waitFor(() => {
+ expect(screen.queryByRole('alert')).toBeInTheDocument()
+ expect(screen.queryByRole('alert')).toHaveTextContent(
+ nb.NationalIdentityNumber.errorFnr
+ )
+ })
+ })
+ })
})
})