diff --git a/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityRepository.service.ts b/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityRepository.service.ts index 36b7dd26a9..02653c9824 100644 --- a/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityRepository.service.ts +++ b/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityRepository.service.ts @@ -17,7 +17,7 @@ export const userStructureSecurityRepository = myDataSource "uuid" | "userId" | "temporaryTokens" | "eventsHistory" > > { - return this.createQueryBuilder("user_structure_security") + return await this.createQueryBuilder("user_structure_security") .where(`"temporaryTokens"->>'token' = :tokenValue`, { tokenValue, }) @@ -51,7 +51,7 @@ export const userStructureSecurityRepository = myDataSource clearAllEvents, }); - return this.update( + return await this.update( { userId }, attributes ? { diff --git a/packages/backend/src/modules/portail-admin/controllers/admin-structures/admin-structures.controller.ts b/packages/backend/src/modules/portail-admin/controllers/admin-structures/admin-structures.controller.ts index ed604f4d78..083638d09d 100644 --- a/packages/backend/src/modules/portail-admin/controllers/admin-structures/admin-structures.controller.ts +++ b/packages/backend/src/modules/portail-admin/controllers/admin-structures/admin-structures.controller.ts @@ -146,6 +146,7 @@ export class AdminStructuresController { user_structure.prenom, user_structure.email, user_structure.role, + user_structure.verified, user_structure."lastLogin", user_structure."createdAt", user_structure.uuid, diff --git a/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/services/usagersSearchStringFilter.service.ts b/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/services/usagersSearchStringFilter.service.ts index 6c9c886c0f..f934033e91 100644 --- a/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/services/usagersSearchStringFilter.service.ts +++ b/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/services/usagersSearchStringFilter.service.ts @@ -1,9 +1,15 @@ import { UsagersFilterCriteria } from "../UsagersFilterCriteria"; -import { format } from "date-fns"; +import { format, isValid, parseISO } from "date-fns"; import { UsagerLight } from "../../../../../../_common/model"; import { UsagerProcuration } from "../../../../usager-shared/interfaces/UsagerProcuration.interface"; import { UsagerAyantDroit } from "@domifa/common"; +const validateBirthDate = (date?: Date | string): string | undefined => { + if (!date) return undefined; + const parsedDate = typeof date === "string" ? parseISO(date) : date; + return !isValid(parsedDate) ? undefined : format(parsedDate, "dd/MM/yyyy"); +}; + export const getAttributes = ( usager: UsagerLight, { @@ -12,21 +18,16 @@ export const getAttributes = ( ) => { let attributes = []; if (searchStringField === "DATE_NAISSANCE") { - const dateNaissance = - typeof usager.dateNaissance === "string" - ? new Date(usager.dateNaissance) - : null; - - attributes = dateNaissance ? [format(dateNaissance, "dd/MM/yyyy")] : []; - - usager.ayantsDroits.forEach((ad: UsagerAyantDroit) => { - const dateNaissanceAd = - typeof ad.dateNaissance === "string" - ? new Date(ad.dateNaissance) - : null; - if (dateNaissanceAd) { - attributes.push(format(dateNaissanceAd, "dd/MM/yyyy")); - } + const attributes: string[] = []; + + if (usager.dateNaissance) { + const formattedDate = validateBirthDate(usager.dateNaissance); + if (formattedDate) attributes.push(formattedDate); + } + + usager.ayantsDroits.forEach((ad) => { + const formattedDate = validateBirthDate(ad.dateNaissance); + if (formattedDate) attributes.push(formattedDate); }); return attributes; diff --git a/packages/frontend/src/app/shared/store/setUsagerInformation.ts b/packages/frontend/src/app/shared/store/setUsagerInformation.ts index c5e5714228..69b114dc96 100644 --- a/packages/frontend/src/app/shared/store/setUsagerInformation.ts +++ b/packages/frontend/src/app/shared/store/setUsagerInformation.ts @@ -32,6 +32,7 @@ export const setUsagerInformation = (usager: Usager): any => { historique: [], options: new Options(usager.options), rdv: null, + dateNaissance: new Date(usager?.dateNaissance), entretien: null, }; }; diff --git a/packages/portail-admins/package.json b/packages/portail-admins/package.json index db4f684404..131341ef5f 100644 --- a/packages/portail-admins/package.json +++ b/packages/portail-admins/package.json @@ -41,6 +41,7 @@ "class-validator": "^0.14.1", "date-fns": "^2.30.0", "file-saver": "^2.0.5", + "google-libphonenumber": "^3.2.40", "ngx-matomo-client": "^5.0.4", "redux": "^4.2.1", "rimraf": "^5.0.10", diff --git a/packages/portail-admins/src/app/app.module.ts b/packages/portail-admins/src/app/app.module.ts index 4e3d447273..eef4b06ff8 100644 --- a/packages/portail-admins/src/app/app.module.ts +++ b/packages/portail-admins/src/app/app.module.ts @@ -2,6 +2,7 @@ import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http"; import { CUSTOM_ELEMENTS_SCHEMA, ErrorHandler, + LOCALE_ID, NgModule, NO_ERRORS_SCHEMA, } from "@angular/core"; @@ -54,6 +55,7 @@ registerLocaleData(localeFr, "fr"); MATOMO_INJECTORS, ], providers: [ + { provide: LOCALE_ID, useValue: "fr" }, { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true }, { multi: true, diff --git a/packages/portail-admins/src/app/modules/structure/components/structure-info/structure-info.component.html b/packages/portail-admins/src/app/modules/structure/components/structure-info/structure-info.component.html index c3a91ef029..595c7aec46 100644 --- a/packages/portail-admins/src/app/modules/structure/components/structure-info/structure-info.component.html +++ b/packages/portail-admins/src/app/modules/structure/components/structure-info/structure-info.component.html @@ -1,44 +1,55 @@
-
-
-
-

Informations

-
+
+

Informations

+
-
-

Nom : {{ structure.nom }}

-

- Type de structure : {{ structure.structureType }} -

-

Département : {{ structure.departement }}

+

+ Nom + {{ structure.nom }} +

+

+ Type de structure + {{ structure.structureType }} +

+

+ Département + {{ structure.departement }} +

-

- Adresse : -

-
    -
  • {{ structure.adresse }}
  • -
  • {{ structure.codePostal }}, {{ structure.ville }}
  • -
-

-

- Coordonnées de la structure: -

-
    -
  • {{ structure.email }}
  • -
  • {{ structure.telephone }}
  • -
+ +

+ Adresse + {{ structure.adresse }} +

+

+ Ville + {{ structure.codePostal }}, {{ structure.ville }} +

-

- Responsable de la structure: -

-
    -
  • - {{ structure?.responsable?.nom }} - {{ structure?.responsable?.prenom }} -
  • -
  • {{ structure?.responsable?.fonction }}
  • -
-
-
-
+ +

+ Email + {{ structure.email }} +

+

+ Téléphone + {{ + structure.telephone | formatInternationalPhoneNumber + }} +

+ + +

+ Nom du responsable + {{ structure?.responsable?.nom }} + {{ structure?.responsable?.prenom }} +

+

+ Fonction du responsable + {{ structure?.responsable?.fonction }} +

diff --git a/packages/portail-admins/src/app/modules/structure/components/structure-info/structure-info.component.spec.ts b/packages/portail-admins/src/app/modules/structure/components/structure-info/structure-info.component.spec.ts index 779822f503..0852363334 100644 --- a/packages/portail-admins/src/app/modules/structure/components/structure-info/structure-info.component.spec.ts +++ b/packages/portail-admins/src/app/modules/structure/components/structure-info/structure-info.component.spec.ts @@ -8,6 +8,7 @@ import { TableHeadSortComponent } from "../../../shared/components/table-head-so import { SortArrayPipe } from "../../../shared/pipes/sort-array.pipe"; import { StructureService } from "../../services/structure.service"; import { STRUCTURE_MOCK } from "../../STRUCTURE_MOCK.const"; +import { FormatInternationalPhoneNumberPipe } from "../../../../shared/utils/formatInternationalPhoneNumber.pipe"; describe("StructureInfoComponent", () => { let component: StructureInfoComponent; @@ -22,6 +23,7 @@ describe("StructureInfoComponent", () => { SortArrayPipe, HttpClientTestingModule, RouterModule.forRoot([]), + FormatInternationalPhoneNumberPipe, ], providers: [StructureService], }).compileComponents(); diff --git a/packages/portail-admins/src/app/modules/structure/components/users/users.component.html b/packages/portail-admins/src/app/modules/structure/components/users/users.component.html index 3cae98ed78..272032393a 100644 --- a/packages/portail-admins/src/app/modules/structure/components/users/users.component.html +++ b/packages/portail-admins/src/app/modules/structure/components/users/users.component.html @@ -35,13 +35,22 @@

Utilisateurs enregistrés: {{ users.length }} utilisateurs

+ + + + Utilisateurs enregistrés: {{ users.length }} utilisateurs {{ user.createdAt | date : "d MMMM y" }}

✅ Compte actif

-

- ❌ Inactif depuis plus de 2 mois
Dernière connexion le - {{ user.lastLogin | date : "d MMMM y" }} -

-

+

❌ Compte non vérifié

+ + + +

+ {{ user.lastLogin | date : "dd/MM/yyyy" }} + +
❌ Inactif depuis plus de 2 mois
+
+

+
+

❌ Compte jamais utilisé

diff --git a/packages/portail-admins/src/app/modules/structure/components/users/users.component.ts b/packages/portail-admins/src/app/modules/structure/components/users/users.component.ts index 28b3b7c97e..bad7fab6a4 100644 --- a/packages/portail-admins/src/app/modules/structure/components/users/users.component.ts +++ b/packages/portail-admins/src/app/modules/structure/components/users/users.component.ts @@ -6,6 +6,7 @@ import { UserStructureWithSecurity, } from "../../services/structure.service"; import { environment } from "../../../../../environments/environment"; +import { subMonths } from "date-fns"; @Component({ selector: "app-users", @@ -16,6 +17,7 @@ export class UsersComponent implements OnInit { public users: UserStructureWithSecurity[] = []; public sortValue: SortValues = "asc"; public currentKey = "id"; + public twoMonthsAgo = subMonths(new Date(), 2); public readonly frontendUrl = environment.frontendUrl; public readonly USER_ROLES_LABELS: { [key in UserStructureRole]: string } = { @@ -34,7 +36,12 @@ export class UsersComponent implements OnInit { ngOnInit(): void { this.subscription.add( this.structureService.getUsers(this.structure.id).subscribe((users) => { - this.users = users; + this.users = users.map((user) => { + if (user?.lastLogin) { + user.lastLogin = new Date(user.lastLogin); + } + return user; + }); }) ); } diff --git a/packages/portail-admins/src/app/modules/structure/structure.module.ts b/packages/portail-admins/src/app/modules/structure/structure.module.ts index b83a678a95..f4daf7c476 100644 --- a/packages/portail-admins/src/app/modules/structure/structure.module.ts +++ b/packages/portail-admins/src/app/modules/structure/structure.module.ts @@ -9,6 +9,7 @@ import { StructureRoutingModule } from "./structure-routing.module"; import { UsersComponent } from "./components/users/users.component"; import { SortArrayPipe } from "../shared/pipes/sort-array.pipe"; import { StructureInfoComponent } from "./components/structure-info/structure-info.component"; +import { FormatInternationalPhoneNumberPipe } from "../../shared/utils/formatInternationalPhoneNumber.pipe"; @NgModule({ declarations: [ @@ -20,6 +21,7 @@ import { StructureInfoComponent } from "./components/structure-info/structure-in imports: [ CommonModule, NgbModule, + FormatInternationalPhoneNumberPipe, SharedModule, FontAwesomeModule, TableHeadSortComponent, diff --git a/packages/portail-admins/src/app/shared/utils/formatInternationalPhoneNumber.pipe.ts b/packages/portail-admins/src/app/shared/utils/formatInternationalPhoneNumber.pipe.ts new file mode 100644 index 0000000000..74a1cb6340 --- /dev/null +++ b/packages/portail-admins/src/app/shared/utils/formatInternationalPhoneNumber.pipe.ts @@ -0,0 +1,34 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { Telephone } from "@domifa/common"; +import { PhoneNumberFormat, PhoneNumberUtil } from "google-libphonenumber"; + +@Pipe({ name: "formatInternationalPhoneNumber", standalone: true }) +export class FormatInternationalPhoneNumberPipe implements PipeTransform { + public transform(telephone: Telephone): string { + const phoneUtil = PhoneNumberUtil.getInstance(); + if (!telephone) { + return "Non renseigné"; + } + + if ( + telephone?.numero === "" || + !telephone?.numero || + !telephone?.countryCode + ) { + return "Non renseigné"; + } + + try { + const numero = phoneUtil.parse( + telephone.numero, + telephone.countryCode.toLowerCase() + ); + if (!phoneUtil.isValidNumber(numero) || !numero) { + return "Non renseigné"; + } + return phoneUtil.format(numero, PhoneNumberFormat.INTERNATIONAL); + } catch (error) { + return "Numéro introuvable"; + } + } +} diff --git a/yarn.lock b/yarn.lock index 543adcedd8..8cd24985c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4067,6 +4067,7 @@ __metadata: eslint-plugin-no-lookahead-lookbehind-regexp: "npm:^0.3.0" eslint-plugin-prettier: "npm:^5.2.1" file-saver: "npm:^2.0.5" + google-libphonenumber: "npm:^3.2.40" jest: "npm:^29.7.0" jest-preset-angular: "npm:^14.1.1" lint-staged: "npm:^15.2.10" @@ -16652,6 +16653,13 @@ __metadata: languageName: node linkType: hard +"google-libphonenumber@npm:^3.2.40": + version: 3.2.40 + resolution: "google-libphonenumber@npm:3.2.40" + checksum: 10/787627acb2fd3467dcf294e17184ece3b67aa3250e361e12fbbab9c0b6aaf0e5b75e97943ba152f2321581aadceb4180f41299ec56461543fd6f3021f54e6363 + languageName: node + linkType: hard + "gopd@npm:^1.0.1": version: 1.0.1 resolution: "gopd@npm:1.0.1"