Skip to content

Commit

Permalink
feat(admin-react,api): implement state in dff competence details
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomasDos committed Jul 4, 2024
1 parent 0362507 commit 28c3eb9
Show file tree
Hide file tree
Showing 10 changed files with 249 additions and 103 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import CandidacySectionCard from "@/components/card/candidacy-section-card/CandidacySectionCard";
import {
BadgeCompleted,
BadgeToComplete,
} from "@/components/card/candidacy-section-card/DefaultCandidacySectionCard";
import {
CertificationCompetenceDetails,
CompetenceBlocsPartCompletion,
DffCertificationCompetenceBloc,
} from "@/graphql/generated/graphql";
import Badge from "@codegouvfr/react-dsfr/Badge";
import Button from "@codegouvfr/react-dsfr/Button";
import { useParams } from "next/navigation";
import { CertificationCompetenceAccordion } from "./DffSummary/_components/CertificationCompetenceAccordion";

const CompetencesSectionBadge = ({
completion,
}: {
completion: CompetenceBlocsPartCompletion;
}) => {
switch (completion) {
case "COMPLETED":
return <BadgeCompleted />;
case "IN_PROGRESS":
return <Badge severity="info">En cours</Badge>;
default:
return <BadgeToComplete />;
}
};

export const CompetenciesBlocksSection = ({
competenceBlocsPartCompletion,
certificationCompetenceDetails,
blocsDeCompetences,
}: {
competenceBlocsPartCompletion?: CompetenceBlocsPartCompletion;
certificationCompetenceDetails: CertificationCompetenceDetails[];
blocsDeCompetences: DffCertificationCompetenceBloc[];
}) => {
const { candidacyId } = useParams();

return (
<CandidacySectionCard
title="Blocs de compétences"
titleIconClass="fr-icon-survey-fill"
badge={
<CompetencesSectionBadge
completion={competenceBlocsPartCompletion || "TO_COMPLETE"}
/>
}
>
<ul className="list-none flex flex-col">
{blocsDeCompetences?.map((bloc) => (
<li
key={bloc.certificationCompetenceBloc.id}
className="flex justify-between items-start pb-0 gap-6"
>
<CertificationCompetenceAccordion
key={bloc.certificationCompetenceBloc.id}
competenceBloc={bloc.certificationCompetenceBloc}
competenceDetails={certificationCompetenceDetails}
/>
<Button
className="w-[120px] mt-4 flex-none"
priority={bloc.complete ? "secondary" : "primary"}
linkProps={{
href: `/candidacies/${candidacyId}/feasibility-aap/competencies-blocks/${bloc.certificationCompetenceBloc.id}`,
}}
>
<span className="mx-auto">
{bloc.complete ? "Modifier" : "Compléter"}
</span>
</Button>
</li>
))}
</ul>
</CandidacySectionCard>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import {
CertificationCompetence,
CertificationCompetenceBloc,
CertificationCompetenceDetails,
DffCertificationCompetenceDetailsState,
} from "@/graphql/generated/graphql";
import Accordion from "@codegouvfr/react-dsfr/Accordion";
import Badge from "@codegouvfr/react-dsfr/Badge";

const getTextFromCompetence = ({
competence,
Expand All @@ -19,6 +21,50 @@ const getTextFromCompetence = ({
);
};

const getStateFromCompetence = ({
competence,
competenceDetails,
}: {
competence: CertificationCompetence;
competenceDetails: CertificationCompetenceDetails[];
}): DffCertificationCompetenceDetailsState => {
return (
competenceDetails.find(
(detail) => detail.certificationCompetence.id === competence.id,
)?.state || "YES"
);
};

const BadgeState = ({
state,
}: {
state: DffCertificationCompetenceDetailsState;
}) => {
if (state === "YES") {
return (
<Badge noIcon severity="success" small>
oui
</Badge>
);
}
if (state === "NO") {
return (
<Badge severity="error" noIcon small>
Non
</Badge>
);
}
if (state === "PARTIALLY") {
return (
<Badge severity="new" noIcon small>
Partiellement
</Badge>
);
}

return null;
};

export const CertificationCompetenceAccordion = ({
competenceBloc,
competenceDetails,
Expand All @@ -35,16 +81,24 @@ export const CertificationCompetenceAccordion = ({
return (
<Accordion label={label} defaultExpanded={defaultExpanded}>
{competenceBloc.competences.map((competence) => (
<p key={competence.id}>
<span className="font-bold">{competence.label} :</span>
<br />
<span>
{getTextFromCompetence({
<>
<BadgeState
state={getStateFromCompetence({
competence,
competenceDetails,
})}
</span>
</p>
/>
<p key={competence.id}>
<span className="font-bold">{competence.label} :</span>
<br />
<span>
{getTextFromCompetence({
competence,
competenceDetails,
})}
</span>
</p>
</>
))}
</Accordion>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const getCandidacyById = graphql(`
}
}
certificationCompetenceDetails {
state
text
certificationCompetence {
id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { FormButtons } from "@/components/form/form-footer/FormButtons";
import { useGraphQlClient } from "@/components/graphql/graphql-client/GraphqlClient";
import { graphqlErrorToast, successToast } from "@/components/toast/toast";
import { graphql } from "@/graphql/generated";
import { CompetenceIdAndText } from "@/graphql/generated/graphql";
import { CompetenceDetails } from "@/graphql/generated/graphql";
import { Input } from "@codegouvfr/react-dsfr/Input";
import RadioButtons from "@codegouvfr/react-dsfr/RadioButtons";
import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useParams } from "next/navigation";
Expand All @@ -19,6 +20,7 @@ const schema = z.object({
competenceId: z.string(),
label: z.string(),
text: z.string().min(1, "Merci de remplir ce champ"),
state: z.enum(["YES", "NO", "PARTIALLY"]),
})
.array(),
});
Expand All @@ -34,6 +36,7 @@ const getBlocDeCompetencesQuery = graphql(`
dematerializedFeasibilityFile {
id
certificationCompetenceDetails {
state
certificationCompetence {
id
}
Expand Down Expand Up @@ -88,7 +91,7 @@ const CompetenciesBlockPage = () => {
candidacyId: string;
dematerializedFeasibilityFileId: string;
competenceBlocId: string;
competenceIdAndTexts: CompetenceIdAndText[];
competenceDetails: CompetenceDetails[];
}) =>
graphqlClient.request(createOrUpdateCompetenceDetailsMutation, {
input,
Expand All @@ -112,6 +115,9 @@ const CompetenciesBlockPage = () => {
text: dematerializedFile?.certificationCompetenceDetails.find(
(ccd) => ccd.certificationCompetence.id === c.id,
)?.text,
state: dematerializedFile?.certificationCompetenceDetails.find(
(ccd) => ccd.certificationCompetence.id === c.id,
)?.state,
})),
}),
[competencesFromBlock, dematerializedFile?.certificationCompetenceDetails],
Expand Down Expand Up @@ -141,15 +147,17 @@ const CompetenciesBlockPage = () => {
useEffect(resetForm, [resetForm]);

const handleFormSubmit = handleSubmit(async (data) => {
const competenceDetails = data.competences.map((c) => ({
competenceId: c.competenceId,
text: c.text,
state: c.state,
}));
try {
await createOrUpdateCompetenceDetails.mutateAsync({
candidacyId,
dematerializedFeasibilityFileId: dematerializedFile?.id || "",
competenceBlocId: blocDeCompetencesId,
competenceIdAndTexts: data.competences.map((c) => ({
competenceId: c.competenceId,
text: c.text,
})),
competenceDetails,
});
successToast("Modifications enregistrées");
} catch (e) {
Expand Down Expand Up @@ -177,19 +185,47 @@ const CompetenciesBlockPage = () => {
}}
>
{competencesFields?.map((c, i) => (
<Input
key={c.id}
textArea
label={c.label}
classes={{ nativeInputOrTextArea: "!min-h-[88px]" }}
nativeTextAreaProps={{
...register(`competences.${i}.text`),
}}
stateRelatedMessage={
errors?.competences?.[i]?.text?.message as string
}
state={errors?.competences?.[i]?.text ? "error" : "default"}
/>
<>
<Input
key={c.id}
textArea
label={c.label}
classes={{ nativeInputOrTextArea: "!min-h-[88px]" }}
nativeTextAreaProps={{
...register(`competences.${i}.text`),
}}
stateRelatedMessage={
errors?.competences?.[i]?.text?.message as string
}
state={errors?.competences?.[i]?.text ? "error" : "default"}
/>
<RadioButtons
orientation="horizontal"
options={[
{
label: "Oui",
nativeInputProps: {
...register(`competences.${i}.state`),
value: "YES",
},
},
{
label: "Non",
nativeInputProps: {
...register(`competences.${i}.state`),
value: "NO",
},
},
{
label: "Partiellement",
nativeInputProps: {
...register(`competences.${i}.state`),
value: "PARTIALLY",
},
},
]}
/>
</>
))}
<FormButtons
backUrl={`/candidacies/${candidacyId}/feasibility-aap`}
Expand Down
Loading

0 comments on commit 28c3eb9

Please sign in to comment.