From 559fc95225c3e7a9072ebdec8d1d4b34c09e481f Mon Sep 17 00:00:00 2001 From: Hadrien Mens-Pellen Date: Thu, 3 Aug 2023 16:04:59 +0200 Subject: [PATCH 1/5] feat: afficher le NIR dans les informations personnelles --- app/package-lock.json | 44 +++++++ app/package.json | 2 + app/src/lib/helpers.ts | 5 + .../ProBeneficiaryUpdateFields.svelte | 36 ++++-- .../beneficiary.schema.ts | 13 ++ .../ProNotebookPersonalInfoUpdate.svelte | 119 ++++-------------- .../ProNotebookPersonalInfoUpdateView.svelte | 107 ++++++++++++++++ .../ProNotebookPersonalInfoUpdateView.test.ts | 78 ++++++++++++ .../ProNotebookPersonalInfoView.svelte | 4 +- app/src/lib/validation.ts | 4 + .../_getNotebookByBeneficiaryId.gql | 1 + .../routes/(auth)/pro/carnet/_getNotebook.gql | 1 + hasura/metadata/actions.graphql | 12 +- hasura/metadata/actions.yaml | 22 ++-- .../tables/public_beneficiary.yaml | 10 +- 15 files changed, 329 insertions(+), 129 deletions(-) create mode 100644 app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.svelte create mode 100644 app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts diff --git a/app/package-lock.json b/app/package-lock.json index 34fa13af3..b5f90e719 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -40,6 +40,7 @@ "@babel/core": "7.21.4", "@babel/preset-env": "7.21.4", "@babel/preset-typescript": "7.21.4", + "@faker-js/faker": "^8.0.2", "@graphql-codegen/cli": "3.2.2", "@graphql-codegen/typed-document-node": "3.0.2", "@graphql-codegen/typescript": "3.0.2", @@ -58,6 +59,7 @@ "@tailwindcss/typography": "^0.5.0", "@testing-library/jest-dom": "^5.16.1", "@testing-library/svelte": "^3.0.3", + "@testing-library/user-event": "^14.4.3", "@types/cookie": "^0.5.0", "@types/jsonwebtoken": "9.0.1", "@types/nodemailer": "^6.4.4", @@ -2707,6 +2709,22 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@faker-js/faker": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.0.2.tgz", + "integrity": "sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0", + "npm": ">=6.14.13" + } + }, "node_modules/@fal-works/esbuild-plugin-global-externals": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz", @@ -6736,6 +6754,19 @@ "svelte": "3.x" } }, + "node_modules/@testing-library/user-event": { + "version": "14.4.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", + "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", + "dev": true, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -26294,6 +26325,12 @@ "integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==", "dev": true }, + "@faker-js/faker": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.0.2.tgz", + "integrity": "sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A==", + "dev": true + }, "@fal-works/esbuild-plugin-global-externals": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz", @@ -29292,6 +29329,13 @@ "@testing-library/dom": "^8.1.0" } }, + "@testing-library/user-event": { + "version": "14.4.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", + "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", + "dev": true, + "requires": {} + }, "@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", diff --git a/app/package.json b/app/package.json index 15cbe7857..948e4c311 100644 --- a/app/package.json +++ b/app/package.json @@ -52,6 +52,7 @@ "@babel/core": "7.21.4", "@babel/preset-env": "7.21.4", "@babel/preset-typescript": "7.21.4", + "@faker-js/faker": "^8.0.2", "@graphql-codegen/cli": "3.2.2", "@graphql-codegen/typed-document-node": "3.0.2", "@graphql-codegen/typescript": "3.0.2", @@ -70,6 +71,7 @@ "@tailwindcss/typography": "^0.5.0", "@testing-library/jest-dom": "^5.16.1", "@testing-library/svelte": "^3.0.3", + "@testing-library/user-event": "^14.4.3", "@types/cookie": "^0.5.0", "@types/jsonwebtoken": "9.0.1", "@types/nodemailer": "^6.4.4", diff --git a/app/src/lib/helpers.ts b/app/src/lib/helpers.ts index d9d36bdb2..eaffc7c24 100644 --- a/app/src/lib/helpers.ts +++ b/app/src/lib/helpers.ts @@ -22,6 +22,11 @@ export const pluck = function pluck( return result; }; +export function trimToNull(arg0: string): string { + const trimmed = arg0.trim(); + return trimmed === '' ? null : trimmed; +} + export function filterFalsyProps(obj: Record): Record { const result = {}; for (const [k, v] of Object.entries(obj)) { diff --git a/app/src/lib/ui/ProBeneficiaryUpdate/ProBeneficiaryUpdateFields.svelte b/app/src/lib/ui/ProBeneficiaryUpdate/ProBeneficiaryUpdateFields.svelte index 44d03fef8..a51b2aca5 100644 --- a/app/src/lib/ui/ProBeneficiaryUpdate/ProBeneficiaryUpdateFields.svelte +++ b/app/src/lib/ui/ProBeneficiaryUpdate/ProBeneficiaryUpdateFields.svelte @@ -2,6 +2,7 @@ export type Field = | 'firstname' | 'lastname' + | 'nir' | 'dateOfBirth' | 'rightRsa' | 'rightAre' @@ -16,14 +17,9 @@ import { Checkbox, Radio } from '../forms'; export let disabledFields: Field[]; - // We can by default edit any field - - function isFieldDisabled(fieldName: Field) { - return disabledFields.includes(fieldName); - } function titleForField(fieldName: Field) { - return isFieldDisabled(fieldName) + return disabledFields.includes(fieldName) ? 'Ce champ n‘est pas modifiable. Si toutefois vous devez y apporter une modification, merci de nous contacter par chat.' : ''; } @@ -34,7 +30,7 @@ placeholder="Jean-Baptiste" name="firstname" required - disabled={isFieldDisabled('firstname')} + disabled={disabledFields.includes('firstname')} title={titleForField('firstname')} /> @@ -43,10 +39,20 @@ placeholder="Poquelin" name="lastname" required - disabled={isFieldDisabled('lastname')} + disabled={disabledFields.includes('lastname')} title={titleForField('lastname')} /> + + @@ -78,19 +84,23 @@ legend="Revenu de solidarité active (RSA)" name="rightRsa" options={rsaRightKeys.options} - disabled={isFieldDisabled('rightRsa')} + disabled={disabledFields.includes('rightRsa')} />
Autres aides
- +
- +
- +
diff --git a/app/src/lib/ui/ProBeneficiaryUpdate/beneficiary.schema.ts b/app/src/lib/ui/ProBeneficiaryUpdate/beneficiary.schema.ts index a89858071..69f3c8255 100644 --- a/app/src/lib/ui/ProBeneficiaryUpdate/beneficiary.schema.ts +++ b/app/src/lib/ui/ProBeneficiaryUpdate/beneficiary.schema.ts @@ -3,6 +3,7 @@ import { nullifyEmptyString, validateCodePostal, validateDateInput, + validateNir, validatePhoneNumber, } from '$lib/validation'; import * as yup from 'yup'; @@ -17,6 +18,17 @@ const beneficiaryAccountSchemaObject = { .test('is-date-valid', 'Le format de la date est incorrect', validateDateInput) .required(), + nir: yup + .string() + .trim() + .test( + 'is-nir-valid', + 'Le NIR doit être composé de 13 chiffres', + (value) => !value || validateNir(value) + ) + .transform(nullifyEmptyString) + .nullable(), + mobileNumber: yup .string() .trim() @@ -58,6 +70,7 @@ export const beneficiaryAccountPartialSchema = yup.object().shape({ firstname: beneficiaryAccountSchemaObject.firstname.optional(), lastname: beneficiaryAccountSchemaObject.lastname.optional(), dateOfBirth: beneficiaryAccountSchemaObject.dateOfBirth.optional(), + nir: beneficiaryAccountSchemaObject.nir.optional(), }); export type BeneficiaryAccountInput = yup.InferType; diff --git a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdate.svelte b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdate.svelte index e24ecfc2d..5d05e1eb8 100644 --- a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdate.svelte +++ b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdate.svelte @@ -1,83 +1,28 @@ -
-

Informations personnelles

-
- - - -
- - -
- -
+ diff --git a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.svelte b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.svelte new file mode 100644 index 000000000..ce18ec8b1 --- /dev/null +++ b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.svelte @@ -0,0 +1,107 @@ + + + + +
+

Informations personnelles

+
+ + + +
+ + +
+ +
diff --git a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts new file mode 100644 index 000000000..0e67b6246 --- /dev/null +++ b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts @@ -0,0 +1,78 @@ +import '@testing-library/jest-dom'; + +import { RoleEnum } from '$lib/graphql/_gen/typed-document-nodes'; +import { faker } from '@faker-js/faker'; +import { fireEvent, render, screen, waitFor } from '@testing-library/svelte'; +import userEvent from '@testing-library/user-event'; +import { v4 as uuidv4 } from 'uuid'; +import { expect, vi } from 'vitest'; +import ProNotebookPersonalInfoUpdateView from './ProNotebookPersonalInfoUpdateView.svelte'; + +const user = userEvent.setup(); +describe('Mise à jour des données personelles', () => { + it(`Met à jour le NIR`, async () => { + const { onSubmit } = setup(); + + const newNIR = '1234567890123'; + await changeNir(newNIR); + await submit(); + + await waitFor(() => + expect(onSubmit.mock.lastCall[1]).toEqual(expect.objectContaining({ nir: newNIR })) + ); + }); + + it(`Rejette les valeurs incorrectes`, async () => { + setup(); + + await changeNir('Je ne suis pas un NIR'); + await submit(); + + await waitFor(() => + expect(screen.getByText('Le NIR doit être composé de 13 chiffres')).toBeInTheDocument() + ); + }); + it('transforme un NIR blanc en undefined', async () => { + const { onSubmit } = setup(); + + await changeNir(' '); + await submit(); + + await waitFor(() => + expect(onSubmit.mock.lastCall[1]).toEqual(expect.objectContaining({ nir: null })) + ); + }); +}); + +const setup = () => { + const onSubmit = vi.fn(); + const onCancel = vi.fn(); + render(ProNotebookPersonalInfoUpdateView, { + beneficiary: { + id: uuidv4(), + firstname: faker.person.firstName(), + lastname: faker.person.lastName(), + dateOfBirth: faker.date.past().toISOString(), + nir: faker.number.int({ min: 1000000000000, max: 9999999999999 }) + '', + rightAre: false, + rightAss: false, + rightBonus: false, + }, + role: RoleEnum.Professional, + onSubmit, + onCancel, + }); + // throw Error(printDateFr(faker.date.past())); + return { onSubmit, onCancel }; +}; +async function changeNir(nir: string) { + const nirField = screen.getByRole('textbox', { name: 'NIR' }); + await user.clear(nirField); + await user.type(nirField, nir); + expect(nirField).toHaveValue(nir); + return nir; +} + +async function submit() { + await fireEvent.click(screen.getByRole('button', { name: 'Enregistrer' })); +} diff --git a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoView.svelte b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoView.svelte index 37d0a107a..34872def4 100644 --- a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoView.svelte +++ b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoView.svelte @@ -24,6 +24,7 @@ | 'lastname' | 'mobileNumber' | 'email' + | 'nir' | 'dateOfBirth' | 'address1' | 'address2' @@ -80,7 +81,8 @@ {displayFullName(beneficiary)} -
Né le {formatDateLocale(beneficiary.dateOfBirth)}
+
NIR: {beneficiary.nir ?? 'Inconnu'}
+
Né le {formatDateLocale(beneficiary.dateOfBirth)}

Informations personnelles

diff --git a/app/src/lib/validation.ts b/app/src/lib/validation.ts index 3e300cb49..e3d760eec 100644 --- a/app/src/lib/validation.ts +++ b/app/src/lib/validation.ts @@ -19,6 +19,10 @@ export function validatePhoneNumber(value: string): boolean { return /^(?:(?:\+|00)33|0)\s*[1-9](?:[\s.-]*\d{2}){4}$/.test(value.trim()); } +export function validateNir(value: string): boolean { + return /^\d{13}/.test(value.trim()); +} + export function validateCodePostal(value: string): boolean { // le code postal est composé de 5 chiffres mais // ne peut pas commencer par 00 sinon il est pas valide diff --git a/app/src/routes/(auth)/beneficiaire/_getNotebookByBeneficiaryId.gql b/app/src/routes/(auth)/beneficiaire/_getNotebookByBeneficiaryId.gql index 232afe9d8..9c8f3c05b 100644 --- a/app/src/routes/(auth)/beneficiaire/_getNotebookByBeneficiaryId.gql +++ b/app/src/routes/(auth)/beneficiaire/_getNotebookByBeneficiaryId.gql @@ -73,6 +73,7 @@ fragment notebookFragment on notebook { cafNumber city dateOfBirth + nir email firstname id diff --git a/app/src/routes/(auth)/pro/carnet/_getNotebook.gql b/app/src/routes/(auth)/pro/carnet/_getNotebook.gql index 76757f7cf..ce25a6586 100644 --- a/app/src/routes/(auth)/pro/carnet/_getNotebook.gql +++ b/app/src/routes/(auth)/pro/carnet/_getNotebook.gql @@ -13,6 +13,7 @@ query GetNotebook($id: uuid!, $withOrientationRequests: Boolean = true) { city dateOfBirth email + nir firstname id lastname diff --git a/hasura/metadata/actions.graphql b/hasura/metadata/actions.graphql index 89e24f542..83af0323c 100644 --- a/hasura/metadata/actions.graphql +++ b/hasura/metadata/actions.graphql @@ -31,12 +31,6 @@ type Query { ): PoleEmploiDossierIndividu } -type Mutation { - update_notebook_from_pole_emploi( - notebookId: uuid! - ): UpdateNotebookFromPoleEmploiOutput -} - type Mutation { remove_notebook_focus( id: uuid! @@ -50,6 +44,12 @@ type Mutation { ): UpdateNotebookFocusLink } +type Mutation { + update_notebook_from_pole_emploi( + notebookId: uuid! + ): UpdateNotebookFromPoleEmploiOutput +} + type Mutation { update_notebook_target_status( status: String! diff --git a/hasura/metadata/actions.yaml b/hasura/metadata/actions.yaml index 01a852181..1aeaae5bc 100644 --- a/hasura/metadata/actions.yaml +++ b/hasura/metadata/actions.yaml @@ -60,22 +60,22 @@ actions: - role: orientation_manager - role: professional comment: Récupération du diagnostic individu pole-emploi - - name: update_notebook_from_pole_emploi + - name: remove_notebook_focus definition: kind: synchronous - handler: '{{BACKEND_API_ACTION_URL}}/v1/notebooks/update-notebook-from-pole-emploi' + handler: '{{BACKEND_API_ACTION_URL}}/v1/notebook_focus/delete' headers: - name: secret-token value_from_env: ACTION_SECRET permissions: - - role: admin_structure - role: professional - role: orientation_manager - - role: manager - - name: remove_notebook_focus + - role: admin_cdb + comment: Remove notebook focus + - name: update_notebook_focus_link definition: kind: synchronous - handler: '{{BACKEND_API_ACTION_URL}}/v1/notebook_focus/delete' + handler: '{{BACKEND_API_ACTION_URL}}/v1/notebook_focus/update' headers: - name: secret-token value_from_env: ACTION_SECRET @@ -83,19 +83,19 @@ actions: - role: professional - role: orientation_manager - role: admin_cdb - comment: Remove notebook focus - - name: update_notebook_focus_link + comment: Update a notebook focus link + - name: update_notebook_from_pole_emploi definition: kind: synchronous - handler: '{{BACKEND_API_ACTION_URL}}/v1/notebook_focus/update' + handler: '{{BACKEND_API_ACTION_URL}}/v1/notebooks/update-notebook-from-pole-emploi' headers: - name: secret-token value_from_env: ACTION_SECRET permissions: + - role: admin_structure - role: professional - role: orientation_manager - - role: admin_cdb - comment: Update a notebook focus link + - role: manager - name: update_notebook_target_status definition: kind: synchronous diff --git a/hasura/metadata/databases/carnet_de_bord/tables/public_beneficiary.yaml b/hasura/metadata/databases/carnet_de_bord/tables/public_beneficiary.yaml index 0a5bd0dd2..a1bafb13d 100644 --- a/hasura/metadata/databases/carnet_de_bord/tables/public_beneficiary.yaml +++ b/hasura/metadata/databases/carnet_de_bord/tables/public_beneficiary.yaml @@ -184,12 +184,13 @@ select_permissions: - date_of_birth - deployment_id - email + - external_id - firstname - id - - external_id - is_homeless - lastname - mobile_number + - nir - pe_number - pe_unique_import_id - place_of_birth @@ -221,6 +222,7 @@ select_permissions: - is_homeless - lastname - mobile_number + - nir - pe_number - place_of_birth - postal_code @@ -266,6 +268,7 @@ select_permissions: - is_homeless - lastname - mobile_number + - nir - pe_number - pe_unique_import_id - postal_code @@ -297,6 +300,7 @@ select_permissions: - is_homeless - lastname - mobile_number + - nir - pe_number - place_of_birth - postal_code @@ -329,6 +333,7 @@ select_permissions: - is_homeless - lastname - mobile_number + - nir - pe_number - place_of_birth - postal_code @@ -361,6 +366,7 @@ select_permissions: - is_homeless - lastname - mobile_number + - nir - pe_number - place_of_birth - postal_code @@ -392,6 +398,7 @@ update_permissions: - id - lastname - mobile_number + - nir - pe_number - place_of_birth - postal_code @@ -458,6 +465,7 @@ update_permissions: - is_homeless - lastname - mobile_number + - nir - pe_number - place_of_birth - postal_code From b0db2dd814e6868024449b8a92bcd181342826dc Mon Sep 17 00:00:00 2001 From: Hadrien Mens-Pellen Date: Tue, 8 Aug 2023 17:00:31 +0200 Subject: [PATCH 2/5] fix: permissions pro --- .../ProNotebookPersonalInfoUpdateView.svelte | 3 +- .../ProNotebookPersonalInfoUpdateView.test.ts | 64 +++++++++++-------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.svelte b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.svelte index ce18ec8b1..00ba1079a 100644 --- a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.svelte +++ b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.svelte @@ -63,8 +63,7 @@ export let onSubmit: (isPartialUpdate: boolean, values: BeneficiaryAccountInput) => void; export let onCancel: () => void; export let role: RoleEnum; - let isPartialUpdate: boolean; - $: isPartialUpdate = role !== RoleEnum.Manager; + const isPartialUpdate = role !== RoleEnum.Manager; const validationSchema = isPartialUpdate ? beneficiaryAccountPartialSchema diff --git a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts index 0e67b6246..ac065648a 100644 --- a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts +++ b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts @@ -10,41 +10,53 @@ import ProNotebookPersonalInfoUpdateView from './ProNotebookPersonalInfoUpdateVi const user = userEvent.setup(); describe('Mise à jour des données personelles', () => { - it(`Met à jour le NIR`, async () => { - const { onSubmit } = setup(); + describe('Permissions', () => { + it('Un professionel ne peut pas éditer,prénom, nom, date de naissance et NIR', () => { + setup({ role: RoleEnum.Professional }); - const newNIR = '1234567890123'; - await changeNir(newNIR); - await submit(); - - await waitFor(() => - expect(onSubmit.mock.lastCall[1]).toEqual(expect.objectContaining({ nir: newNIR })) - ); + expect(screen.getByRole('textbox', { name: /Prénom/ })).toBeDisabled(); + expect(screen.getByRole('textbox', { name: /Nom/ })).toBeDisabled(); + expect(screen.getByLabelText(/Date de naissance/)).toBeDisabled(); + expect(screen.getByRole('textbox', { name: /NIR/ })).toBeDisabled(); + }); }); + describe('NIR', () => { + it(`Met à jour le NIR`, async () => { + const { onSubmit } = setup(); - it(`Rejette les valeurs incorrectes`, async () => { - setup(); + const newNIR = '1234567890123'; + await changeNir(newNIR); + await submit(); - await changeNir('Je ne suis pas un NIR'); - await submit(); + await waitFor(() => + expect(onSubmit.mock.lastCall[1]).toEqual(expect.objectContaining({ nir: newNIR })) + ); + }); - await waitFor(() => - expect(screen.getByText('Le NIR doit être composé de 13 chiffres')).toBeInTheDocument() - ); - }); - it('transforme un NIR blanc en undefined', async () => { - const { onSubmit } = setup(); + it(`Rejette les valeurs incorrectes`, async () => { + setup(); + + await changeNir('Je ne suis pas un NIR'); + await submit(); + + await waitFor(() => + expect(screen.getByText('Le NIR doit être composé de 13 chiffres')).toBeInTheDocument() + ); + }); + it('transforme un NIR blanc en undefined', async () => { + const { onSubmit } = setup(); - await changeNir(' '); - await submit(); + await changeNir(' '); + await submit(); - await waitFor(() => - expect(onSubmit.mock.lastCall[1]).toEqual(expect.objectContaining({ nir: null })) - ); + await waitFor(() => + expect(onSubmit.mock.lastCall[1]).toEqual(expect.objectContaining({ nir: null })) + ); + }); }); }); -const setup = () => { +const setup = (params: { role: RoleEnum } = { role: RoleEnum.Manager }) => { const onSubmit = vi.fn(); const onCancel = vi.fn(); render(ProNotebookPersonalInfoUpdateView, { @@ -58,7 +70,7 @@ const setup = () => { rightAss: false, rightBonus: false, }, - role: RoleEnum.Professional, + role: params.role, onSubmit, onCancel, }); From c97079022f379d1032e2c2c4eb7e53f45d5b8aa8 Mon Sep 17 00:00:00 2001 From: Hadrien Mens-Pellen Date: Tue, 8 Aug 2023 17:14:56 +0200 Subject: [PATCH 3/5] fix: validation du NIR --- .../ProNotebookPersonalInfoUpdateView.test.ts | 37 +++++++++++-------- app/src/lib/validation.ts | 2 +- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts index ac065648a..742233d7d 100644 --- a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts +++ b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoUpdateView.test.ts @@ -21,27 +21,34 @@ describe('Mise à jour des données personelles', () => { }); }); describe('NIR', () => { - it(`Met à jour le NIR`, async () => { - const { onSubmit } = setup(); + describe(`Met à jour le NIR`, async () => { + it.each(['123452A890123', '1234567890123'])('%s', async (nir) => { + const { onSubmit } = setup(); - const newNIR = '1234567890123'; - await changeNir(newNIR); - await submit(); + await changeNir(nir); + await submit(); - await waitFor(() => - expect(onSubmit.mock.lastCall[1]).toEqual(expect.objectContaining({ nir: newNIR })) - ); + await waitFor(() => + expect(onSubmit.mock.lastCall[1]).toEqual(expect.objectContaining({ nir: nir })) + ); + }); }); - it(`Rejette les valeurs incorrectes`, async () => { - setup(); + describe('Rejette les valeurs incorrectes', () => { + it.each([ + ['Je ne suis pas un NIR', 'alphanumérique'], + ['123456789012', 'pas assez de caractères'], + ['12345678901234', 'trop de caractères'], + ])('%s est invalide car : %s', async (nir, _) => { + setup(); - await changeNir('Je ne suis pas un NIR'); - await submit(); + await changeNir(nir); + await submit(); - await waitFor(() => - expect(screen.getByText('Le NIR doit être composé de 13 chiffres')).toBeInTheDocument() - ); + await waitFor(() => + expect(screen.getByText('Le NIR doit être composé de 13 chiffres')).toBeInTheDocument() + ); + }); }); it('transforme un NIR blanc en undefined', async () => { const { onSubmit } = setup(); diff --git a/app/src/lib/validation.ts b/app/src/lib/validation.ts index e3d760eec..24a67f465 100644 --- a/app/src/lib/validation.ts +++ b/app/src/lib/validation.ts @@ -20,7 +20,7 @@ export function validatePhoneNumber(value: string): boolean { } export function validateNir(value: string): boolean { - return /^\d{13}/.test(value.trim()); + return /^[\d\w]{13}$/.test(value.trim()); } export function validateCodePostal(value: string): boolean { From 79f5ee3604c71a3572eefb5caacd1178a50e3974 Mon Sep 17 00:00:00 2001 From: Hadrien Mens-Pellen Date: Tue, 8 Aug 2023 17:18:42 +0200 Subject: [PATCH 4/5] fix: inverse les champs nir et date de naissance --- .../ProBeneficiaryUpdateFields.svelte | 20 +++++++++---------- .../ProNotebookPersonalInfoView.svelte | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/lib/ui/ProBeneficiaryUpdate/ProBeneficiaryUpdateFields.svelte b/app/src/lib/ui/ProBeneficiaryUpdate/ProBeneficiaryUpdateFields.svelte index a51b2aca5..0ebfef2df 100644 --- a/app/src/lib/ui/ProBeneficiaryUpdate/ProBeneficiaryUpdateFields.svelte +++ b/app/src/lib/ui/ProBeneficiaryUpdate/ProBeneficiaryUpdateFields.svelte @@ -43,16 +43,6 @@ title={titleForField('lastname')} /> - - + + diff --git a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoView.svelte b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoView.svelte index 34872def4..8eff0348c 100644 --- a/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoView.svelte +++ b/app/src/lib/ui/ProNotebookPersonalInfo/ProNotebookPersonalInfoView.svelte @@ -81,8 +81,8 @@ {displayFullName(beneficiary)} -
NIR: {beneficiary.nir ?? 'Inconnu'}
-
Né le {formatDateLocale(beneficiary.dateOfBirth)}
+
Né le {formatDateLocale(beneficiary.dateOfBirth)}
+
NIR: {beneficiary.nir ?? 'Inconnu'}

Informations personnelles

From ef0c480fee8073e92825d63299178fb2f5e71547 Mon Sep 17 00:00:00 2001 From: Hadrien Mens-Pellen Date: Wed, 9 Aug 2023 09:38:41 +0200 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20am=C3=A9liore=20les=20permissions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/carnet_de_bord/tables/public_beneficiary.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hasura/metadata/databases/carnet_de_bord/tables/public_beneficiary.yaml b/hasura/metadata/databases/carnet_de_bord/tables/public_beneficiary.yaml index a1bafb13d..fdab4e883 100644 --- a/hasura/metadata/databases/carnet_de_bord/tables/public_beneficiary.yaml +++ b/hasura/metadata/databases/carnet_de_bord/tables/public_beneficiary.yaml @@ -130,11 +130,12 @@ insert_permissions: - date_of_birth - deployment_id - email + - external_id - firstname - id - - external_id - lastname - mobile_number + - nir - pe_number - place_of_birth - postal_code