Skip to content

Commit

Permalink
modify contact by mail modal add inputs and modify mail request v1 dt…
Browse files Browse the repository at this point in the history
…o and schema
  • Loading branch information
clement-duport committed Jun 8, 2023
1 parent 9ee2532 commit a98b16a
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type ContactInformationPublicV1<T extends ContactMethod> = {
contactMode: T;
};

type ContactEstablishmentByMailPublicV1Dto =
export type ContactEstablishmentByMailPublicV1Dto =
ContactInformationPublicV1<"EMAIL"> & {
message: string;
};
Expand All @@ -30,4 +30,13 @@ export type ContactEstablishmentPublicV1Dto =

export const contactEstablishmentPublicV1ToDomain = (
contactRequest: ContactEstablishmentPublicV1Dto,
): ContactEstablishmentRequestDto => contactRequest;
): ContactEstablishmentRequestDto => {
if (contactRequest.contactMode === "EMAIL")
return {
...contactRequest,
potentialBeneficiaryPhone: "Numéro de téléphone Non communiqué",
immersionObjective: "Object non communiqué",
};

return contactRequest;
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
import { z } from "zod";
import { contactEstablishmentRequestSchema } from "shared";
import { ContactEstablishmentPublicV1Dto } from "./ContactEstablishmentPublicV1.dto";
import {
contactEstablishmentByPhoneSchema,
contactEstablishmentInPersonSchema,
emailSchema,
preferEmailContactSchema,
romeSchema,
siretSchema,
zTrimmedString,
} from "shared";
import {
ContactEstablishmentByMailPublicV1Dto,
ContactEstablishmentPublicV1Dto,
} from "./ContactEstablishmentPublicV1.dto";

const commonFields = {
offer: romeSchema,
siret: siretSchema,
potentialBeneficiaryFirstName: zTrimmedString,
potentialBeneficiaryLastName: zTrimmedString,
potentialBeneficiaryEmail: emailSchema,
};

const contactEstablishmentByMailSchemaV1: z.Schema<ContactEstablishmentByMailPublicV1Dto> =
z.object({
...commonFields,
contactMode: preferEmailContactSchema,
message: zTrimmedString,
});

const contactEstablishmentRequestSchemaV1: z.Schema<ContactEstablishmentPublicV1Dto> =
z.union([
contactEstablishmentByMailSchemaV1,
contactEstablishmentByPhoneSchema,
contactEstablishmentInPersonSchema,
]);

export const contactEstablishmentPublicV1Schema: z.Schema<ContactEstablishmentPublicV1Dto> =
contactEstablishmentRequestSchema;
contactEstablishmentRequestSchemaV1;
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const validRequest: ContactEstablishmentRequestDto = {
potentialBeneficiaryLastName: "potential_beneficiary_last_name",
potentialBeneficiaryEmail: "potential_beneficiary@email.fr",
message: "message_to_send",
immersionObjective: "Confirmer un projet professionnel",
potentialBeneficiaryPhone: "0654783402",
};

describe(`/${contactEstablishmentRoute} route`, () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ describe("ContactEstablishment", () => {
...validRequest,
contactMode: "EMAIL",
message: "message_to_send",
immersionObjective: "Confirmer un projet professionnel",
potentialBeneficiaryPhone: "0654783402",
};
await contactEstablishment.execute(validEmailRequest);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ describe("Insert discussion aggregate from contact request DTO", () => {
potentialBeneficiaryEmail: "antoine.tourasse@email.com",
contactMode: "EMAIL",
message: "Bonjour, j'aimerais venir jouer chez vous. Je suis sympa.",
immersionObjective: "Confirmer un projet professionnel",
potentialBeneficiaryPhone: "0654783402",
};
await insertDiscussionAggregate.execute(contactRequestDto);

Expand Down Expand Up @@ -141,6 +143,8 @@ describe("Insert discussion aggregate from contact request DTO", () => {
potentialBeneficiaryEmail: "bob.marley@email.com",
contactMode: "EMAIL",
message: "Bonjour, j'aimerais venir jouer chez vous. Je suis sympa.",
immersionObjective: "Confirmer un projet professionnel",
potentialBeneficiaryPhone: "0654783402",
};
await insertDiscussionAggregate.execute(secondContactRequestDto);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ describe("NotifyContactRequest", () => {
...payload,
contactMode: "EMAIL",
message: "message_to_send",
immersionObjective: "Confirmer un projet professionnel",
potentialBeneficiaryPhone: "0654783402",
};
const establishment = new EstablishmentEntityBuilder()
.withSiret(siret)
Expand Down
147 changes: 116 additions & 31 deletions front/src/app/components/search/ContactByEmail.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import React from "react";
import { FormProvider, useForm } from "react-hook-form";
import { fr } from "@codegouvfr/react-dsfr";
import { Button } from "@codegouvfr/react-dsfr/Button";
import Alert from "@codegouvfr/react-dsfr/Alert";
import { ButtonsGroup } from "@codegouvfr/react-dsfr/ButtonsGroup";
import { Input } from "@codegouvfr/react-dsfr/Input";
import Select from "@codegouvfr/react-dsfr/SelectNext";
import { zodResolver } from "@hookform/resolvers/zod";
import {
ContactEstablishmentByMailDto,
contactEstablishmentByMailSchema,
domElementIds,
ImmersionObjective,
RomeDto,
SiretDto,
} from "shared";
Expand All @@ -19,22 +22,23 @@ type ContactByEmailProps = {
siret: SiretDto;
offer: RomeDto;
onSuccess: () => void;
onClose: () => void;
};

const initialMessage =
"Bonjour, \n\n\
J’ai trouvé votre entreprise sur 'Immersion Facilitée.'\n\
Je souhaiterais passer quelques jours dans votre entreprise en immersion professionnelle auprès de vos salariés pour découvrir ce métier.\n\
const initialMessage = `Bonjour, \n\n\
J’ai trouvé votre entreprise sur le site https://immersion-facile.beta.gouv.fr\n\
***Rédigez ici votre email de motivation en suivant nos conseils.***\n\
\n\
Pourriez-vous me contacter par mail pour me proposer un rendez-vous ? \n\
Pourriez-vous me contacter par mail ou par téléphone pour me proposer un rendez-vous ? \n\
Je pourrais alors vous expliquer directement mon projet. \n\
\n\
En vous remerciant,";
En vous remerciant,`;

export const ContactByEmail = ({
siret,
offer,
onSuccess,
onClose,
}: ContactByEmailProps) => {
const initialValues: ContactEstablishmentByMailDto = {
siret,
Expand All @@ -44,6 +48,9 @@ export const ContactByEmail = ({
potentialBeneficiaryLastName: "",
potentialBeneficiaryEmail: "",
message: initialMessage,
immersionObjective: "",
potentialBeneficiaryLinkedinOrCv: "",
potentialBeneficiaryPhone: "",
};

const methods = useForm<ContactEstablishmentByMailDto>({
Expand All @@ -68,50 +75,128 @@ export const ContactByEmail = ({
<FormProvider {...methods}>
<form onSubmit={handleSubmit(onFormValid)}>
<>
<p className={fr.cx("fr-pb-3w")}>
<p>
Cette entreprise a choisi d'être contactée par mail. Veuillez
compléter ce formulaire qui sera transmis à l'entreprise.
</p>
<EmailValidationInput
label="Votre email *"
nativeInputProps={{
...register("potentialBeneficiaryEmail"),
type: "email",
<hr />
<Alert
severity="info"
small
description={
<div>
Besoin d’aide ? {""}
<a href="https://aide.immersion-facile.beta.gouv.fr/fr/article/choisir-lobjet-et-rediger-un-email-de-motivation-pour-decrocher-une-immersion-xytzii/">
Nos conseils pour choisir l’objet et rédiger un bon email de
motivation.
</a>
</div>
}
className={fr.cx("fr-mt-1w")}
/>

<h2 className={fr.cx("fr-h6", "fr-pt-3w")}>
Votre email de motivation
</h2>

<Select
label={
"Objet de la période de mise en situation en milieu professionnel *"
}
options={immersionObjectiveListOfOptions}
placeholder={"Sélectionnez un objet"}
nativeSelectProps={{
...register("immersionObjective"),
}}
{...getFieldError("potentialBeneficiaryEmail")}
{...getFieldError("immersionObjective")}
/>

<Input
label="Votre message à l’entreprise *"
textArea
nativeTextAreaProps={{
...register("message"),
rows: 6,
}}
{...getFieldError("message")}
/>
<h2 className={fr.cx("fr-h6")}>Vos informations</h2>

<Input
label="Votre prénom *"
label="Prénom *"
nativeInputProps={register("potentialBeneficiaryFirstName")}
{...getFieldError("potentialBeneficiaryFirstName")}
/>
<Input
label="Votre nom *"
label="Nom *"
nativeInputProps={register("potentialBeneficiaryLastName")}
{...getFieldError("potentialBeneficiaryLastName")}
/>
<EmailValidationInput
label="Email *"
nativeInputProps={{
...register("potentialBeneficiaryEmail"),
type: "email",
}}
{...getFieldError("potentialBeneficiaryEmail")}
/>

<Input
label="Votre message *"
textArea
nativeTextAreaProps={{
...register("message"),
rows: 6,
label="Téléphone *"
nativeInputProps={{
...register("potentialBeneficiaryPhone"),
type: "phone",
}}
{...getFieldError("message")}
{...getFieldError("potentialBeneficiaryPhone")}
/>

<Button
priority="secondary"
type="submit"
disabled={isSubmitting}
nativeButtonProps={{
id: domElementIds.search.contactByMailButton,
<Input
label="Page LinkedIn ou CV en ligne (facultatif)"
nativeInputProps={{
...register("potentialBeneficiaryLinkedinOrCv"),
}}
>
Envoyer
</Button>
/>

<ButtonsGroup
className={fr.cx()}
alignment="right"
inlineLayoutWhen="always"
buttons={[
{
type: "button",
priority: "secondary",
onClick: onClose,
nativeButtonProps: {
id: domElementIds.search.contactByMailCloseButton,
},
children: "Annuler et revenir à la recherche",
},
{
type: "submit",
priority: "primary",
disabled: isSubmitting,
nativeButtonProps: {
id: domElementIds.search.contactByMailButton,
},
children: "Envoyer",
},
]}
/>
</>
</form>
</FormProvider>
);
};

const immersionObjective: ImmersionObjective[] = [
"Confirmer un projet professionnel",
"Découvrir un métier ou un secteur d'activité",
"Initier une démarche de recrutement",
];

export const immersionObjectiveListOfOptions = immersionObjective.map(
(immersionObjective) => ({
value: immersionObjective,
label: immersionObjective,
}),
);
16 changes: 14 additions & 2 deletions front/src/app/components/search/ContactModalContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type ContactModalContentProps = {
offer: RomeDto;
searchResultData?: SearchImmersionResultDto;
onSuccess: () => void;
onClose: () => void;
};

export const ModalContactContent = ({
Expand All @@ -23,19 +24,30 @@ export const ModalContactContent = ({
offer,
onSuccess,
searchResultData,
onClose,
}: ContactModalContentProps) => {
switch (contactMethod) {
case "EMAIL":
return (
<ContactByEmail siret={siret} offer={offer} onSuccess={onSuccess} />
<ContactByEmail
siret={siret}
offer={offer}
onSuccess={onSuccess}
onClose={onClose}
/>
);
case "PHONE":
return (
<ContactByPhone siret={siret} offer={offer} onSuccess={onSuccess} />
);
case "IN_PERSON":
return (
<ContactByEmail siret={siret} offer={offer} onSuccess={onSuccess} />
<ContactByEmail
siret={siret}
offer={offer}
onSuccess={onSuccess}
onClose={onClose}
/>
);
default:
return <AdvisesForContact data={searchResultData} />;
Expand Down
7 changes: 6 additions & 1 deletion front/src/app/components/search/SearchListResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export const SearchListResults = () => {
},
contactMethod: searchResult.contactMode,
searchResultData: searchResult,
onClose: () => closeContactModal(),
});
openContactModal();
}}
Expand Down Expand Up @@ -164,9 +165,10 @@ export const SearchListResults = () => {
<ContactModal
title={
modalContent?.contactMethod
? "Contactez l'entreprise"
? `Contactez l'entreprise ${modalContent.searchResultData?.name}`
: "Tentez votre chance !"
}
size="large"
>
{modalContent && (
<ModalContactContent
Expand All @@ -178,6 +180,9 @@ export const SearchListResults = () => {
setSuccessfullyValidated(true);
closeContactModal();
}}
onClose={() => {
closeContactModal();
}}
/>
)}
</ContactModal>
Expand Down
Loading

0 comments on commit a98b16a

Please sign in to comment.