Skip to content

Commit

Permalink
assessment document page
Browse files Browse the repository at this point in the history
  • Loading branch information
celineung committed Feb 10, 2025
1 parent 163846f commit b011cc4
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 2 deletions.
6 changes: 5 additions & 1 deletion front/src/app/hooks/jwt.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ export const useAdminToken = () => {
return rawToken;
};

export const useJwt = (route: Route<typeof routes.conventionDocument>) => {
export const useJwt = (
route: Route<
typeof routes.conventionDocument | typeof routes.assessmentDocument
>,
) => {
const jwtQueryParam: ConventionSupportedJwt | undefined = route.params?.jwt;
const inclusionConnectJwt = useAppSelector(
authSelectors.inclusionConnectToken,
Expand Down
224 changes: 224 additions & 0 deletions front/src/app/pages/convention/AssessmentDocumentPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import { fr } from "@codegouvfr/react-dsfr";
import React, { useEffect } from "react";
import { Document, Loader, MainWrapper } from "react-design-system";
import { useDispatch } from "react-redux";
import {
computeTotalHours,
convertLocaleDateToUtcTimezoneDate,
isStringDate,
makeSiretDescriptionLink,
toDisplayedDate,
} from "shared";
import { useConvention } from "src/app/hooks/convention.hooks";
import { useJwt } from "src/app/hooks/jwt.hooks";
import { useAppSelector } from "src/app/hooks/reduxHooks";
import { routes } from "src/app/routes/routes";
import { assessmentSelectors } from "src/core-logic/domain/assessment/assessment.selectors";
import { assessmentSlice } from "src/core-logic/domain/assessment/assessment.slice";
import { Route } from "type-route";
import logoIf from "/assets/img/logo-if.svg";
import logoRf from "/assets/img/logo-rf.svg";

type AssessmentDocumentPageProps = {
route: Route<typeof routes.assessmentDocument>;
};

export const AssessmentDocumentPage = ({
route,
}: AssessmentDocumentPageProps) => {
const dispatch = useDispatch();
const { jwt, jwtPayload } = useJwt(route);
const conventionId = jwtPayload.applicationId;
const assessment = useAppSelector(assessmentSelectors.currentAssessment);
const isAssessmentLoading = useAppSelector(assessmentSelectors.isLoading);
const { convention, isLoading: isConventionLoading } = useConvention({
jwt,
conventionId: jwtPayload.applicationId,
});

const logos = [
<img key="logo-rf" src={logoRf} alt="Logo RF" />,
<img key={"logo-if"} src={logoIf} alt="" />,
];

useEffect(() => {
dispatch(
assessmentSlice.actions.getAssessmentRequested({
conventionId,
jwt,
feedbackTopic: "assessment",
}),
);
}, [dispatch, conventionId, jwt]);

if (isConventionLoading || isAssessmentLoading) return <Loader />;
if (!convention) return <p>Pas de convention correspondante trouvée</p>;
if (!assessment) return <p>Pas de bilan correspondant trouvé</p>;

return (
<MainWrapper layout="default" vSpacing={8}>
<Document
logos={logos}
title={`Bilan ${
convention.internshipKind === "immersion"
? "de l'Immersion Professionelle"
: "du mini-stage"
} au sein de ${convention.businessName}`}
customActions={[]}
>
<h2 className={fr.cx("fr-h4")}>
Identifiant de la convention: {convention.id}
</h2>
<p>
{convention.internshipKind === "immersion"
? "Cette immersion s'est déroulée"
: "Ce mini-stage s'est déroulé"}{" "}
du{" "}
{toDisplayedDate({
date: convertLocaleDateToUtcTimezoneDate(
new Date(convention.dateStart),
),
})}{" "}
au{" "}
{toDisplayedDate({
date: convertLocaleDateToUtcTimezoneDate(
new Date(convention.dateEnd),
),
})}{" "}
au sein de <strong>{convention.businessName}</strong> (Siret n° :{" "}
<a
href={makeSiretDescriptionLink(convention.siret)}
target="_blank"
rel="noreferrer"
>
{convention.siret}
</a>
) à l'adresse suivante <strong>{convention.immersionAddress}</strong>.
</p>
<p>
Métier observé : {convention.immersionAppellation.appellationLabel}.
</p>
<p>
Objectif{" "}
{convention.internshipKind === "immersion"
? "de l'immersion"
: "du mini-stage"}{" "}
: {convention.immersionObjective}.
</p>
<p>
Le tuteur {convention.establishmentTutor.firstName}{" "}
{convention.establishmentTutor.lastName} de{" "}
{convention.signatories.beneficiary.firstName}{" "}
{convention.signatories.beneficiary.lastName} a évalué son{" "}
{convention.internshipKind === "immersion"
? "immersion"
: "mini-stage"}
.
</p>
<h2 className={fr.cx("fr-h4", "fr-mt-4w")}>
Voici les informations saisies durant{" "}
{convention.internshipKind === "immersion"
? "cette immersion"
: "ce mini-stage"}{" "}
:
</h2>
<ul>
<li>
{convention.internshipKind === "immersion"
? "L'immersion a-t-elle"
: "Le mini-stage a-il"}{" "}
eu lieu ? {assessment.status === "DID_NOT_SHOW" ? "Non" : "Oui"}
</li>
{assessment.status === "COMPLETED" && (
<>
<li>
Nombre d'heures totales de l'immersion :{" "}
{computeTotalHours({
convention,
assessmentStatus: assessment.status,
missedHours: 0,
})}
</li>
<li>
Date réelle de fin de l'immersion :{" "}
{toDisplayedDate({
date: new Date(convention.dateEnd),
withHours: false,
})}
</li>
</>
)}
{assessment.status === "PARTIALLY_COMPLETED" && (
<>
<li>
Nombre d'heures totales de l'immersion :{" "}
{computeTotalHours({
convention,
assessmentStatus: assessment.status,
missedHours:
assessment.status === "PARTIALLY_COMPLETED"
? assessment.numberOfMissedHours
: 0,
})}
</li>
<li>
Date réelle de fin de l'immersion :{" "}
{isStringDate(assessment.lastDayOfPresence ?? "")
? toDisplayedDate({
date: new Date(assessment.lastDayOfPresence ?? ""),
withHours: false,
})
: "DATE INVALIDE"}
</li>
</>
)}
</ul>
<h2 className={fr.cx("fr-h4", "fr-mt-4w")}>
Résultats de{" "}
{convention.internshipKind === "immersion"
? "l'immersion"
: "du mini-stage"}{" "}
:
</h2>
<ul>
<li>Embauche ? {assessment.endedWithAJob ? "Oui" : "Non"}</li>
{assessment.endedWithAJob && (
<>
<li>
{toDisplayedDate({
date: convertLocaleDateToUtcTimezoneDate(
new Date(assessment.contractStartDate),
),
})}
</li>
<li>Type de contrat : {assessment.typeOfContract}</li>
</>
)}
</ul>
<h2 className={fr.cx("fr-h4", "fr-mt-4w")}>Appréciation générale :</h2>
<p>{assessment.establishmentFeedback}</p>
<h2 className={fr.cx("fr-h4", "fr-mt-4w")}>Conseils pour la suite :</h2>
<p>{assessment.establishmentAdvices}</p>
<hr className={fr.cx("fr-hr", "fr-mb-6w", "fr-mt-10w")} />
<footer className={fr.cx("fr-text--xs")}>
<p>
Ce document a été rédigé dans le cadre{" "}
{convention.internshipKind === "immersion"
? "de l'immersion professionelle réalisée"
: "du mini-stage réalisé"}
par {convention.signatories.beneficiary.firstName}{" "}
{convention.signatories.beneficiary.lastName} chez{" "}
{convention.businessName}. Il peut être utilisé comme référence lors
de futurs entretiens ou dans le dossier de candidature pour
valoriser l'expérience acquise au sein de l'entreprise d'accueil.
</p>
<p>
Nous vous encourageons à conserver ce PDF comme preuve officielle de
votre immersion et des compétences développées, en vue de vos
futures candidatures.
</p>
</footer>
</Document>
</MainWrapper>
);
};
3 changes: 2 additions & 1 deletion front/src/app/routes/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { AdminUserDetail } from "src/app/pages/admin/AdminUserDetail";
import { AgencyDashboardPage } from "src/app/pages/agency-dashboard/AgencyDashboardPage";
import { AddAgencyPage } from "src/app/pages/agency/AddAgencyPage";
import { BeneficiaryDashboardPage } from "src/app/pages/beneficiary-dashboard/BeneficiaryDashboardPage";
import { AssessmentDocumentPage } from "src/app/pages/convention/AssessmentDocumentPage";
import { ConventionConfirmationPage } from "src/app/pages/convention/ConventionConfirmationPage";
import { ConventionImmersionPage } from "src/app/pages/convention/ConventionImmersionPage";
import { ConventionManageInclusionConnectedPage } from "src/app/pages/convention/ConventionManageInclusionConnectedPage";
Expand Down Expand Up @@ -137,7 +138,7 @@ const getPageByRouteName: {
<AgencyDetailForAgencyDashboard route={route} />
</AgencyDashboardPrivateRoute>
),

assessmentDocument: (route) => <AssessmentDocumentPage route={route} />,
beneficiaryDashboard: () => <BeneficiaryDashboardPage />,
initiateConvention: () => <InitiateConventionPage />,
conventionImmersion: (route) => <ConventionImmersionPage route={route} />,
Expand Down
4 changes: 4 additions & 0 deletions front/src/app/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ export const { RouteProvider, useRoute, routes } = createRouter({
({ conventionId }) =>
`/${frontRoutes.conventionImmersionRoute}/confirmation/${conventionId}`,
),
assessmentDocument: defineRoute(
{ jwt: param.query.optional.string },
() => `/${frontRoutes.assessmentDocument}`,
),
conventionDocument: defineRoute(
{
jwt: param.query.optional.string,
Expand Down
1 change: 1 addition & 0 deletions shared/src/domElementIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@ export const domElementIds = {
conventionDocument: {
downloadPdfButton: "im-convention-document__download-pdf-button",
},
assessmentDocument: {},
landingEstablishment: {},
conventionToSign: {
form: "im-convention-to-sign-form",
Expand Down
1 change: 1 addition & 0 deletions shared/src/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const frontRoutes = {
[allowedStartInclusionConnectLoginPages[0]]: "tableau-de-bord-agence",
[allowedStartInclusionConnectLoginPages[1]]: "tableau-de-bord-etablissement",
[allowedStartInclusionConnectLoginPages[2]]: "admin",
assessmentDocument: "bilan-document",
beneficiaryDashboard: "tableau-de-bord-beneficiaire",
initiateConvention: "initier-convention",
conventionImmersionRoute: "demande-immersion",
Expand Down

0 comments on commit b011cc4

Please sign in to comment.