diff --git a/back/src/domains/establishment/entities/EstablishmentAggregate.ts b/back/src/domains/establishment/entities/EstablishmentAggregate.ts index 311608b259..fab95825d8 100644 --- a/back/src/domains/establishment/entities/EstablishmentAggregate.ts +++ b/back/src/domains/establishment/entities/EstablishmentAggregate.ts @@ -1,4 +1,4 @@ -import { Phone, UserId } from "shared"; +import { EstablishmentRole, Phone, UserId } from "shared"; import { EstablishmentEntity } from "./EstablishmentEntity"; import { OfferEntity } from "./OfferEntity"; @@ -12,7 +12,6 @@ export type WithEstablishmentAggregate = { establishmentAggregate: EstablishmentAggregate; }; -type EstablishmentRole = "establishment-admin" | "establishment-contact"; type GenericEstablishmentUserRight = { userId: UserId; role: Role; diff --git a/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.ts b/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.ts index d394cd8fd6..8e04a3258e 100644 --- a/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.ts +++ b/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.ts @@ -5,7 +5,7 @@ import { EstablishmentDashboards, InclusionConnectedUser, WithDashboards, - WithEstablismentsSiretAndName, + WithEstablishmentData, WithOptionalUserId, agencyRoleIsNotToReview, errors, @@ -85,20 +85,32 @@ export class GetInclusionConnectedUser extends TransactionalUseCase< async #withEstablishments( uow: UnitOfWork, user: InclusionConnectedUser, - ): Promise<{ establishments?: WithEstablismentsSiretAndName[] }> { + ): Promise<{ establishments?: WithEstablishmentData[] }> { const establishmentAggregates = await uow.establishmentAggregateRepository.getEstablishmentAggregatesByFilters( { userId: user.id, }, ); - - const establishments = establishmentAggregates.map(({ establishment }) => ({ - siret: establishment.siret, - businessName: establishment.customizedName - ? establishment.customizedName - : establishment.name, - })); + const establishments = establishmentAggregates.map( + ({ establishment, userRights }) => { + const userRight = userRights.find( + (userRight) => userRight.userId === user.id, + ); + if (!userRight) { + throw errors.establishment.noUserRights({ + siret: establishment.siret, + }); + } + return { + siret: establishment.siret, + businessName: establishment.customizedName + ? establishment.customizedName + : establishment.name, + role: userRight.role, + }; + }, + ); return establishments.length ? { establishments } : {}; } diff --git a/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.unit.test.ts b/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.unit.test.ts index 7c4b2a6592..f5596b6d1b 100644 --- a/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.unit.test.ts +++ b/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.unit.test.ts @@ -28,8 +28,14 @@ describe("GetUserAgencyDashboardUrl", () => { .withFirstName("John") .withIsAdmin(false) .withEstablishments(undefined); + const anotherUserBuilder = new InclusionConnectedUserBuilder() + .withId("another-user-id") + .withFirstName("Jane") + .withIsAdmin(false) + .withEstablishments(undefined); const icNotAdmin = notAdminBuilder.build(); const notAdmin = notAdminBuilder.buildUser(); + const anotherUser = anotherUserBuilder.build(); const agencyWithoutCounsellorAndValidatorBuilder = new AgencyDtoBuilder(); @@ -438,23 +444,40 @@ describe("GetUserAgencyDashboardUrl", () => { it("retrieve establishments when IC user is establishement rep in at least one establishment", async () => { uow.userRepository.users = [notAdmin]; - const establishmentUserRights: EstablishmentUserRight[] = [ - { - job: "Chef", - role: "establishment-admin", - userId: notAdmin.id, - phone: "+33600000000", - }, - ]; + const establishmentUserRightsForFirstEstablishment: EstablishmentUserRight[] = + [ + { + job: "Chef", + role: "establishment-admin", + userId: notAdmin.id, + phone: "+33600000000", + }, + { + job: "Dev", + role: "establishment-admin", + userId: anotherUser.id, + phone: "+33600000001", + }, + ]; + + const establishmentUserRightsForSecondEstablishment: EstablishmentUserRight[] = + [ + { + job: "Chef", + role: "establishment-contact", + userId: notAdmin.id, + phone: "+33600000000", + }, + ]; const establishmentAggregate1 = new EstablishmentAggregateBuilder() .withEstablishmentSiret("89114285300012") - .withUserRights(establishmentUserRights) + .withUserRights(establishmentUserRightsForFirstEstablishment) .build(); const establishmentAggregate2 = new EstablishmentAggregateBuilder() .withEstablishmentSiret("89114285300013") - .withUserRights(establishmentUserRights) + .withUserRights(establishmentUserRightsForSecondEstablishment) .build(); uow.establishmentAggregateRepository.establishmentAggregates = [ @@ -471,10 +494,12 @@ describe("GetUserAgencyDashboardUrl", () => { { siret: establishmentAggregate1.establishment.siret, businessName: establishmentAggregate1.establishment.name, + role: "establishment-admin", }, { siret: establishmentAggregate2.establishment.siret, businessName: establishmentAggregate2.establishment.name, + role: "establishment-contact", }, ]); }); diff --git a/front/src/app/pages/establishment-dashboard/EstablishmentDashboardPage.tsx b/front/src/app/pages/establishment-dashboard/EstablishmentDashboardPage.tsx index fb8644fa4a..a1c3c29358 100644 --- a/front/src/app/pages/establishment-dashboard/EstablishmentDashboardPage.tsx +++ b/front/src/app/pages/establishment-dashboard/EstablishmentDashboardPage.tsx @@ -5,7 +5,7 @@ import Tabs from "@codegouvfr/react-dsfr/Tabs"; import { ReactJSXElement } from "@emotion/react/types/jsx-namespace"; import React from "react"; import { Loader } from "react-design-system"; -import { EstablishmentRole, InclusionConnectedUser } from "shared"; +import { ConventionEstablishmentRole, InclusionConnectedUser } from "shared"; import { MetabaseView } from "src/app/components/MetabaseView"; import { SelectConventionFromIdForm } from "src/app/components/SelectConventionFromIdForm"; import { useAppSelector } from "src/app/hooks/reduxHooks"; @@ -20,7 +20,7 @@ import { P, match } from "ts-pattern"; import { Route } from "type-route"; import { ManageDiscussionFormSection } from "./ManageDiscussionFormSection"; -const currentUserRoleToDisplay = (role: EstablishmentRole) => +const currentUserRoleToDisplay = (role: ConventionEstablishmentRole) => role === "establishment-representative" ? "responsable d'entreprise" : "tuteur de l'entreprise"; @@ -96,7 +96,10 @@ export const EstablishmentDashboardPage = ({ tabId: "fiche-entreprise", content: ( + establishment.role === "establishment-admin", + )} route={route} /> ), diff --git a/front/src/app/pages/establishment-dashboard/ManageEstablishmentTab.tsx b/front/src/app/pages/establishment-dashboard/ManageEstablishmentTab.tsx index c4034ef199..cf10e8a0cf 100644 --- a/front/src/app/pages/establishment-dashboard/ManageEstablishmentTab.tsx +++ b/front/src/app/pages/establishment-dashboard/ManageEstablishmentTab.tsx @@ -1,13 +1,13 @@ import { fr } from "@codegouvfr/react-dsfr"; import Select from "@codegouvfr/react-dsfr/SelectNext"; import React from "react"; -import { WithEstablismentsSiretAndName, domElementIds } from "shared"; +import { WithEstablishmentData, domElementIds } from "shared"; import { EstablishmentForm } from "src/app/components/forms/establishment/EstablishmentForm"; import { routes } from "src/app/routes/routes"; import { getUrlParameters } from "src/app/utils/url.utils"; import { Route } from "type-route"; type ManageEstablishmentTabProps = { - establishments: WithEstablismentsSiretAndName[]; + establishments: WithEstablishmentData[]; route: Route; }; export const ManageEstablishmentsTab = ({ diff --git a/shared/src/inclusionConnect/inclusionConnect.dto.ts b/shared/src/inclusionConnect/inclusionConnect.dto.ts index b7d439b3c6..37d42fc22a 100644 --- a/shared/src/inclusionConnect/inclusionConnect.dto.ts +++ b/shared/src/inclusionConnect/inclusionConnect.dto.ts @@ -5,7 +5,7 @@ import { InclusionConnectedUser, User, } from "../inclusionConnectedAllowed/inclusionConnectedAllowed.dto"; -import { EstablishmentRole, Role } from "../role/role.dto"; +import { ConventionEstablishmentRole, Role } from "../role/role.dto"; import { allowedStartInclusionConnectLoginPages } from "../routes/routes"; import { ExcludeFromExisting, ExtractFromExisting } from "../utils"; @@ -32,7 +32,7 @@ export type AuthenticatedUserQueryParams = { } & Pick; type InclusionConnectConventionManageAllowedRole = - | EstablishmentRole + | ConventionEstablishmentRole | ExtractFromExisting | ExcludeFromExisting; diff --git a/shared/src/inclusionConnectedAllowed/InclusionConnectedUser.builder.ts b/shared/src/inclusionConnectedAllowed/InclusionConnectedUser.builder.ts index df118331bb..c101b75368 100644 --- a/shared/src/inclusionConnectedAllowed/InclusionConnectedUser.builder.ts +++ b/shared/src/inclusionConnectedAllowed/InclusionConnectedUser.builder.ts @@ -6,7 +6,7 @@ import { User, UserId, UserWithAdminRights, - WithEstablismentsSiretAndName, + WithEstablishmentData, } from "./inclusionConnectedAllowed.dto"; const defaultUser: User = { @@ -126,9 +126,7 @@ export class InclusionConnectedUserBuilder return new InclusionConnectedUserBuilder({ ...this.#dto, agencyRights }); } - withEstablishments( - establishments: WithEstablismentsSiretAndName[] | undefined, - ) { + withEstablishments(establishments: WithEstablishmentData[] | undefined) { return new InclusionConnectedUserBuilder({ ...this.#dto, establishments }); } } diff --git a/shared/src/inclusionConnectedAllowed/inclusionConnectedAllowed.dto.ts b/shared/src/inclusionConnectedAllowed/inclusionConnectedAllowed.dto.ts index d1580c8834..a6f51fbbd8 100644 --- a/shared/src/inclusionConnectedAllowed/inclusionConnectedAllowed.dto.ts +++ b/shared/src/inclusionConnectedAllowed/inclusionConnectedAllowed.dto.ts @@ -6,7 +6,10 @@ import { import { DiscussionId } from "../discussion/discussion.dto"; import { Email } from "../email/email.dto"; import { WithSourcePage } from "../inclusionConnect/inclusionConnect.dto"; -import { EstablishmentRole } from "../role/role.dto"; +import { + ConventionEstablishmentRole, + EstablishmentRole, +} from "../role/role.dto"; import { SiretDto } from "../siret/siret"; import { Flavor } from "../typeFlavors"; import { DateTimeIsoString } from "../utils/date"; @@ -48,18 +51,19 @@ type WithAgencyRights = { agencyRights: AgencyRight[]; }; -export type WithEstablismentsSiretAndName = { +export type WithEstablishmentData = { siret: SiretDto; businessName: string; + role: EstablishmentRole; }; export type WithEstablishments = { - establishments?: WithEstablismentsSiretAndName[]; + establishments?: WithEstablishmentData[]; }; export type ConventionsEstablishmentDashboard = { url: AbsoluteUrl; - role: EstablishmentRole; + role: ConventionEstablishmentRole; }; export type WithDiscussionId = { discussionId: DiscussionId; diff --git a/shared/src/inclusionConnectedAllowed/inclusionConnectedAllowed.schema.ts b/shared/src/inclusionConnectedAllowed/inclusionConnectedAllowed.schema.ts index 11da710c3e..eb3a751010 100644 --- a/shared/src/inclusionConnectedAllowed/inclusionConnectedAllowed.schema.ts +++ b/shared/src/inclusionConnectedAllowed/inclusionConnectedAllowed.schema.ts @@ -4,7 +4,10 @@ import { agencyDtoForAgencyUsersAndAdminsSchema } from "../agency/agency.schema" import { discussionIdSchema } from "../discussion/discussion.schema"; import { emailSchema } from "../email/email.schema"; import { IdToken } from "../inclusionConnect/inclusionConnect.dto"; -import { establishmentsRoles } from "../role/role.dto"; +import { + conventionEstablishmentsRoles, + establishmentsRoles, +} from "../role/role.dto"; import { dateTimeIsoStringSchema } from "../schedule/Schedule.schema"; import { siretSchema } from "../siret/siret.schema"; import { zStringCanBeEmpty, zStringMinLength1 } from "../zodUtils"; @@ -17,7 +20,7 @@ import { WithAgencyDashboards, WithDiscussionId, WithEstablishmentDashboards, - WithEstablismentsSiretAndName, + WithEstablishmentData, WithOptionalUserId, allAgencyRoles, } from "./inclusionConnectedAllowed.dto"; @@ -40,11 +43,13 @@ export const withOptionalUserIdSchema: z.Schema = z.object({ userId: userIdSchema.optional(), }); -const withEstablishmentSiretAndName: z.Schema = - z.object({ +const withEstablishmentSiretAndName: z.Schema = z.object( + { siret: siretSchema, businessName: zStringMinLength1, - }); + role: z.enum(establishmentsRoles), + }, +); const dashboardsSchema: z.Schema< WithAgencyDashboards & WithEstablishmentDashboards @@ -53,7 +58,7 @@ const dashboardsSchema: z.Schema< conventions: z .object({ url: absoluteUrlSchema, - role: z.enum(establishmentsRoles), + role: z.enum(conventionEstablishmentsRoles), }) .optional(), discussions: absoluteUrlSchema.optional(), diff --git a/shared/src/role/role.dto.ts b/shared/src/role/role.dto.ts index e12125c59c..46ef7bef2c 100644 --- a/shared/src/role/role.dto.ts +++ b/shared/src/role/role.dto.ts @@ -4,8 +4,9 @@ export type Role = (typeof allRoles)[number]; export type SignatoryRole = (typeof allSignatoryRoles)[number]; export type AgencyModifierRole = (typeof agencyModifierRoles)[number]; export type ModifierRole = (typeof allModifierRoles)[number]; -export type EstablishmentRole = (typeof establishmentsRoles)[number]; export type AssessmentRole = (typeof assessmentRoles)[number]; +export type ConventionEstablishmentRole = + (typeof conventionEstablishmentsRoles)[number]; export const allRoles = [ "beneficiary", "beneficiary-representative", @@ -29,7 +30,7 @@ export const allSignatoryRoles = [ Required[keyof Required]["role"] >; -export const establishmentsRoles = [ +export const conventionEstablishmentsRoles = [ "establishment-representative", "establishment-tutor", ] as const; @@ -53,3 +54,9 @@ export const getRequesterRole = (roles: Role[]): Role => { if (roles.includes("counsellor")) return "counsellor"; return roles[0]; }; + +export const establishmentsRoles = [ + "establishment-admin", + "establishment-contact", +] as const; +export type EstablishmentRole = (typeof establishmentsRoles)[number];