From f3921773771d8ef30dea90b720bbaf0e16448617 Mon Sep 17 00:00:00 2001 From: Alan Le Ruyet Date: Tue, 18 Jun 2024 14:53:26 +0200 Subject: [PATCH] feat: LBA-2255 enregistrement du caller pour l'utilisation du widget pour les envois de candidatures (#1299) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: ajustement gestion d'erreurs * feat: restauration transmission caller * feat: caller restauré ok * fix: typing * feat: openapi * feat: masquage caller dans openapi --- .../controllers/application.controller.v2.ts | 2 +- server/src/services/application.service.ts | 2 +- shared/constants/errorCodes.ts | 2 +- shared/models/applications.model.ts | 2 +- shared/routes/application.routes.v2.ts | 9 +++- .../CandidatureLba/CandidatureLbaFailed.tsx | 5 +++ .../CandidatureLba/WidgetCandidatureLba.tsx | 3 +- .../CandidatureLba/WidgetPostuler.tsx | 43 +++++++++---------- .../CandidatureLba/WidgetPostulerError.tsx | 6 ++- .../services/submitCandidature.ts | 3 ++ 10 files changed, 46 insertions(+), 31 deletions(-) diff --git a/server/src/http/controllers/application.controller.v2.ts b/server/src/http/controllers/application.controller.v2.ts index 750e041a20..cba1c5c569 100644 --- a/server/src/http/controllers/application.controller.v2.ts +++ b/server/src/http/controllers/application.controller.v2.ts @@ -38,7 +38,7 @@ export default function (server: Server) { bodyLimit: 5 * 1024 ** 2, // 5MB }, async (req, res) => { - await sendApplicationV2({ newApplication: req.body }) + await sendApplicationV2({ newApplication: req.body, caller: req.body.caller || undefined }) return res.status(200).send({}) } ) diff --git a/server/src/services/application.service.ts b/server/src/services/application.service.ts index 182c4c2c6f..e6635327e0 100644 --- a/server/src/services/application.service.ts +++ b/server/src/services/application.service.ts @@ -270,7 +270,7 @@ export const sendApplicationV2 = async ({ const recruteurEmail = (type === LBA_ITEM_TYPE.OFFRES_EMPLOI_LBA ? recruiter.email : job.email)?.toLowerCase() if (!recruteurEmail) { - sentryCaptureException(`Aucun email trouver pour l'offre trouvé. ${type === LBA_ITEM_TYPE.OFFRES_EMPLOI_LBA ? `recruiter: ${recruiter._id} ` : `LbaCompany: ${job._id}`}`) + sentryCaptureException(`${BusinessErrorCodes.INTERNAL_EMAIL} ${type === LBA_ITEM_TYPE.OFFRES_EMPLOI_LBA ? `recruiter: ${recruiter._id} ` : `LbaCompany: ${job._id}`}`) throw Boom.internal(BusinessErrorCodes.INTERNAL_EMAIL) } try { diff --git a/shared/constants/errorCodes.ts b/shared/constants/errorCodes.ts index 8263579b97..eecf48ca20 100644 --- a/shared/constants/errorCodes.ts +++ b/shared/constants/errorCodes.ts @@ -13,5 +13,5 @@ export enum BusinessErrorCodes { BURNER = "L'email est invalide.", NOTFOUND = "Aucune offre correspondante trouvée.", ATTACHMENT = "Pièce jointe invalide.", - INTERNAL_EMAIL = "Aucun email trouver pour l'offre trouvé.", + INTERNAL_EMAIL = "Aucun email pour l'offre trouvée.", } diff --git a/shared/models/applications.model.ts b/shared/models/applications.model.ts index a7b935ffc0..576249770e 100644 --- a/shared/models/applications.model.ts +++ b/shared/models/applications.model.ts @@ -88,7 +88,7 @@ export const ZApplication = z }), to_applicant_message_id: z.string().nullable().describe("Identifiant chez le transporteur du mail envoyé au candidat"), to_company_message_id: z.string().nullable().describe("Identifiant chez le transporteur du mail envoyé à l'entreprise"), - caller: z.string().nullable().describe("L'identification de la source d'émission de la candidature (pour widget et api)"), + caller: z.string().nullish().describe("L'identification de la source d'émission de la candidature"), created_at: z.date().nullable().describe("La date création de la demande"), last_update_at: z.date().nullable().describe("Date de dernières mise à jour"), }) diff --git a/shared/routes/application.routes.v2.ts b/shared/routes/application.routes.v2.ts index 793c35e632..0fb7c53adf 100644 --- a/shared/routes/application.routes.v2.ts +++ b/shared/routes/application.routes.v2.ts @@ -36,6 +36,13 @@ const ZNewApplicationV2NEWJobId = ZApplication.pick({ applicant_first_name: true }) .openapi("V2 - Application") +const ZNewApplicationV2NEWCompanySiretPrivate = ZNewApplicationV2NEWCompanySiret.extend({ + caller: z.string().nullish().describe("L'identification de la source d'émission de la candidature (pour widget uniquement)"), +}) +const ZNewApplicationV2NEWJobIdPrivate = ZNewApplicationV2NEWJobId.extend({ + caller: z.string().nullish().describe("L'identification de la source d'émission de la candidature (pour widget uniquement)"), +}) + export type INewApplicationV2NEWCompanySiret = z.output export type INewApplicationV2NEWJobId = z.output @@ -61,7 +68,7 @@ export const zApplicationRoutesV2 = { "/_private/application": { path: "/_private/application", method: "post", - body: z.union([ZNewApplicationV2NEWCompanySiret, ZNewApplicationV2NEWJobId]), + body: z.union([ZNewApplicationV2NEWCompanySiretPrivate, ZNewApplicationV2NEWJobIdPrivate]), response: { "200": z.object({}), }, diff --git a/ui/components/ItemDetail/CandidatureLba/CandidatureLbaFailed.tsx b/ui/components/ItemDetail/CandidatureLba/CandidatureLbaFailed.tsx index a6597df4d2..8e22ea2190 100644 --- a/ui/components/ItemDetail/CandidatureLba/CandidatureLbaFailed.tsx +++ b/ui/components/ItemDetail/CandidatureLba/CandidatureLbaFailed.tsx @@ -46,6 +46,11 @@ const sendingStateValues = { text: "Vous pourrez en envoyer de nouveau demain", dataTestId: "CandidatureSpontaneeFailedTooManyApplicationsPerCompanyPerCaller", }, + [BusinessErrorCodes.INTERNAL_EMAIL]: { + title: "Aucune information de contact disponible pour postuler", + text: "Nous ne disposons pas des éléments de contact nécessaires pour relayer votre candidatuer à cette entreprise", + dataTestId: "CandidatureSpontaneeFailedNoEmail", + }, "Internal Server Error": { title: "Erreur technique", text: "Veuillez patienter quelques instants et réessayer. Si l'erreur persiste merci de nous contacter.", diff --git a/ui/components/ItemDetail/CandidatureLba/WidgetCandidatureLba.tsx b/ui/components/ItemDetail/CandidatureLba/WidgetCandidatureLba.tsx index cdbb0346ba..2a8f196dcc 100644 --- a/ui/components/ItemDetail/CandidatureLba/WidgetCandidatureLba.tsx +++ b/ui/components/ItemDetail/CandidatureLba/WidgetCandidatureLba.tsx @@ -13,7 +13,7 @@ import hasAlreadySubmittedCandidature from "./services/hasAlreadySubmittedCandid import submitCandidature from "./services/submitCandidature" import useLocalStorage from "./services/useLocalStorage" -const WidgetCandidatureLba = ({ item, fakeLocalStorage = null }) => { +const WidgetCandidatureLba = ({ item, caller, fakeLocalStorage = null }) => { const [sendingState, setSendingState] = useState("not_sent") const kind: LBA_ITEM_TYPE_OLD = item?.ideaType || "" @@ -55,6 +55,7 @@ const WidgetCandidatureLba = ({ item, fakeLocalStorage = null }) => { formValues, setSendingState, LbaJob: item, + caller, }) if (success) { setApplied(Date.now().toString()) diff --git a/ui/components/ItemDetail/CandidatureLba/WidgetPostuler.tsx b/ui/components/ItemDetail/CandidatureLba/WidgetPostuler.tsx index 8748867ad3..727bb5a4e1 100644 --- a/ui/components/ItemDetail/CandidatureLba/WidgetPostuler.tsx +++ b/ui/components/ItemDetail/CandidatureLba/WidgetPostuler.tsx @@ -24,29 +24,25 @@ const WidgetPostuler = () => { const fetchPostulerItem = async (parameters) => { let item = null - switch (parameters.type) { - case LBA_ITEM_TYPE_OLD.MATCHA: { - item = await fetchLbaJobDetails({ id: parameters.itemId }) - break - } - case LBA_ITEM_TYPE_OLD.LBA: { - item = await fetchLbaCompanyDetails({ id: parameters.itemId }) - break - } - default: { - assertUnreachable("shouldNotHappen" as never) - break - } - } - - if (item) { - if (!item?.contact?.email || !item?.contact?.iv) { - setHasError("missing_email") - } else { - setItem(item) + try { + switch (parameters.type) { + case LBA_ITEM_TYPE_OLD.MATCHA: { + item = await fetchLbaJobDetails({ id: parameters.itemId }) + break + } + case LBA_ITEM_TYPE_OLD.LBA: { + item = await fetchLbaCompanyDetails({ id: parameters.itemId }) + break + } + default: { + assertUnreachable("shouldNotHappen" as never) + break + } } - } else { - setHasError("item_not_found") + setCaller(parameters.caller) + setItem(item) + } catch (err) { + setHasError(err.message) } setIsLoading(false) @@ -55,6 +51,7 @@ const WidgetPostuler = () => { const [isLoading, setIsLoading] = useState(true) const [hasError, setHasError] = useState(null) const [item, setItem] = useState(null) + const [caller, setCaller] = useState(null) return hasError ? ( @@ -64,7 +61,7 @@ const WidgetPostuler = () => { Veuillez patienter ) : ( - + ) } diff --git a/ui/components/ItemDetail/CandidatureLba/WidgetPostulerError.tsx b/ui/components/ItemDetail/CandidatureLba/WidgetPostulerError.tsx index 5f68befc0d..b6bcfa144b 100644 --- a/ui/components/ItemDetail/CandidatureLba/WidgetPostulerError.tsx +++ b/ui/components/ItemDetail/CandidatureLba/WidgetPostulerError.tsx @@ -1,14 +1,16 @@ +import { BusinessErrorCodes } from "@/../shared/constants/errorCodes" import { Box } from "@chakra-ui/react" import React from "react" const WidgetPostulerError = ({ hasError }) => { const getErrorText = () => { switch (hasError) { + case "Société non trouvée": case "item_not_found": { return "L'offre n'est plus disponible" } - case "missing_email": { - return "Nous ne disposons pas des informations permettant de postuler en ligne." + case BusinessErrorCodes.INTERNAL_EMAIL: { + return "Les informations de contact disponibles ne permettent pas de postuler auprès de cette société." } case "missing_caller_parameter": { return "La source de l'appel au service est manquante (caller)." diff --git a/ui/components/ItemDetail/CandidatureLba/services/submitCandidature.ts b/ui/components/ItemDetail/CandidatureLba/services/submitCandidature.ts index ba54194a2c..9707e9a2da 100644 --- a/ui/components/ItemDetail/CandidatureLba/services/submitCandidature.ts +++ b/ui/components/ItemDetail/CandidatureLba/services/submitCandidature.ts @@ -6,10 +6,12 @@ export default async function submitCandidature({ formValues, setSendingState, LbaJob = {}, + caller, }: { formValues: any // TODO setSendingState: (state: string) => void LbaJob?: any // TODO + caller?: string }) { setSendingState("currently_sending") @@ -23,6 +25,7 @@ export default async function submitCandidature({ applicant_file_content: formValues.fileContent, company_siret: LbaJob.ideaType === LBA_ITEM_TYPE_OLD.LBA ? LbaJob.company?.siret : undefined, // either company_siret or job_id job_id: LbaJob.ideaType === LBA_ITEM_TYPE_OLD.MATCHA ? LbaJob.job?.id : undefined, // either company_siret or job_id + caller, } try {