Skip to content

Commit

Permalink
♻ Déplacement des Forms Abandon dans des fichiers dédiés (#1946)
Browse files Browse the repository at this point in the history
* ♻ Move form in a dedicated file with use client

* ♻️ Move form dans un module à part + use client
  • Loading branch information
spontoreau committed Jul 8, 2024
1 parent bdc8357 commit 19c0487
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 201 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
'use client';

import Alert from '@codegouvfr/react-dsfr/Alert';
import Checkbox from '@codegouvfr/react-dsfr/Checkbox';
import Input from '@codegouvfr/react-dsfr/Input';
import { FC, useState } from 'react';
import { useRouter } from 'next/navigation';

import { Routes } from '@potentiel-applications/routes';

import { Form } from '@/components/atoms/form/Form';
import { SubmitButton } from '@/components/atoms/form/SubmitButton';
import { UploadDocument } from '@/components/atoms/form/UploadDocument';

import { demanderAbandonAction } from './demanderAbandon.action';

export type DemanderAbandonFormProps = {
identifiantProjet: string;
showRecandidatureCheckBox: boolean;
};

export const DemanderAbandonForm: FC<DemanderAbandonFormProps> = ({
identifiantProjet,
showRecandidatureCheckBox,
}) => {
const router = useRouter();
const [validationErrors, setValidationErrors] = useState<Array<string>>([]);
const [recandidature, setRecandidature] = useState(false);

return (
<Form
action={demanderAbandonAction}
method="post"
encType="multipart/form-data"
onSuccess={() => router.push(Routes.Abandon.détail(identifiantProjet))}
onValidationError={(validationErrors) => setValidationErrors(validationErrors)}
>
<input type={'hidden'} value={identifiantProjet} name="identifiantProjet" />

<Input
textArea
label="Raison"
id="raison"
hintText="Pour faciliter le traitement de votre demande, veillez à détailler les raisons ayant
conduit à ce besoin de modification (contexte, facteurs extérieurs, etc.)."
nativeTextAreaProps={{ name: 'raison', required: true, 'aria-required': true }}
state={validationErrors.includes('raison') ? 'error' : 'default'}
stateRelatedMessage="Raison à préciser"
/>

<UploadDocument
label={`Pièce justificative${recandidature ? ' (optionnel)' : ''}`}
id="pieceJustificative"
name="pieceJustificative"
required={!recandidature}
state={validationErrors.includes('pieceJustificative') ? 'error' : 'default'}
/>

{showRecandidatureCheckBox && (
<Checkbox
className="mt-6"
legend="Option"
id="recandidature"
state={validationErrors.includes('recandidature') ? 'error' : 'default'}
options={[
{
label: 'Je demande un abandon avec recandidature (optionnel)',
hintText: 'Cocher cette case pour signaler un abandon pour recandidature',
nativeInputProps: {
name: 'recandidature',
value: 'true',
onClick: () => setRecandidature(!recandidature),
},
},
]}
/>
)}

{showRecandidatureCheckBox && recandidature ? (
<Alert
severity="warning"
title="Abandon avec recandidature"
className="mb-6"
description={
<div>
<div className="font-bold">(procédure dérogatoire et facultative)</div>
<div>
<p className="m-0 mt-4">
Par cet abandon avec recandidature, je m'engage sur l'honneur à ne pas avoir
débuté mes travaux au sens du cahier des charges de l'appel d'offres associé et à
abandonner mon statut de lauréat au profit d'une recandidature réalisée au plus
tard le 31/12/2024. Je m'engage sur l'honneur à ce que cette recandidature
respecte les conditions suivantes :
</p>
<ul className="mb-0 list-disc indent-8 list-inside">
<li>
Que le dossier soit complet et respecte les conditions d'éligibilité du cahier
des charges concerné
</li>
<li>Le même lieu d'implantation que le projet abandonné</li>
<li>
La même autorisation préfectorale (numéro ICPE identifique) que le projet
abandonné, nonobstant des porter à connaissance ultérieurs
</li>
<li>
Le tarif proposé ne doit pas être supérieur au prix plafond de la période dont
le projet était initialement lauréat, indexé jusqu’à septembre 2023 selon la
formule d’indexation du prix de référence indiquée dans le cahier des charges
concerné par la recandidature.
</li>
</ul>
</div>
</div>
}
/>
) : null}

<SubmitButton>Envoyer</SubmitButton>
</Form>
);
};
Original file line number Diff line number Diff line change
@@ -1,130 +1,28 @@
'use client';

import Alert from '@codegouvfr/react-dsfr/Alert';
import Checkbox from '@codegouvfr/react-dsfr/Checkbox';
import Input from '@codegouvfr/react-dsfr/Input';
import { useRouter } from 'next/navigation';
import { FC, useState } from 'react';

import { Routes } from '@potentiel-applications/routes';
import { FC } from 'react';

import { Form } from '@/components/atoms/form/Form';
import { SubmitButton } from '@/components/atoms/form/SubmitButton';
import { UploadDocument } from '@/components/atoms/form/UploadDocument';
import { ProjetBanner } from '@/components/molecules/projet/ProjetBanner';
import { ColumnPageTemplate } from '@/components/templates/ColumnPage.template';
import { Heading1 } from '@/components/atoms/headings';

import { demanderAbandonAction } from './demanderAbandon.action';
import { DemanderAbandonForm, DemanderAbandonFormProps } from './DemanderAbandon.form';

export type DemanderAbandonPageProps = {
identifiantProjet: string;
showRecandidatureCheckBox: boolean;
};
export type DemanderAbandonPageProps = DemanderAbandonFormProps;

export const DemanderAbandonPage: FC<DemanderAbandonPageProps> = ({
identifiantProjet,
showRecandidatureCheckBox,
}) => {
const router = useRouter();
const [validationErrors, setValidationErrors] = useState<Array<string>>([]);
const [recandidature, setRecandidature] = useState(false);

return (
<ColumnPageTemplate
banner={<ProjetBanner identifiantProjet={identifiantProjet} />}
heading={<Heading1>Demander l'abandon du projet</Heading1>}
leftColumn={{
children: (
<Form
action={demanderAbandonAction}
method="post"
encType="multipart/form-data"
onSuccess={() => router.push(Routes.Abandon.détail(identifiantProjet))}
onValidationError={(validationErrors) => setValidationErrors(validationErrors)}
>
<input type={'hidden'} value={identifiantProjet} name="identifiantProjet" />

<Input
textArea
label="Raison"
id="raison"
hintText="Pour faciliter le traitement de votre demande, veillez à détailler les raisons ayant
conduit à ce besoin de modification (contexte, facteurs extérieurs, etc.)."
nativeTextAreaProps={{ name: 'raison', required: true, 'aria-required': true }}
state={validationErrors.includes('raison') ? 'error' : 'default'}
stateRelatedMessage="Raison à préciser"
/>

<UploadDocument
label={`Pièce justificative${recandidature ? ' (optionnel)' : ''}`}
id="pieceJustificative"
name="pieceJustificative"
required={!recandidature}
state={validationErrors.includes('pieceJustificative') ? 'error' : 'default'}
/>

{showRecandidatureCheckBox && (
<Checkbox
className="mt-6"
legend="Option"
id="recandidature"
state={validationErrors.includes('recandidature') ? 'error' : 'default'}
options={[
{
label: 'Je demande un abandon avec recandidature (optionnel)',
hintText: 'Cocher cette case pour signaler un abandon pour recandidature',
nativeInputProps: {
name: 'recandidature',
value: 'true',
onClick: () => setRecandidature(!recandidature),
},
},
]}
/>
)}

{showRecandidatureCheckBox && recandidature ? (
<Alert
severity="warning"
title="Abandon avec recandidature"
className="mb-6"
description={
<div>
<div className="font-bold">(procédure dérogatoire et facultative)</div>
<div>
<p className="m-0 mt-4">
Par cet abandon avec recandidature, je m'engage sur l'honneur à ne pas avoir
débuté mes travaux au sens du cahier des charges de l'appel d'offres associé
et à abandonner mon statut de lauréat au profit d'une recandidature réalisée
au plus tard le 31/12/2024. Je m'engage sur l'honneur à ce que cette
recandidature respecte les conditions suivantes :
</p>
<ul className="mb-0 list-disc indent-8 list-inside">
<li>
Que le dossier soit complet et respecte les conditions d'éligibilité du
cahier des charges concerné
</li>
<li>Le même lieu d'implantation que le projet abandonné</li>
<li>
La même autorisation préfectorale (numéro ICPE identifique) que le projet
abandonné, nonobstant des porter à connaissance ultérieurs
</li>
<li>
Le tarif proposé ne doit pas être supérieur au prix plafond de la période
dont le projet était initialement lauréat, indexé jusqu’à septembre 2023
selon la formule d’indexation du prix de référence indiquée dans le cahier
des charges concerné par la recandidature.
</li>
</ul>
</div>
</div>
}
/>
) : null}

<SubmitButton>Envoyer</SubmitButton>
</Form>
<DemanderAbandonForm
identifiantProjet={identifiantProjet}
showRecandidatureCheckBox={showRecandidatureCheckBox}
/>
),
}}
rightColumn={{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use client';

import Badge from '@codegouvfr/react-dsfr/Badge';
import { FC } from 'react';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
'use client';

import { FC, useState } from 'react';
import { useRouter } from 'next/navigation';
import SelectNext from '@codegouvfr/react-dsfr/SelectNext';

import { Routes } from '@potentiel-applications/routes';
import { Iso8601DateTime } from '@potentiel-libraries/iso8601-datetime';

import { Form } from '@/components/atoms/form/Form';
import { SubmitButton } from '@/components/atoms/form/SubmitButton';

import { transmettrePreuveRecandidatureAction } from './transmettrePreuveRecandidature.action';

type ProjetÀSélectionner = {
identifiantProjet: string;
appelOffre: string;
période: string;
famille: string;
numéroCRE: string;
dateDésignation: Iso8601DateTime;
nom: string;
};

export type TransmettrePreuveRecandidatureFormProps = {
identifiantProjet: string;
projetsÀSélectionner: Array<ProjetÀSélectionner>;
};

export const TransmettrePreuveRecandidatureForm: FC<TransmettrePreuveRecandidatureFormProps> = ({
identifiantProjet,
projetsÀSélectionner,
}) => {
const router = useRouter();
const [projetSélectionné, setProjetSélectionné] = useState<{
identifiantProjet: ProjetÀSélectionner['identifiantProjet'];
dateDésignation: ProjetÀSélectionner['dateDésignation'];
}>();

const getProjectLabel = (projet: ProjetÀSélectionner) =>
`${projet.nom} | ${projet.appelOffre}-P${projet.période}${
projet.famille ? `-${projet.famille}` : ''
}-${projet.numéroCRE}`;

const [validationErrors, setValidationErrors] = useState<Array<string>>([]);

return (
<Form
action={transmettrePreuveRecandidatureAction}
method="post"
onValidationError={(validationErrors) => setValidationErrors(validationErrors)}
onSuccess={() => router.push(Routes.Abandon.détail(identifiantProjet))}
>
<input type={'hidden'} value={identifiantProjet} name="identifiantProjet" />

<SelectNext
label="Choisir un projet comme preuve de recandidature"
placeholder={`Sélectionner un projet`}
state={validationErrors.includes('preuveRecandidature') ? 'error' : 'default'}
stateRelatedMessage="La sélection du projet est obligatoire"
nativeSelectProps={{
onChange: ({ currentTarget: { value } }) => {
const projet = projetsÀSélectionner.find(
(projet) => projet.identifiantProjet === value,
);

if (projet) {
setProjetSélectionné({
identifiantProjet: projet.identifiantProjet,
dateDésignation: projet.dateDésignation,
});
}
},
}}
options={projetsÀSélectionner.map((projet) => ({
label: getProjectLabel(projet),
value: projet.identifiantProjet,
}))}
/>

{projetSélectionné && (
<>
<input
type={'hidden'}
value={projetSélectionné.identifiantProjet}
name="preuveRecandidature"
/>
<input type={'hidden'} value={projetSélectionné.dateDésignation} name="dateDesignation" />
</>
)}

<SubmitButton disabledCondition={() => !projetSélectionné}>
Transmettre la preuve de recandidature
</SubmitButton>
</Form>
);
};
Loading

0 comments on commit 19c0487

Please sign in to comment.