Skip to content

Commit

Permalink
fix: search cc tracking (#6373)
Browse files Browse the repository at this point in the history
* fix: tracking manquant recherche cc

* chore: clean

* fix: test e2e ajout useeffect

* fix: ajout tracking particulier employeur

---------

Co-authored-by: victor <[email protected]>
  • Loading branch information
Viczei and victor authored Dec 18, 2024
1 parent 9bbdd41 commit ff6095d
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { useState } from "react";
import Button from "@codegouvfr/react-dsfr/Button";
import { ButtonStyle } from "../style";
import { AgreementSearchInput } from "./AgreementSearchInput";
import { useAgreementSearchTracking } from "../tracking";

export const AgreementSearch = () => {
const [noResult, setNoResult] = useState(false);
const { emitPreviousEvent } = useAgreementSearchTracking();
return (
<>
<AgreementSearchInput
Expand All @@ -17,7 +19,10 @@ export const AgreementSearch = () => {
/>
<div className={fr.cx("fr-mt-2w")}>
<Button
linkProps={{ href: "/outils/convention-collective" }}
linkProps={{
href: "/outils/convention-collective",
onClick: emitPreviousEvent,
}}
priority="secondary"
className={ButtonStyle}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export const AgreementSearchInput = ({ onSearch }: Props) => {
"noSearch" | "lowSearch" | "notFoundSearch" | "errorSearch" | "fullSearch"
>("noSearch");
const [error, setError] = useState("");
const { emitAgreementSearchInputEvent } = useAgreementSearchTracking();
const { emitAgreementSearchInputEvent, emitSelectEvent } =
useAgreementSearchTracking();
const getStateMessage = () => {
switch (searchState) {
case "lowSearch":
Expand Down Expand Up @@ -73,6 +74,11 @@ export const AgreementSearchInput = ({ onSearch }: Props) => {
lineAsLink={(item) => {
return `/${getRouteBySource(SOURCES.CCN)}/${item.slug}`;
}}
onChange={(agreement) => {
if (agreement) {
emitSelectEvent(`idcc${agreement.id}`);
}
}}
search={searchAgreement}
onSearch={(query, agreements) => {
if (query) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"use client";
import { fr } from "@codegouvfr/react-dsfr";
import Button from "@codegouvfr/react-dsfr/Button";
import { css } from "@styled-system/css";
import { useAgreementSearchTracking } from "../tracking";
import { useEffect } from "react";

type Props = {
navigationUrl?: string;
Expand All @@ -9,6 +12,14 @@ type Props = {
export const AgreementSearchIntro = ({
navigationUrl = "/outils/convention-collective",
}: Props) => {
const {
emitNavigateEnterpriseSearchEvent,
emitNavigateAgreementSearchEvent,
emitViewStepEvent,
} = useAgreementSearchTracking();
useEffect(() => {
emitViewStepEvent();
});
return (
<>
<div className={`${fr.cx("fr-mt-2w", "fr-ml-md-15v")}`}>
Expand Down Expand Up @@ -48,6 +59,7 @@ export const AgreementSearchIntro = ({
iconId="fr-icon-arrow-right-line"
linkProps={{
href: `${navigationUrl}/convention`,
onClick: emitNavigateAgreementSearchEvent,
}}
>
Je connais ma convention collective je la saisis
Expand All @@ -64,6 +76,7 @@ export const AgreementSearchIntro = ({
iconId="fr-icon-arrow-right-line"
linkProps={{
href: `${navigationUrl}/entreprise`,
onClick: emitNavigateEnterpriseSearchEvent,
}}
>
Je cherche mon entreprise pour trouver ma convention collective
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ jest.mock("../search", () => ({
searchAgreement: jest.fn(),
}));

jest.mock("next/navigation", () => ({
redirect: jest.fn(),
}));

describe("Trouver sa CC - recherche par nom de CC", () => {
describe("Test de l'autocomplete", () => {
let rendering: RenderResult;
Expand All @@ -28,7 +32,7 @@ describe("Trouver sa CC - recherche par nom de CC", () => {
jest.resetAllMocks();
rendering = render(<AgreementSearch />);
});
it("Vérifier le déroulement de la liste & effacement", async () => {
it("Vérifier la navigation", async () => {
(searchAgreement as jest.Mock).mockImplementation(() =>
Promise.resolve([
{
Expand All @@ -47,7 +51,7 @@ describe("Trouver sa CC - recherche par nom de CC", () => {
userAction.setInput(ui.searchByName.input.get(), "16");
await wait();
expect(sendEvent).toHaveBeenCalledTimes(1);
expect(sendEvent).toHaveBeenCalledWith({
expect(sendEvent).toHaveBeenLastCalledWith({
action: "Trouver sa convention collective",
category: "cc_search",
name: '{"query":"16"}',
Expand All @@ -61,9 +65,20 @@ describe("Trouver sa CC - recherche par nom de CC", () => {
"href",
"/convention-collective/16-transports-routiers-et-activites-auxiliaires-du-transport"
);
expect(ui.searchByName.input.get()).toHaveValue("16");
userAction.click(ui.searchByName.inputCloseBtn.get());
expect(ui.searchByName.input.get()).toHaveValue("");
userAction.click(ui.searchByName.autocompleteLines.IDCC16.link.get());
expect(sendEvent).toHaveBeenCalledTimes(2);
expect(sendEvent).toHaveBeenLastCalledWith({
action: "Trouver sa convention collective",
category: "cc_select_p1",
name: "idcc0016",
});
userAction.click(ui.searchByName.buttonPrevious.get());
expect(sendEvent).toHaveBeenCalledTimes(3);
expect(sendEvent).toHaveBeenLastCalledWith({
action: "back_step_cc_search_p1",
category: "view_step_cc_search_p1",
name: "Trouver sa convention collective",
});
});
it("Vérifier l'affichage des erreurs", async () => {
(searchAgreement as jest.Mock).mockImplementation(() =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { render, RenderResult } from "@testing-library/react";
import React from "react";
import { ui } from "./ui";
import { UserAction } from "src/common";
import { sendEvent } from "../../utils";
import { AgreementSearchIntro } from "../AgreementSearch";

jest.mock("../../utils", () => ({
sendEvent: jest.fn(),
}));

jest.mock("uuid", () => ({
v4: jest.fn(() => {}),
}));

describe("Trouver sa CC - intro", () => {
let rendering: RenderResult;
let userAction: UserAction;
beforeEach(() => {
jest.resetAllMocks();
});
it("Vérifier le tracking à l'arrivée", async () => {
rendering = render(<AgreementSearchIntro />);
expect(sendEvent).toHaveBeenLastCalledWith({
action: "view_step_Trouver sa convention collective",
category: "outil",
name: "start",
});
});
it("Vérifier le tracking vers recherche CC", async () => {
rendering = render(<AgreementSearchIntro />);
userAction = new UserAction();
userAction.click(ui.searchAgreementIntro.buttonSearchAgreement.get());
expect(sendEvent).toHaveBeenLastCalledWith({
action: "click_p1",
category: "cc_search_type_of_users",
name: "Trouver sa convention collective",
});
});

it("Vérifier le tracking vers recherche entreprise", async () => {
rendering = render(<AgreementSearchIntro />);
userAction = new UserAction();
userAction.click(ui.searchAgreementIntro.buttonSearchEnterprise.get());
expect(sendEvent).toHaveBeenLastCalledWith({
action: "click_p2",
category: "cc_search_type_of_users",
name: "Trouver sa convention collective",
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@ import {
} from "testing-library-selector";

export const ui = {
searchAgreementIntro: {
buttonSearchAgreement: byRole("link", {
name: "Je connais ma convention collective je la saisis",
}),
buttonSearchEnterprise: byRole("link", {
name: "Je cherche mon entreprise pour trouver ma convention collective",
}),
},
searchByName: {
input: byLabelText(
/Nom de la convention collective ou son numéro d’identification IDCC \(4 chiffres\)/
),
inputCloseBtn: byTestId("AgreementSearchAutocomplete-autocomplete-close"),
buttonPrevious: byRole("link", {
name: "Précédent",
}),
autocompleteLines: {
IDCC16: {
name: byText(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,87 @@
import { v4 as generateUUID } from "uuid";
import { sendEvent } from "../utils";

export enum TrackingAgreementSearchEvent {
export enum TrackingAgreementSearchCategory {
CC_SEARCH = "cc_search",
CC_SEARCH_TYPE_OF_USERS = "cc_search_type_of_users",
ENTERPRISE_SEARCH = "enterprise_search",
VIEW_STEP = "view_step_Trouver sa convention collective",
CC_SELECT_P1 = "cc_select_p1",
CC_SELECT_P2 = "cc_select_p2",
CC_ENTERPRISE_SELECT = "enterprise_select",
VIEW_STEP_CC_SEARCH_P1 = "view_step_cc_search_p1",
VIEW_STEP_CC_SEARCH_P2 = "view_step_cc_search_p2",
}

export const AGREEMENT_SEARCH_ACTION = "Trouver sa convention collective";
export enum TrackingAgreementSearchAction {
AGREEMENT_SEARCH = "Trouver sa convention collective",
CLICK_P1 = "click_p1",
CLICK_P2 = "click_p2",
BACK_STEP_P1 = "back_step_cc_search_p1",
BACK_STEP_P2 = "back_step_cc_search_p2",
CLICK_NO_COMPANY = "click_je_n_ai_pas_d_entreprise",
}

export const useAgreementSearchTracking = () => {
const emitAgreementSearchInputEvent = (query: string) => {
sendEvent({
category: TrackingAgreementSearchEvent.CC_SEARCH,
action: AGREEMENT_SEARCH_ACTION,
category: TrackingAgreementSearchCategory.CC_SEARCH,
action: TrackingAgreementSearchAction.AGREEMENT_SEARCH,
name: JSON.stringify({ query }),
value: generateUUID(),
});
};

const emitViewStepEvent = () => {
sendEvent({
category: "outil",
action: `view_step_${TrackingAgreementSearchAction.AGREEMENT_SEARCH}`,
name: "start",
});
};

const emitNavigateAgreementSearchEvent = (): undefined => {
sendEvent({
category: TrackingAgreementSearchCategory.CC_SEARCH_TYPE_OF_USERS,
action: TrackingAgreementSearchAction.CLICK_P1,
name: TrackingAgreementSearchAction.AGREEMENT_SEARCH,
value: generateUUID(),
});
};

const emitNavigateEnterpriseSearchEvent = (): undefined => {
sendEvent({
category: TrackingAgreementSearchCategory.CC_SEARCH_TYPE_OF_USERS,
action: TrackingAgreementSearchAction.CLICK_P2,
name: TrackingAgreementSearchAction.AGREEMENT_SEARCH,
value: generateUUID(),
});
};

const emitSelectEvent = (idcc: string) => {
sendEvent({
category: TrackingAgreementSearchCategory.CC_SELECT_P1,
action: TrackingAgreementSearchAction.AGREEMENT_SEARCH,
name: idcc,
value: generateUUID(),
});
};

const emitPreviousEvent = () => {
sendEvent({
category: TrackingAgreementSearchCategory.VIEW_STEP_CC_SEARCH_P1,
action: TrackingAgreementSearchAction.BACK_STEP_P1,
name: TrackingAgreementSearchAction.AGREEMENT_SEARCH,
value: generateUUID(),
});
};

return {
emitAgreementSearchInputEvent,
emitViewStepEvent,
emitNavigateAgreementSearchEvent,
emitNavigateEnterpriseSearchEvent,
emitSelectEvent,
emitPreviousEvent,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Button from "@codegouvfr/react-dsfr/Button";
import { ButtonStyle } from "../../convention-collective/style";
import { EnterpriseAgreementSearchInput } from "./EnterpriseAgreementSearchInput";
import { useSearchParams } from "next/navigation";
import { useEnterpriseAgreementSearchTracking } from "./tracking";

type Props = {
widgetMode?: boolean;
Expand All @@ -15,6 +16,7 @@ export const EnterpriseAgreementSearch = ({ widgetMode = false }: Props) => {
const defaultSearch = searchParams?.get("q") ?? undefined;
const cp = searchParams?.get("cp");
const defaultLocation = cp ? JSON.parse(atob(cp)) : undefined;
const { emitPreviousEvent } = useEnterpriseAgreementSearchTracking();
return (
<>
<EnterpriseAgreementSearchInput
Expand All @@ -25,7 +27,10 @@ export const EnterpriseAgreementSearch = ({ widgetMode = false }: Props) => {
{!widgetMode && (
<div className={fr.cx("fr-mt-2w")}>
<Button
linkProps={{ href: "/outils/convention-collective" }}
linkProps={{
href: "/outils/convention-collective",
onClick: emitPreviousEvent,
}}
priority="secondary"
className={ButtonStyle}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ export const EnterpriseAgreementSearchInput = ({
const [searchState, setSearchState] = useState<
"noSearch" | "notFoundSearch" | "errorSearch" | "fullSearch" | "required"
>("noSearch");
const { emitEnterpriseAgreementSearchInputEvent } =
useEnterpriseAgreementSearchTracking();
const {
emitEnterpriseAgreementSearchInputEvent,
emitSelectEnterpriseEvent,
emitNoEnterpriseEvent,
} = useEnterpriseAgreementSearchTracking();

const [search, setSearch] = useState<string | undefined>(defaultSearch);
const [loading, setLoading] = useState<boolean>(false);
Expand Down Expand Up @@ -251,6 +254,9 @@ export const EnterpriseAgreementSearchInput = ({
href: widgetMode
? `/widgets/convention-collective/entreprise/${enterprise.siren}${getQueries()}`
: `/outils/convention-collective/entreprise/${enterprise.siren}${getQueries()}`,
onClick: () => {
emitSelectEnterpriseEvent(enterprise);
},
}}
desc={
enterprise.activitePrincipale ? (
Expand Down Expand Up @@ -286,6 +292,9 @@ export const EnterpriseAgreementSearchInput = ({
linkProps={{
href: `/convention-collective/3239-particuliers-employeurs-et-emploi-a-domicile`,
...(widgetMode ? { target: "_blank" } : {}),
onClick: () => {
emitNoEnterpriseEvent();
},
}}
title="Particuliers employeurs et emploi à domicile"
desc="Retrouvez les questions-réponses les plus fréquentes organisées par thème et élaborées par le Ministère du travail concernant cette convention collective"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Enterprise } from "../types";
import { ButtonStyle, CardTitleStyle } from "../../convention-collective/style";
import { css } from "@styled-system/css";
import { useSearchParams } from "next/navigation";
import { useEnterpriseAgreementSearchTracking } from "./tracking";

type Props = {
enterprise: Omit<Enterprise, "complements">;
Expand All @@ -17,6 +18,8 @@ export const EnterpriseAgreementSelection = ({
widgetMode = false,
}: Props) => {
const searchParams = useSearchParams();
const { emitSelectEnterpriseAgreementEvent } =
useEnterpriseAgreementSearchTracking();
return (
<>
<h2 className={fr.cx("fr-h4", "fr-mt-2w", "fr-mb-0")}>
Expand Down Expand Up @@ -64,6 +67,9 @@ export const EnterpriseAgreementSelection = ({
...(!disabled
? {
href: `/convention-collective/${agreement.slug}`,
onClick: () => {
emitSelectEnterpriseAgreementEvent(`idcc${agreement.id}`);
},
}
: {
href: "#",
Expand Down
Loading

0 comments on commit ff6095d

Please sign in to comment.