From 710e4aa5809baedb993ca10b68859981e4000893 Mon Sep 17 00:00:00 2001 From: hbalty Date: Mon, 15 Sep 2025 15:26:48 +0200 Subject: [PATCH 1/6] fix(portail-usagers): fix conversion date dans inWithinInterval --- .../components/home-usager/home-usager.component.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts index 94f4b7a3f3..4710297317 100644 --- a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts +++ b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts @@ -21,7 +21,7 @@ export class HomeUsagerComponent implements OnInit { private readonly usagerAuthService: UsagerAuthService, private readonly titleService: Title, private readonly router: Router, - private readonly structureInformationService: StructureInformationService, + private readonly structureInformationService: StructureInformationService ) { this.usagerProfile = null; this.titleService.setTitle("Mon DomiFa"); @@ -37,8 +37,8 @@ export class HomeUsagerComponent implements OnInit { } this.usagerProfile = apiResponse; - }, - ), + } + ) ); if (this.usagerProfile) { @@ -59,14 +59,14 @@ export class HomeUsagerComponent implements OnInit { if (info.endDate && info.startDate) { return isWithinInterval(today, { - start: info.startDate, - end: info.endDate, + start: new Date(info.startDate), + end: new Date(info.endDate), }); } return false; }); }, - }), + }) ); } } From 0890f3d71757526f4a1ecec3a9f49f73a397c096 Mon Sep 17 00:00:00 2001 From: hbalty Date: Mon, 15 Sep 2025 17:39:16 +0200 Subject: [PATCH 2/6] feat(portail-usager): adding frontend unit tests --- .../mocks/PORTAIL_USAGER_PROFILE.mock.ts | 66 +++++++++++++++++++ .../mocks/STRUCTURE_INFORMATION.mock.ts | 46 +++++++++++++ .../home-usager/home-usager.component.spec.ts | 52 ++++++++++++++- .../home-usager/home-usager.component.ts | 2 - 4 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 packages/portail-usagers/src/_tests/mocks/PORTAIL_USAGER_PROFILE.mock.ts create mode 100644 packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts diff --git a/packages/portail-usagers/src/_tests/mocks/PORTAIL_USAGER_PROFILE.mock.ts b/packages/portail-usagers/src/_tests/mocks/PORTAIL_USAGER_PROFILE.mock.ts new file mode 100644 index 0000000000..cca60e1e7f --- /dev/null +++ b/packages/portail-usagers/src/_tests/mocks/PORTAIL_USAGER_PROFILE.mock.ts @@ -0,0 +1,66 @@ +import { PortailUsagerProfile, PortailUsagerPublic } from "@domifa/common"; + +const usager: PortailUsagerPublic = { + uuid: "4dcdcddc-fad2-4827-aac5-0acf1df7b5bc", + ref: 5, + customRef: "5", + structureId: 1, + nom: "Derick", + prenom: "Inspecteur", + sexe: "homme", + dateNaissance: new Date("1911-05-24T00:00:00.000Z"), + villeNaissance: "Dreux", + email: null, + telephone: { + numero: "", + countryCode: "FR", + }, + contactByPhone: false, + datePremiereDom: new Date("2025-08-13T00:00:00.000Z"), + typeDom: "PREMIERE_DOM", + decision: { + uuid: "4328c843-e4bd-432d-b60b-b72a13ee3c9c", + statut: "VALIDE", + userId: 1, + dateFin: new Date("2026-08-12T00:00:00.000Z"), + userName: "Patrick Roméro", + dateDebut: new Date("2025-08-13T00:00:00.000Z"), + dateDecision: new Date("2025-08-13T14:29:36.624Z"), + }, + historique: [], + ayantsDroits: [], + lastInteraction: { + colisIn: 0, + enAttente: false, + courrierIn: 0, + recommandeIn: 0, + dateInteraction: new Date("2025-08-13T00:00:00.000Z"), + }, + etapeDemande: 5, + rdv: { + userId: 2, + dateRdv: new Date("2019-10-07T19:30:02.675Z"), + userName: "Juste Isabelle", + }, + options: { + transfert: { + nom: "", + dateDebut: null, + dateFin: null, + isExpired: false, + adresse: null, + actif: false, + }, + procurations: [], + portailUsagerEnabled: true, + npai: { + actif: false, + dateDebut: null, + }, + }, +}; + +export const unProfilUsager: PortailUsagerProfile = { + acceptTerms: new Date(), + usager: usager, +}; diff --git a/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts b/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts new file mode 100644 index 0000000000..b851f8a4f3 --- /dev/null +++ b/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts @@ -0,0 +1,46 @@ +import { StructureInformation } from "@domifa/common"; +import { add, sub } from "date-fns"; + +export const unMessageCourant: StructureInformation = { + uuid: "1", + createdAt: new Date("2025-08-13T15:28:52.311Z"), + updatedAt: new Date("2025-08-13T15:28:52.311Z"), + version: 1, + title: "Un message courant", + description: "Un message", + isTemporary: true, + startDate: sub(new Date(), { + days: 1, + }), + endDate: add(new Date(), { + days: 1, + }), + type: "general", + createdBy: { + userId: 1, + userName: "Patrick Roméro", + }, + structureId: 1, +}; + +export const unMessagePasse: StructureInformation = { + ...unMessageCourant, + title: "Un message passé", + startDate: sub(new Date(), { + days: 4, + }), + endDate: sub(new Date(), { + days: 1, + }), +}; + +export const unMessageFutur: StructureInformation = { + ...unMessageCourant, + title: "Un message futur", + startDate: add(new Date(), { + days: 2, + }), + endDate: add(new Date(), { + days: 4, + }), +}; diff --git a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.spec.ts b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.spec.ts index c6eaa0ad24..9b20f5dd66 100644 --- a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.spec.ts +++ b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.spec.ts @@ -1,11 +1,40 @@ import { provideHttpClientTesting } from "@angular/common/http/testing"; -import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { + ComponentFixture, + fakeAsync, + TestBed, + tick, +} from "@angular/core/testing"; import { HomeUsagerComponent } from "./home-usager.component"; import { UsagerAccountModule } from "../../usager-account.module"; import { RouterModule } from "@angular/router"; +import { StructureInformationService } from "../../services/structure-information.service"; +import { BehaviorSubject, of } from "rxjs"; +import { PortailUsagerProfile, StructureInformation } from "@domifa/common"; +import { + unMessageCourant, + unMessageFutur, + unMessagePasse, +} from "../../../../../_tests/mocks/STRUCTURE_INFORMATION.mock"; +import { unProfilUsager } from "../../../../../_tests/mocks/PORTAIL_USAGER_PROFILE.mock"; +import { UsagerAuthService } from "../../../usager-auth/services/usager-auth.service"; +import { NO_ERRORS_SCHEMA } from "@angular/core"; describe("HomeUsagerComponent", () => { + const messagesStructures: StructureInformation[] = [ + unMessageCourant, + unMessagePasse, + unMessageFutur, + ]; + const structureInformationService = { + getAllStructureInformation: jest.fn(() => of(messagesStructures)), + }; + const authService = { + currentUsagerSubject: new BehaviorSubject( + unProfilUsager + ), + }; let component: HomeUsagerComponent; let fixture: ComponentFixture; @@ -13,7 +42,18 @@ describe("HomeUsagerComponent", () => { await TestBed.configureTestingModule({ declarations: [HomeUsagerComponent], imports: [UsagerAccountModule, RouterModule.forRoot([])], - providers: [provideHttpClientTesting()], + providers: [ + provideHttpClientTesting(), + { + provide: StructureInformationService, + useValue: structureInformationService, + }, + { + provide: UsagerAuthService, + useValue: authService, + }, + ], + schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); }); @@ -26,4 +66,12 @@ describe("HomeUsagerComponent", () => { it("should create", () => { expect(component).toBeTruthy(); }); + + it("Filter out obsolete messages", fakeAsync(() => { + tick(); + expect(component.structureInformation.length).toEqual(1); + expect(component.structureInformation[0].title).toEqual( + "Un message courant" + ); + })); }); diff --git a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts index 4710297317..035e9843f9 100644 --- a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts +++ b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts @@ -35,7 +35,6 @@ export class HomeUsagerComponent implements OnInit { this.router.navigate(["/account/accept-terms"]); return; } - this.usagerProfile = apiResponse; } ) @@ -51,7 +50,6 @@ export class HomeUsagerComponent implements OnInit { this.structureInformationService.getAllStructureInformation().subscribe({ next: (structureInformation: StructureInformation[]) => { const today = new Date(); - this.structureInformation = structureInformation.filter((info) => { if (!info.isTemporary) { return true; From f9b556ad758be99919b495229691d1b8515dfb65 Mon Sep 17 00:00:00 2001 From: hbalty Date: Mon, 15 Sep 2025 18:44:39 +0200 Subject: [PATCH 3/6] fix(backend): move controller tests to the right location --- ...portail-usagers-profile.controller.spec.ts | 26 ------- .../structure-information.controller.spec.ts | 72 ++++++++++++++++--- 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/packages/backend/src/modules/portail-usagers/controllers/portail-usagers-profile/portail-usagers-profile.controller.spec.ts b/packages/backend/src/modules/portail-usagers/controllers/portail-usagers-profile/portail-usagers-profile.controller.spec.ts index e48851c4b3..eaf3faf55f 100644 --- a/packages/backend/src/modules/portail-usagers/controllers/portail-usagers-profile/portail-usagers-profile.controller.spec.ts +++ b/packages/backend/src/modules/portail-usagers/controllers/portail-usagers-profile/portail-usagers-profile.controller.spec.ts @@ -46,32 +46,6 @@ describe("PortailUsagersProfileController", () => { ); expect(controller).toBeDefined(); }); - - describe("GET /portail-usagers/profile/structure-information", () => { - it("should return structure information for authenticated usager", async () => { - const response = await supertest(context.app.getHttpServer()) - .get("/portail-usagers/profile/structure-information") - .set("Authorization", `Bearer ${authToken}`) - .expect(HttpStatus.OK); - - expect(response.body).toBeDefined(); - expect(Array.isArray(response.body)).toBe(true); - }); - - it("should return 401 for unauthenticated request", async () => { - await supertest(context.app.getHttpServer()) - .get("/portail-usagers/profile/structure-information") - .expect(HttpStatus.UNAUTHORIZED); - }); - - it("should return 401 for invalid token", async () => { - await supertest(context.app.getHttpServer()) - .get("/portail-usagers/profile/structure-information") - .set("Authorization", "Bearer invalid-token") - .expect(HttpStatus.UNAUTHORIZED); - }); - }); - describe("GET /portail-usagers/profile/me", () => { it("should return user profile for authenticated usager", async () => { const response = await supertest(context.app.getHttpServer()) diff --git a/packages/backend/src/modules/portail-usagers/controllers/structure-information/structure-information.controller.spec.ts b/packages/backend/src/modules/portail-usagers/controllers/structure-information/structure-information.controller.spec.ts index 0bf117d203..aded1fbddc 100644 --- a/packages/backend/src/modules/portail-usagers/controllers/structure-information/structure-information.controller.spec.ts +++ b/packages/backend/src/modules/portail-usagers/controllers/structure-information/structure-information.controller.spec.ts @@ -1,20 +1,74 @@ -import { Test, TestingModule } from "@nestjs/testing"; +import { HttpStatus } from "@nestjs/common"; +import supertest from "supertest"; + +import { AuthModule } from "../../../../auth/auth.module"; +import { AppTestContext, AppTestHelper } from "../../../../util/test"; +import { TESTS_USERS_USAGER } from "../../../../_tests"; +import { PortailUsagersModule } from "../../portail-usagers.module"; import { StructureInformationController } from "./structure-information.controller"; +const PERMANENT_PASS_USER = TESTS_USERS_USAGER.ALL.find( + (x) => x.login === "LNQIFFBK" +); + describe("StructureInformationController", () => { - let controller: StructureInformationController; + let context: AppTestContext; + let authToken: string; + + beforeAll(async () => { + context = await AppTestHelper.bootstrapTestApp( + { + controllers: [], + imports: [PortailUsagersModule, AuthModule], + providers: [], + }, + { initApp: true } + ); - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [StructureInformationController], - }).compile(); + // Login to get auth token for authenticated requests + const loginResponse = await supertest(context.app.getHttpServer()) + .post("/portail-usagers/auth/login") + .send({ + login: PERMANENT_PASS_USER.login, + password: PERMANENT_PASS_USER.password, + }); - controller = module.get( + authToken = loginResponse.body.token; + }); + + afterAll(async () => { + await AppTestHelper.tearDownTestApp(context); + }); + + it("should be defined", async () => { + const controller = context.module.get( StructureInformationController ); + expect(controller).toBeDefined(); }); - it("should be defined", () => { - expect(controller).toBeDefined(); + describe("GET /portail-usagers/profile/structure-information", () => { + it("should return structure information for authenticated usager", async () => { + const response = await supertest(context.app.getHttpServer()) + .get("/portail-usagers/profile/structure-information") + .set("Authorization", `Bearer ${authToken}`) + .expect(HttpStatus.OK); + + expect(response.body).toBeDefined(); + expect(Array.isArray(response.body)).toBe(true); + }); + + it("should return 401 for unauthenticated request", async () => { + await supertest(context.app.getHttpServer()) + .get("/portail-usagers/profile/structure-information") + .expect(HttpStatus.UNAUTHORIZED); + }); + + it("should return 401 for invalid token", async () => { + await supertest(context.app.getHttpServer()) + .get("/portail-usagers/profile/structure-information") + .set("Authorization", "Bearer invalid-token") + .expect(HttpStatus.UNAUTHORIZED); + }); }); }); From 88c75d447e0ca361fdb66c9f3723fd80580e05eb Mon Sep 17 00:00:00 2001 From: hbalty Date: Tue, 16 Sep 2025 11:27:52 +0200 Subject: [PATCH 4/6] feat(portail-usager): testing edge cases where server data is different --- .../classes/StructureInformation.class.ts | 44 +++++++++++++++++++ .../structure-information/classes/index.ts | 1 + .../common/src/structure-information/index.ts | 1 + .../mocks/STRUCTURE_INFORMATION.mock.ts | 22 ++++++++++ .../home-usager/home-usager.component.spec.ts | 9 +++- .../home-usager/home-usager.component.ts | 27 +++++------- 6 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 packages/common/src/structure-information/classes/StructureInformation.class.ts create mode 100644 packages/common/src/structure-information/classes/index.ts diff --git a/packages/common/src/structure-information/classes/StructureInformation.class.ts b/packages/common/src/structure-information/classes/StructureInformation.class.ts new file mode 100644 index 0000000000..414417047d --- /dev/null +++ b/packages/common/src/structure-information/classes/StructureInformation.class.ts @@ -0,0 +1,44 @@ +import { StructureInformation } from "./../interfaces/StructureInformation.interface"; +import { createDate } from "../../_core"; +import { UserStructureResume } from "../../users"; +import { isWithinInterval } from "date-fns"; + +export class StructureInformationMessage implements StructureInformation { + public title: string; + public description: string; + public startDate: Date; + public endDate: Date | null; + public type: "closing" | "opening-hours" | "general" | "other"; + public createdBy: UserStructureResume; + public structureId: number; + public isTemporary: boolean; + public isExpired: boolean; + public uuid?: string | undefined; + public createdAt?: Date; + public updatedAt?: Date; + public version?: number; + constructor(options: StructureInformation) { + this.title = options.title; + this.description = options.description; + this.startDate = options.startDate; + this.endDate = options.endDate; + this.type = options.type; + this.createdAt = createDate(options.createdAt) ?? undefined; + this.updatedAt = createDate(options.updatedAt) ?? undefined; + this.createdBy = options.createdBy; + this.structureId = options.structureId; + this.isTemporary = options.isTemporary; + this.isExpired = this.isMessageExpired(); + this.uuid = options.uuid; + this.version = options.version; + } + + public isMessageExpired(): boolean { + if (!this.endDate || !this.startDate || !this.isTemporary) return false; + const today = new Date(); + return !isWithinInterval(today, { + start: new Date(this.startDate), + end: new Date(this.endDate), + }); + } +} diff --git a/packages/common/src/structure-information/classes/index.ts b/packages/common/src/structure-information/classes/index.ts new file mode 100644 index 0000000000..ceaf273710 --- /dev/null +++ b/packages/common/src/structure-information/classes/index.ts @@ -0,0 +1 @@ +export * from "./StructureInformation.class"; diff --git a/packages/common/src/structure-information/index.ts b/packages/common/src/structure-information/index.ts index b9723b0efe..ab1e34b623 100644 --- a/packages/common/src/structure-information/index.ts +++ b/packages/common/src/structure-information/index.ts @@ -2,3 +2,4 @@ export * from "./constants"; export * from "./interfaces"; export * from "./types"; +export * from "./classes"; diff --git a/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts b/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts index b851f8a4f3..0193ec44f2 100644 --- a/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts +++ b/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts @@ -44,3 +44,25 @@ export const unMessageFutur: StructureInformation = { days: 4, }), }; + +export const unMessageFuturAvecIsoDate = { + ...unMessageCourant, + title: "Un message futur", + startDate: add(new Date(), { + days: 2, + }).toISOString(), + endDate: add(new Date(), { + days: 4, + }).toISOString(), +}; + +export const unMessageAvecIsoDate = { + ...unMessageCourant, + title: "Un message courant avec text date", + startDate: sub(new Date(), { + days: 4, + }).toISOString(), + endDate: add(new Date(), { + days: 1, + }).toISOString(), +}; diff --git a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.spec.ts b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.spec.ts index 9b20f5dd66..b7810c49e6 100644 --- a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.spec.ts +++ b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.spec.ts @@ -13,8 +13,10 @@ import { StructureInformationService } from "../../services/structure-informatio import { BehaviorSubject, of } from "rxjs"; import { PortailUsagerProfile, StructureInformation } from "@domifa/common"; import { + unMessageAvecIsoDate, unMessageCourant, unMessageFutur, + unMessageFuturAvecIsoDate, unMessagePasse, } from "../../../../../_tests/mocks/STRUCTURE_INFORMATION.mock"; import { unProfilUsager } from "../../../../../_tests/mocks/PORTAIL_USAGER_PROFILE.mock"; @@ -26,6 +28,8 @@ describe("HomeUsagerComponent", () => { unMessageCourant, unMessagePasse, unMessageFutur, + unMessageAvecIsoDate as unknown as StructureInformation, // un message avec date string + unMessageFuturAvecIsoDate as unknown as StructureInformation, ]; const structureInformationService = { getAllStructureInformation: jest.fn(() => of(messagesStructures)), @@ -69,9 +73,12 @@ describe("HomeUsagerComponent", () => { it("Filter out obsolete messages", fakeAsync(() => { tick(); - expect(component.structureInformation.length).toEqual(1); + expect(component.structureInformation.length).toEqual(2); expect(component.structureInformation[0].title).toEqual( "Un message courant" ); + expect(component.structureInformation[1].title).toEqual( + "Un message courant avec text date" + ); })); }); diff --git a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts index 035e9843f9..a695945fe7 100644 --- a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts +++ b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts @@ -1,10 +1,13 @@ import { Component, OnInit } from "@angular/core"; import { Title } from "@angular/platform-browser"; -import { PortailUsagerProfile, StructureInformation } from "@domifa/common"; +import { + PortailUsagerProfile, + StructureInformation, + StructureInformationMessage, +} from "@domifa/common"; import { UsagerAuthService } from "../../../usager-auth/services/usager-auth.service"; import { Router } from "@angular/router"; import { Subscription } from "rxjs"; -import { isWithinInterval } from "date-fns"; import { StructureInformationService } from "../../services/structure-information.service"; @Component({ @@ -49,20 +52,12 @@ export class HomeUsagerComponent implements OnInit { this.subscription.add( this.structureInformationService.getAllStructureInformation().subscribe({ next: (structureInformation: StructureInformation[]) => { - const today = new Date(); - this.structureInformation = structureInformation.filter((info) => { - if (!info.isTemporary) { - return true; - } - - if (info.endDate && info.startDate) { - return isWithinInterval(today, { - start: new Date(info.startDate), - end: new Date(info.endDate), - }); - } - return false; - }); + this.structureInformation = structureInformation + .map( + (_structureInfo) => + new StructureInformationMessage(_structureInfo) + ) + .filter((info) => !info.isExpired); }, }) ); From 1e2b916e3a5211c3968da51d753cca31b984514f Mon Sep 17 00:00:00 2001 From: hbalty Date: Wed, 17 Sep 2025 12:08:10 +0200 Subject: [PATCH 5/6] fix(reviews): refactoring structureInformation class --- .../classes/StructureInformation.class.ts | 53 ++++++++++--------- .../common/src/structure-information/index.ts | 1 - .../StructureInformation.interface.ts | 13 ----- .../structure-information/interfaces/index.ts | 2 - packages/common/src/structure/types/index.ts | 1 - .../mocks/STRUCTURE_INFORMATION.mock.ts | 5 ++ .../home-usager/home-usager.component.ts | 15 ++---- 7 files changed, 37 insertions(+), 53 deletions(-) delete mode 100644 packages/common/src/structure-information/interfaces/StructureInformation.interface.ts delete mode 100644 packages/common/src/structure-information/interfaces/index.ts diff --git a/packages/common/src/structure-information/classes/StructureInformation.class.ts b/packages/common/src/structure-information/classes/StructureInformation.class.ts index 414417047d..6a4f893c06 100644 --- a/packages/common/src/structure-information/classes/StructureInformation.class.ts +++ b/packages/common/src/structure-information/classes/StructureInformation.class.ts @@ -1,44 +1,47 @@ -import { StructureInformation } from "./../interfaces/StructureInformation.interface"; +import { AppEntity } from "./../../_core/interfaces/AppEntity.interface"; import { createDate } from "../../_core"; import { UserStructureResume } from "../../users"; import { isWithinInterval } from "date-fns"; -export class StructureInformationMessage implements StructureInformation { +export class StructureInformation implements AppEntity { public title: string; public description: string; - public startDate: Date; - public endDate: Date | null; + public startDate?: Date | null; + public endDate?: Date | null; public type: "closing" | "opening-hours" | "general" | "other"; - public createdBy: UserStructureResume; - public structureId: number; - public isTemporary: boolean; - public isExpired: boolean; + public createdBy?: UserStructureResume; + public structureId?: number; + public isTemporary?: boolean; + public isExpired?: boolean; public uuid?: string | undefined; public createdAt?: Date; public updatedAt?: Date; public version?: number; - constructor(options: StructureInformation) { - this.title = options.title; - this.description = options.description; - this.startDate = options.startDate; - this.endDate = options.endDate; - this.type = options.type; - this.createdAt = createDate(options.createdAt) ?? undefined; - this.updatedAt = createDate(options.updatedAt) ?? undefined; + constructor(options: Partial) { + this.title = options.title || ""; + this.description = options.description || ""; + this.startDate = options.startDate || null; + this.endDate = options.endDate || null; + this.type = options.type || "other"; + this.createdAt = createDate(options.createdAt) ?? new Date(); + this.updatedAt = createDate(options.updatedAt) ?? new Date(); this.createdBy = options.createdBy; this.structureId = options.structureId; this.isTemporary = options.isTemporary; - this.isExpired = this.isMessageExpired(); + this.isExpired = isMessageExpired(options); this.uuid = options.uuid; this.version = options.version; } +} - public isMessageExpired(): boolean { - if (!this.endDate || !this.startDate || !this.isTemporary) return false; - const today = new Date(); - return !isWithinInterval(today, { - start: new Date(this.startDate), - end: new Date(this.endDate), - }); - } +export function isMessageExpired( + message: Partial +): boolean { + if (!message.endDate || !message.startDate || !message.isTemporary) + return false; + const today = new Date(); + return !isWithinInterval(today, { + start: new Date(message.startDate), + end: new Date(message.endDate), + }); } diff --git a/packages/common/src/structure-information/index.ts b/packages/common/src/structure-information/index.ts index ab1e34b623..dbb1472601 100644 --- a/packages/common/src/structure-information/index.ts +++ b/packages/common/src/structure-information/index.ts @@ -1,5 +1,4 @@ // @index('./*', f => `export * from '${f.path}'`) export * from "./constants"; -export * from "./interfaces"; export * from "./types"; export * from "./classes"; diff --git a/packages/common/src/structure-information/interfaces/StructureInformation.interface.ts b/packages/common/src/structure-information/interfaces/StructureInformation.interface.ts deleted file mode 100644 index 3019ee920e..0000000000 --- a/packages/common/src/structure-information/interfaces/StructureInformation.interface.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { AppEntity } from "../../_core"; -import { UserStructureResume } from "../../users/user-structure"; - -export interface StructureInformation extends AppEntity { - title: string; - description: string; - startDate: Date; - endDate: Date | null; - type: "closing" | "opening-hours" | "general" | "other"; - createdBy: UserStructureResume; - structureId: number; - isTemporary: boolean; -} diff --git a/packages/common/src/structure-information/interfaces/index.ts b/packages/common/src/structure-information/interfaces/index.ts deleted file mode 100644 index c9315109bc..0000000000 --- a/packages/common/src/structure-information/interfaces/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -// @index('./*', f => `export * from '${f.path}'`) -export * from "./StructureInformation.interface"; diff --git a/packages/common/src/structure/types/index.ts b/packages/common/src/structure/types/index.ts index cb1b7b5123..966a88af04 100644 --- a/packages/common/src/structure/types/index.ts +++ b/packages/common/src/structure/types/index.ts @@ -1,5 +1,4 @@ // @index('./*', f => `export * from '${f.path}'`) export * from "./StructureCommon.type"; -export * from "../../structure-information/types/StructureInformationType.type"; export * from "./StructureLight.type"; export * from "./StructureType.type"; diff --git a/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts b/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts index 0193ec44f2..50fa6830d6 100644 --- a/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts +++ b/packages/portail-usagers/src/_tests/mocks/STRUCTURE_INFORMATION.mock.ts @@ -21,6 +21,7 @@ export const unMessageCourant: StructureInformation = { userName: "Patrick Roméro", }, structureId: 1, + isExpired: false, }; export const unMessagePasse: StructureInformation = { @@ -32,6 +33,7 @@ export const unMessagePasse: StructureInformation = { endDate: sub(new Date(), { days: 1, }), + isExpired: true, }; export const unMessageFutur: StructureInformation = { @@ -43,6 +45,7 @@ export const unMessageFutur: StructureInformation = { endDate: add(new Date(), { days: 4, }), + isExpired: true, }; export const unMessageFuturAvecIsoDate = { @@ -54,6 +57,7 @@ export const unMessageFuturAvecIsoDate = { endDate: add(new Date(), { days: 4, }).toISOString(), + isExpired: true, }; export const unMessageAvecIsoDate = { @@ -65,4 +69,5 @@ export const unMessageAvecIsoDate = { endDate: add(new Date(), { days: 1, }).toISOString(), + isExpired: false, }; diff --git a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts index a695945fe7..ccd112cd48 100644 --- a/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts +++ b/packages/portail-usagers/src/app/modules/usager-account/components/home-usager/home-usager.component.ts @@ -1,10 +1,6 @@ import { Component, OnInit } from "@angular/core"; import { Title } from "@angular/platform-browser"; -import { - PortailUsagerProfile, - StructureInformation, - StructureInformationMessage, -} from "@domifa/common"; +import { PortailUsagerProfile, StructureInformation } from "@domifa/common"; import { UsagerAuthService } from "../../../usager-auth/services/usager-auth.service"; import { Router } from "@angular/router"; import { Subscription } from "rxjs"; @@ -52,12 +48,9 @@ export class HomeUsagerComponent implements OnInit { this.subscription.add( this.structureInformationService.getAllStructureInformation().subscribe({ next: (structureInformation: StructureInformation[]) => { - this.structureInformation = structureInformation - .map( - (_structureInfo) => - new StructureInformationMessage(_structureInfo) - ) - .filter((info) => !info.isExpired); + this.structureInformation = structureInformation.filter( + (info) => !info.isExpired + ); }, }) ); From ff9fb7047d7e8246b3ee8933be0917b40b3a2bee Mon Sep 17 00:00:00 2001 From: hbalty Date: Wed, 17 Sep 2025 12:42:11 +0200 Subject: [PATCH 6/6] fix(backend): optional chaining --- .../classes/StructureInformation.class.ts | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/common/src/structure-information/classes/StructureInformation.class.ts b/packages/common/src/structure-information/classes/StructureInformation.class.ts index 6a4f893c06..3766c67a47 100644 --- a/packages/common/src/structure-information/classes/StructureInformation.class.ts +++ b/packages/common/src/structure-information/classes/StructureInformation.class.ts @@ -17,26 +17,27 @@ export class StructureInformation implements AppEntity { public createdAt?: Date; public updatedAt?: Date; public version?: number; - constructor(options: Partial) { - this.title = options.title || ""; - this.description = options.description || ""; - this.startDate = options.startDate || null; - this.endDate = options.endDate || null; - this.type = options.type || "other"; - this.createdAt = createDate(options.createdAt) ?? new Date(); - this.updatedAt = createDate(options.updatedAt) ?? new Date(); - this.createdBy = options.createdBy; - this.structureId = options.structureId; - this.isTemporary = options.isTemporary; + constructor(options?: Partial) { + this.title = options?.title || ""; + this.description = options?.description || ""; + this.startDate = options?.startDate || null; + this.endDate = options?.endDate || null; + this.type = options?.type || "other"; + this.createdAt = createDate(options?.createdAt) ?? new Date(); + this.updatedAt = createDate(options?.updatedAt) ?? new Date(); + this.createdBy = options?.createdBy; + this.structureId = options?.structureId; + this.isTemporary = options?.isTemporary; this.isExpired = isMessageExpired(options); - this.uuid = options.uuid; - this.version = options.version; + this.uuid = options?.uuid; + this.version = options?.version; } } export function isMessageExpired( - message: Partial -): boolean { + message?: Partial +): boolean | undefined { + if (!message) return undefined; if (!message.endDate || !message.startDate || !message.isTemporary) return false; const today = new Date();