diff --git a/package.json b/package.json index 6bb20401a..9a57a7606 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nosgestesclimat-site-nextjs", "license": "MIT", - "version": "2.9.4", + "version": "2.10.0", "description": "The leading open source climate footprint calculator", "repository": { "type": "git", @@ -37,7 +37,7 @@ "dependencies": { "@babel/runtime": "^7.23.1", "@incubateur-ademe/legal-pages-react": "^0.2.0", - "@incubateur-ademe/nosgestesclimat": "3.5.1", + "@incubateur-ademe/nosgestesclimat": "3.5.4", "@mdx-js/loader": "^3.0.0", "@mdx-js/react": "^3.0.0", "@next/bundle-analyzer": "^14.1.0", @@ -67,6 +67,7 @@ "next": "14.2.7", "next-i18n-router": "^4.1.1", "postcss": "8.4.36", + "posthog-js": "^1.217.2", "process": "^0.11.10", "publicodes": "1.4.0", "qrcode.react": "^3.1.0", diff --git a/public/demo-iframeLazy.html b/public/demo-iframeLazy.html new file mode 100644 index 000000000..84b947668 --- /dev/null +++ b/public/demo-iframeLazy.html @@ -0,0 +1,24 @@ + + + + + + Demo Iframe Lazy + + +
+

iframe paramétré

+

+ Ci-dessous, nosgestesclimat.fr intégré comme un iframe paramétré. Son + chargement est déclenché lorsque l'utilisateur interagit avec la page. + Veuillez vous déplacer vers le bas de la page pour voir l'intégration. +

+
+
+ +
+ + diff --git a/public/demo-iframeSimulationHomepage.html b/public/demo-iframeSimulationHomepage.html new file mode 100644 index 000000000..89233e108 --- /dev/null +++ b/public/demo-iframeSimulationHomepage.html @@ -0,0 +1,29 @@ + + + + + + Demo Iframe Simulation with Homepage + + +
+

+ Exemple d'intégration du test avec région fixée par l'intégrateur. +

+

+ Ci-dessous, nosgestesclimat.fr intégré comme un iframe paramétré pour + afficher uniquement le parcours utilisateur du test Nos Gestes Climat, + de la page d'accueil à la page de résultats. +

+

La hauteur de l'iframe est fixée à 500px.

+
+
+ +
+ + diff --git a/public/iframe.js b/public/iframe.js index c2b64da37..1bab82a85 100644 --- a/public/iframe.js +++ b/public/iframe.js @@ -2,6 +2,10 @@ const script = document.getElementById('ecolab-climat') || document.getElementById('nosgestesclimat') +if (!script) { + console.error('Iframe Nos Gestes Climat: No target element found') +} + const integratorUrl = encodeURIComponent(window.location.href.toString()) const srcURL = new URL(script.src) diff --git a/public/iframeSimulation.js b/public/iframeSimulation.js index 382bd3035..ba931d263 100644 --- a/public/iframeSimulation.js +++ b/public/iframeSimulation.js @@ -2,6 +2,10 @@ const script = document.getElementById('ecolab-climat') || document.getElementById('nosgestesclimat') +if (!script) { + console.error('Iframe Nos Gestes Climat: No target element found') +} + const integratorUrl = encodeURIComponent(window.location.href.toString()) const srcURL = new URL(script.src) @@ -13,24 +17,35 @@ const possibleOptions = [ { key: 'lang' }, { key: 'onlySimulation' }, { key: 'pr' }, + { key: 'withHomepage' }, + { key: 'maxHeight' }, ] const lang = script.dataset.lang const url = new URL(hostname) -url.pathname = `/${lang ? lang + '/' : ''}simulateur/bilan` +// Check if withHomepage is true +const withHomepage = script.dataset.withHomepage + +if (withHomepage) { + url.pathname = `/${lang ? lang + '/accueil-iframe' : 'accueil-iframe'}` +} else { + url.pathname = `/${lang ? lang + '/' : ''}simulateur/bilan` +} url.searchParams.append('iframe', 'true') url.searchParams.append('integratorUrl', integratorUrl) -possibleOptions.forEach(({ key, legacy }) => { - const value = script.dataset[key] || script.dataset[legacy] +possibleOptions + .filter(({ key }) => key !== 'maxHeight') + .forEach(({ key, legacy }) => { + const value = script.dataset[key] || script.dataset[legacy] - if (value) { - url.searchParams.append(key === 'pr' ? 'PR' : key, value) - } -}) + if (value) { + url.searchParams.append(key === 'pr' ? 'PR' : key, value) + } + }) const iframe = document.createElement('iframe') @@ -41,7 +56,9 @@ const iframeAttributes = { mozallowfullscreen: true, allow: 'fullscreen', id: 'iframeNGC', - style: 'border: none; width: 100%; display: block; height: 801px;', + style: `border: none; width: 100%; display: block; height: 801px; ${ + script.dataset.maxHeight ? `max-height: ${script.dataset.maxHeight}px;` : '' + }`, } for (var key in iframeAttributes) { @@ -49,12 +66,3 @@ for (var key in iframeAttributes) { } script.parentNode.insertBefore(iframe, script) - -window.addEventListener('message', function (evt) { - if ( - evt.data.kind === 'resize-height' && - iframe.style.height !== `${evt.data.value}px` - ) { - iframe.style.height = `${evt.data.value}px` - } -}) diff --git a/public/images/actions/README.md b/public/images/actions/README.md deleted file mode 100644 index aef7a1273..000000000 --- a/public/images/actions/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Notamment pour les fiches action plus, qui sont illustrées pour aller plus loin. - -Les images sont déployées à l'adresse suivante par exemple https://ecolab-data.netlify.app/images/alternative_bas_carbone.svg diff --git a/src/app/(large-layout)/stats/_components/StatsContent.tsx b/src/app/(large-layout)/stats/_components/StatsContent.tsx index 70fd6c1c8..fb9b40efb 100644 --- a/src/app/(large-layout)/stats/_components/StatsContent.tsx +++ b/src/app/(large-layout)/stats/_components/StatsContent.tsx @@ -12,7 +12,7 @@ import { useCurrentMonthWebsites, useGetSharedSimulationEvents, } from '@/helpers/matomo' -import { useNumberSubscribers } from '@/hooks/useNumberSubscriber' +import { useMainNewsletter } from '@/hooks/useMainNewsletter' import type { UseQueryResult } from '@tanstack/react-query' import AcquisitionBlock from './content/AcquisitionBlock' import MetabaseIframe from './content/MetabaseIframe' @@ -70,7 +70,7 @@ export default function StatsContent() { const currentMonthWebsites = useCurrentMonthWebsites() const currentMonthSocials = useCurrentMonthSocials() const allSharedSimulationEvents = useGetSharedSimulationEvents() - const allSubscribers = useNumberSubscribers() + const { data: mainNewsletter } = useMainNewsletter() return (
@@ -127,7 +127,7 @@ export default function StatsContent() { currentMonthIframeVisitsData, ]) => (
- - {formatValue(allSubscribers?.data, locale)} - {' '} + {!!mainNewsletter && ( + + {formatValue(mainNewsletter.totalSubscribers, locale)} + + )}

inscrits à l'infolettre

diff --git a/src/app/(simulation)/(large-layout)/actions/[...dottedName]/_components/ActionDetail.tsx b/src/app/(simulation)/(large-layout)/actions/[...dottedName]/_components/ActionDetail.tsx index 679c2ca35..5e97acb8c 100644 --- a/src/app/(simulation)/(large-layout)/actions/[...dottedName]/_components/ActionDetail.tsx +++ b/src/app/(simulation)/(large-layout)/actions/[...dottedName]/_components/ActionDetail.tsx @@ -14,7 +14,7 @@ import { useTempEngine, useUser, } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName, NGCRuleNode } from '@incubateur-ademe/nosgestesclimat' import { utils } from 'publicodes' import ActionForm from '../../_components/actionsContent/actions/ActionForm' diff --git a/src/app/(simulation)/(large-layout)/actions/_components/ActionsTutorial.tsx b/src/app/(simulation)/(large-layout)/actions/_components/ActionsTutorial.tsx index 28c085040..67c519b71 100644 --- a/src/app/(simulation)/(large-layout)/actions/_components/ActionsTutorial.tsx +++ b/src/app/(simulation)/(large-layout)/actions/_components/ActionsTutorial.tsx @@ -8,7 +8,7 @@ import Emoji from '@/design-system/utils/Emoji' import { getCarbonFootprint } from '@/helpers/actions/getCarbonFootprint' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useCurrentSimulation, useEngine, useUser } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function ActionsTutorial() { const { t, i18n } = useClientTranslation() diff --git a/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/AllerPlusLoin.tsx b/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/AllerPlusLoin.tsx index dec8b85c6..d769800ba 100644 --- a/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/AllerPlusLoin.tsx +++ b/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/AllerPlusLoin.tsx @@ -6,7 +6,7 @@ import Trans from '@/components/translation/Trans' import { actionsClickAdeme } from '@/constants/tracking/pages/actions' import Card from '@/design-system/layout/Card' import { useClientTranslation } from '@/hooks/useClientTranslation' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function AllerPlusLoin() { const { t } = useClientTranslation() diff --git a/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/actions/ActionCard.tsx b/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/actions/ActionCard.tsx index 3aa5ab326..42186d155 100644 --- a/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/actions/ActionCard.tsx +++ b/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/actions/ActionCard.tsx @@ -26,7 +26,7 @@ import { useTempEngine, useUser, } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { encodeRuleName } from '@/utils/publicodes/encodeRuleName' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import { useCallback } from 'react' diff --git a/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/actions/ActionList.tsx b/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/actions/ActionList.tsx index 9d6325dec..1bdf7167d 100644 --- a/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/actions/ActionList.tsx +++ b/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/actions/ActionList.tsx @@ -8,7 +8,7 @@ import { useEngine, useUser, } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { Fragment } from 'react' import ActionCard from './ActionCard' import ActionForm from './ActionForm' diff --git a/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/categoryFilters/Filter.tsx b/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/categoryFilters/Filter.tsx index 41b84746b..2895902d2 100644 --- a/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/categoryFilters/Filter.tsx +++ b/src/app/(simulation)/(large-layout)/actions/_components/actionsContent/categoryFilters/Filter.tsx @@ -7,7 +7,7 @@ import { getTextDarkColor, } from '@/helpers/getCategoryColorClass' import { useRule } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import { useRouter, useSearchParams } from 'next/navigation' diff --git a/src/app/(simulation)/(large-layout)/amis/creer/vos-informations/_component/GroupCreationForm.tsx b/src/app/(simulation)/(large-layout)/amis/creer/vos-informations/_component/GroupCreationForm.tsx index 26c290feb..df532db3d 100644 --- a/src/app/(simulation)/(large-layout)/amis/creer/vos-informations/_component/GroupCreationForm.tsx +++ b/src/app/(simulation)/(large-layout)/amis/creer/vos-informations/_component/GroupCreationForm.tsx @@ -7,8 +7,8 @@ import EmailInput from '@/design-system/inputs/EmailInput' import PrenomInput from '@/design-system/inputs/PrenomInput' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useUser } from '@/publicodes-state' +import { trackEvent } from '@/utils/analytics/trackEvent' import { formatEmail } from '@/utils/format/formatEmail' -import { trackEvent } from '@/utils/matomo/trackEvent' import { useRouter } from 'next/navigation' import { useForm as useReactHookForm } from 'react-hook-form' diff --git a/src/app/(simulation)/(large-layout)/amis/creer/votre-groupe/_components/NameForm.tsx b/src/app/(simulation)/(large-layout)/amis/creer/votre-groupe/_components/NameForm.tsx index 0d171ae8d..dac3fc186 100644 --- a/src/app/(simulation)/(large-layout)/amis/creer/votre-groupe/_components/NameForm.tsx +++ b/src/app/(simulation)/(large-layout)/amis/creer/votre-groupe/_components/NameForm.tsx @@ -11,8 +11,8 @@ import { useEndPage } from '@/hooks/navigation/useEndPage' import { useSimulateurPage } from '@/hooks/navigation/useSimulateurPage' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useCurrentSimulation, useUser } from '@/publicodes-state' +import { trackEvent } from '@/utils/analytics/trackEvent' import { formatEmail } from '@/utils/format/formatEmail' -import { trackEvent } from '@/utils/matomo/trackEvent' import { captureException } from '@sentry/react' import { useSearchParams } from 'next/navigation' import { useEffect, useState } from 'react' diff --git a/src/app/(simulation)/(large-layout)/amis/resultats/_components/EditableGroupTitle.tsx b/src/app/(simulation)/(large-layout)/amis/resultats/_components/EditableGroupTitle.tsx index e70551ad7..64a0ed119 100644 --- a/src/app/(simulation)/(large-layout)/amis/resultats/_components/EditableGroupTitle.tsx +++ b/src/app/(simulation)/(large-layout)/amis/resultats/_components/EditableGroupTitle.tsx @@ -14,7 +14,7 @@ import { useIsGroupOwner } from '@/hooks/groups/useIsGroupOwner' import { useUpdateGroup } from '@/hooks/groups/useUpdateGroup' import { useClientTranslation } from '@/hooks/useClientTranslation' import type { Group } from '@/types/groups' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { captureException } from '@sentry/react' import { useState } from 'react' diff --git a/src/app/(simulation)/(large-layout)/amis/resultats/_components/groupResults/InviteBlock.tsx b/src/app/(simulation)/(large-layout)/amis/resultats/_components/groupResults/InviteBlock.tsx index 73ed3d63e..9aca40db1 100644 --- a/src/app/(simulation)/(large-layout)/amis/resultats/_components/groupResults/InviteBlock.tsx +++ b/src/app/(simulation)/(large-layout)/amis/resultats/_components/groupResults/InviteBlock.tsx @@ -5,7 +5,7 @@ import { amisDashboardCopyLink } from '@/constants/tracking/pages/amisDashboard' import Button from '@/design-system/inputs/Button' import Emoji from '@/design-system/utils/Emoji' import type { Group } from '@/types/groups' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useEffect, useRef, useState } from 'react' const SubmitButton = ({ diff --git a/src/app/(simulation)/(large-layout)/amis/resultats/_components/groupResults/OwnerAdminSection.tsx b/src/app/(simulation)/(large-layout)/amis/resultats/_components/groupResults/OwnerAdminSection.tsx index 6abbd2f85..bec524d2c 100644 --- a/src/app/(simulation)/(large-layout)/amis/resultats/_components/groupResults/OwnerAdminSection.tsx +++ b/src/app/(simulation)/(large-layout)/amis/resultats/_components/groupResults/OwnerAdminSection.tsx @@ -12,7 +12,7 @@ import { linkToClassement } from '@/helpers/navigation/classementPages' import { useDeleteGroup } from '@/hooks/groups/useDeleteGroup' import { useUser } from '@/publicodes-state' import type { Group } from '@/types/groups' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { captureException } from '@sentry/react' import { useRouter } from 'next/navigation' import { useEffect, useRef, useState } from 'react' diff --git a/src/app/(simulation)/(large-layout)/classements/_components/Organisations/CreateOrganisation.tsx b/src/app/(simulation)/(large-layout)/classements/_components/Organisations/CreateOrganisation.tsx index b8d876333..11176b630 100644 --- a/src/app/(simulation)/(large-layout)/classements/_components/Organisations/CreateOrganisation.tsx +++ b/src/app/(simulation)/(large-layout)/classements/_components/Organisations/CreateOrganisation.tsx @@ -5,7 +5,7 @@ import Trans from '@/components/translation/Trans' import { classementCreateOrganisation } from '@/constants/tracking/pages/classements' import ButtonLink from '@/design-system/inputs/ButtonLink' import type { Organisation } from '@/types/organisations' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' type Props = { organisations?: Organisation[] diff --git a/src/app/(simulation)/(large-layout)/classements/_components/Organisations/pollList/OrganisationItem.tsx b/src/app/(simulation)/(large-layout)/classements/_components/Organisations/pollList/OrganisationItem.tsx index 43d1badbc..76e049f36 100644 --- a/src/app/(simulation)/(large-layout)/classements/_components/Organisations/pollList/OrganisationItem.tsx +++ b/src/app/(simulation)/(large-layout)/classements/_components/Organisations/pollList/OrganisationItem.tsx @@ -6,7 +6,7 @@ import Trans from '@/components/translation/Trans' import { classementClickOrganisation } from '@/constants/tracking/pages/classements' import Badge from '@/design-system/layout/Badge' import type { Organisation } from '@/types/organisations' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function OrganisationItem({ organisation, diff --git a/src/app/(simulation)/(large-layout)/classements/_components/Organisations/pollList/PollItem.tsx b/src/app/(simulation)/(large-layout)/classements/_components/Organisations/pollList/PollItem.tsx index faa9ae95a..ed26e4975 100644 --- a/src/app/(simulation)/(large-layout)/classements/_components/Organisations/pollList/PollItem.tsx +++ b/src/app/(simulation)/(large-layout)/classements/_components/Organisations/pollList/PollItem.tsx @@ -6,7 +6,7 @@ import Trans from '@/components/translation/Trans' import { classementClickOrganisation } from '@/constants/tracking/pages/classements' import { getLinkToPollDashboard } from '@/helpers/navigation/pollPages' import type { Organisation, OrganisationPoll } from '@/types/organisations' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' type Props = { organisation: Organisation diff --git a/src/app/(simulation)/(large-layout)/classements/_components/groups/createOtherGroupsSection/groupList/GroupItem.tsx b/src/app/(simulation)/(large-layout)/classements/_components/groups/createOtherGroupsSection/groupList/GroupItem.tsx index c5fc7c9f6..16cd0ae83 100644 --- a/src/app/(simulation)/(large-layout)/classements/_components/groups/createOtherGroupsSection/groupList/GroupItem.tsx +++ b/src/app/(simulation)/(large-layout)/classements/_components/groups/createOtherGroupsSection/groupList/GroupItem.tsx @@ -8,7 +8,7 @@ import Emoji from '@/design-system/utils/Emoji' import { getLinkToGroupDashboard } from '@/helpers/navigation/groupPages' import { useUser } from '@/publicodes-state' import type { Group } from '@/types/groups' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' type Props = { group: Group diff --git a/src/app/(simulation)/(large-layout)/infos/_components/Navigation.tsx b/src/app/(simulation)/(large-layout)/infos/_components/Navigation.tsx index 8e08d0683..c7e1b8198 100644 --- a/src/app/(simulation)/(large-layout)/infos/_components/Navigation.tsx +++ b/src/app/(simulation)/(large-layout)/infos/_components/Navigation.tsx @@ -16,7 +16,7 @@ import { import Button from '@/design-system/inputs/Button' import ButtonLink from '@/design-system/inputs/ButtonLink' import { useClientTranslation } from '@/hooks/useClientTranslation' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' type Props = { linkToPrev: string diff --git a/src/app/(simulation)/(large-layout)/infos/commencer/page.tsx b/src/app/(simulation)/(large-layout)/infos/commencer/page.tsx index fb78be751..2233eea80 100644 --- a/src/app/(simulation)/(large-layout)/infos/commencer/page.tsx +++ b/src/app/(simulation)/(large-layout)/infos/commencer/page.tsx @@ -13,7 +13,7 @@ import Emoji from '@/design-system/utils/Emoji' import { useSimulateurPage } from '@/hooks/navigation/useSimulateurPage' import { usePollQueryParams } from '@/hooks/organisations/usePollQueryParams' import { useCurrentSimulation } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useContext, useEffect, useState } from 'react' import { InfosContext } from '../_components/InfosProvider' diff --git a/src/app/(simulation)/(large-layout)/infos/email/page.tsx b/src/app/(simulation)/(large-layout)/infos/email/page.tsx index bc7111e18..82c557789 100644 --- a/src/app/(simulation)/(large-layout)/infos/email/page.tsx +++ b/src/app/(simulation)/(large-layout)/infos/email/page.tsx @@ -7,8 +7,8 @@ import Title from '@/design-system/layout/Title' import { useInfosPage } from '@/hooks/navigation/useInfosPage' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useUser } from '@/publicodes-state' +import { trackPageView } from '@/utils/analytics/trackEvent' import { isEmailValid } from '@/utils/isEmailValid' -import { trackPageView } from '@/utils/matomo/trackEvent' import { useRouter, useSearchParams } from 'next/navigation' import { useCallback, useEffect } from 'react' import { useForm as useReactHookForm } from 'react-hook-form' diff --git a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/_components/OurTools.tsx b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/_components/OurTools.tsx index 495ddf6a4..90b560f27 100644 --- a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/_components/OurTools.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/_components/OurTools.tsx @@ -10,7 +10,7 @@ import { import ButtonLink from '@/design-system/inputs/ButtonLink' import Title from '@/design-system/layout/Title' import { useClientTranslation } from '@/hooks/useClientTranslation' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import CTACard from './CTACard' export default function OurTools() { diff --git a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/AdminSection.tsx b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/AdminSection.tsx index 4514d3c1f..68f3bc331 100644 --- a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/AdminSection.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/AdminSection.tsx @@ -13,7 +13,7 @@ import CopyInput from '@/design-system/inputs/CopyInput' import useFetchOrganisation from '@/hooks/organisations/useFetchOrganisation' import { useUser } from '@/publicodes-state' import type { PublicOrganisationPoll } from '@/types/organisations' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useParams } from 'next/navigation' type Props = { diff --git a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/pollStatisticsFilters/AgeFilter.tsx b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/pollStatisticsFilters/AgeFilter.tsx index b48c8d05c..bbc5b905b 100644 --- a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/pollStatisticsFilters/AgeFilter.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/pollStatisticsFilters/AgeFilter.tsx @@ -3,7 +3,7 @@ import { organisationsResultatsDetaillesFilterByAge } from '@/constants/tracking import ComplexSelect from '@/design-system/inputs/ComplexSelect' import { getAgeFilterOptions } from '@/helpers/organisations/getAgeFilterOptions' import type { Simulation } from '@/types/organisations' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { SetStateAction } from 'react' import { useContext } from 'react' import type { MultiValue, SingleValue } from 'react-select' diff --git a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/pollStatisticsFilters/DepartementFilter.tsx b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/pollStatisticsFilters/DepartementFilter.tsx index 6f7b10c65..81bc43904 100644 --- a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/pollStatisticsFilters/DepartementFilter.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/_components/pollStatisticsFilters/DepartementFilter.tsx @@ -3,7 +3,7 @@ import { organisationsResultatsDetaillesFilterByPostalCode } from '@/constants/t import ComplexSelect from '@/design-system/inputs/ComplexSelect' import { extractPostalCodesFromSimulations } from '@/helpers/organisations/extractPostalCodesFromSimulations' import type { Simulation } from '@/types/organisations' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { SetStateAction } from 'react' import { useContext } from 'react' import type { MultiValue, SingleValue } from 'react-select' diff --git a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/parametres/_components/NameForm.tsx b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/parametres/_components/NameForm.tsx index 9e60cb168..3e4a067f9 100644 --- a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/parametres/_components/NameForm.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/parametres/_components/NameForm.tsx @@ -2,17 +2,20 @@ import Trans from '@/components/translation/Trans' import Button from '@/design-system/inputs/Button' import TextInputGroup from '@/design-system/inputs/TextInputGroup' import type { PollToUpdate } from '@/hooks/organisations/polls/useUpdatePoll' +import { useClientTranslation } from '@/hooks/useClientTranslation' import { useEffect } from 'react' import { useForm as useReactHookForm } from 'react-hook-form' type Props = { nameValue: string + expectedNumberOfParticipants?: number updatePoll: (pollToUpdate: PollToUpdate) => void updatePollStatus: string } export default function NameForm({ nameValue, + expectedNumberOfParticipants, updatePoll, updatePollStatus, }: Props) { @@ -24,12 +27,29 @@ export default function NameForm({ } = useReactHookForm({ defaultValues: { name: nameValue, + expectedNumberOfParticipants, }, }) - async function onSubmit(data: { name: string }) { + const { t } = useClientTranslation() + + async function onSubmit({ + name, + expectedNumberOfParticipants: newExpectedNumberOfParticipants, + }: { + name: string + expectedNumberOfParticipants?: number + }) { updatePoll({ - name: data.name, + name, + expectedNumberOfParticipants: + newExpectedNumberOfParticipants !== undefined + ? newExpectedNumberOfParticipants + : // If the expectedNumberOfParticipants is empty, we set it to undefined + // otherwise reset its value to null + expectedNumberOfParticipants + ? null + : undefined, }) } @@ -56,7 +76,7 @@ export default function NameForm({ e.preventDefault() } }> -
+
+ + Nombre de participants attendus + + {' '} + facultatif + +

+ } + value={expectedNumberOfParticipants} + type="number" + {...register('expectedNumberOfParticipants', { + valueAsNumber: true, + min: { + value: 1, + message: t('Le nombre de participants doit être supérieur à 0'), + }, + })} + error={errors.expectedNumberOfParticipants?.message} + />
diff --git a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/parametres/page.tsx b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/parametres/page.tsx index 1c916c86f..9a3160fa3 100644 --- a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/parametres/page.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/campagnes/[pollSlug]/parametres/page.tsx @@ -61,6 +61,9 @@ export default function ParametresPage() { diff --git a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/creer-campagne/_components/PollForm.tsx b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/creer-campagne/_components/PollForm.tsx index 357627d83..408c425f7 100644 --- a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/creer-campagne/_components/PollForm.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/creer-campagne/_components/PollForm.tsx @@ -16,6 +16,7 @@ type Props = { type Inputs = { name: string + expectedNumberOfParticipants: number } export default function PollForm({ organisation }: Props) { @@ -30,23 +31,20 @@ export default function PollForm({ organisation }: Props) { const { t } = useClientTranslation() const { + handleSubmit, register, formState: { errors }, - getValues, } = useReactHookForm() const { mutateAsync: createPoll } = useCreatePoll(organisation.slug) - async function onSubmit() { - if (isError) setIsError(false) - - const { name } = getValues() - + async function onSubmit({ expectedNumberOfParticipants, name }: Inputs) { try { const pollCreated = await createPoll({ name, defaultAdditionalQuestions: pollInfo.defaultAdditionalQuestions, customAdditionalQuestions: pollInfo.customAdditionalQuestions, + expectedNumberOfParticipants: expectedNumberOfParticipants || undefined, }) if (pollCreated) { @@ -62,14 +60,39 @@ export default function PollForm({ organisation }: Props) { return ( <> - Nom de la campagne} - placeholder={t('ex : Campagne 2024, Classe de 6ème A, etc.')} - {...register('name', { - required: t('Ce champ est requis'), - })} - error={errors.name?.message} - /> +
+
+ Nom de la campagne} + placeholder={t('ex : Campagne 2024, Classe de 6ème A, etc.')} + {...register('name', { + required: t('Ce champ est requis'), + })} + error={errors.name?.message} + /> + + + Nombre de participants attendus + + {' '} + facultatif + +

+ } + type="number" + {...register('expectedNumberOfParticipants', { + valueAsNumber: true, + min: { + value: 1, + message: t('Le nombre de participants doit être supérieur à 0'), + }, + })} + error={errors.expectedNumberOfParticipants?.message} + /> +
+
)} - diff --git a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/page.tsx b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/page.tsx index 2ed79aed4..8fd6367a5 100644 --- a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/page.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/page.tsx @@ -5,6 +5,7 @@ import OrganisationFetchError from '@/components/organisations/OrganisationFetch import Trans from '@/components/translation/Trans' import { organisationsDashboardClickParameters } from '@/constants/tracking/pages/organisationsDashboard' import ButtonLink from '@/design-system/inputs/ButtonLink' +import { unformatAdministratorName } from '@/helpers/organisations/unformatAdministratorName' import { useFetchPolls } from '@/hooks/organisations/polls/useFetchPolls' import useFetchOrganisation from '@/hooks/organisations/useFetchOrganisation' import { capitalizeString } from '@/utils/capitalizeString' @@ -44,7 +45,11 @@ export default function OrganisationPage() { Bienvenue{' '} - {capitalizeString(organisation.administrators[0].name || '')} + {capitalizeString( + unformatAdministratorName( + organisation.administrators[0].name || '' + ) + )} , diff --git a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/parametres/DeconnexionButton.tsx b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/parametres/DeconnexionButton.tsx index 26143bf7e..def69a1cf 100644 --- a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/parametres/DeconnexionButton.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/parametres/DeconnexionButton.tsx @@ -5,7 +5,7 @@ import Trans from '@/components/translation/Trans' import { organisationsParametersLogout } from '@/constants/tracking/pages/organisationsParameters' import Button from '@/design-system/inputs/Button' import { useLogout } from '@/hooks/authentication/useLogout' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useQueryClient } from '@tanstack/react-query' import { useRouter } from 'next/navigation' diff --git a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/parametres/_components/OrganisationFields.tsx b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/parametres/_components/OrganisationFields.tsx index 7808c9a84..baa80b1e4 100644 --- a/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/parametres/_components/OrganisationFields.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/[orgaSlug]/parametres/_components/OrganisationFields.tsx @@ -31,19 +31,11 @@ export default function OrganisationFields({ {...register('name')} /> - Type d'organisation{' '} - - {' '} - facultatif - -

- } - {...register('organisationType')}> - {/* Empty option to reset field */} - + containerClassName="pt-[3px]" + label={Type d'organisation} + error={formState.errors.organisationType?.message} + {...register('organisationType', { + required: t('Ce champ est requis'), + })}> {Object.entries(ORGANISATION_TYPES).map(([key, value]) => (
)}
+
+ + + +
+ Votre prénom} + error={formState.errors.administratorFirstName?.message} + {...register('administratorFirstName', { + required: t('Ce champ est requis'), + })} + /> Votre nom} - error={formState.errors.administratorName?.message} - {...register('administratorName', { - required: t('Vous devez renseigner votre nom'), + error={formState.errors.administratorLastName?.message} + {...register('administratorLastName', { + required: t('Ce champ est requis'), })} /> + + + Votre poste + + facultatif + +

+ } + {...register('administratorPosition')} + />
{isErrorUpdateOrga && ( diff --git a/src/app/(simulation)/(large-layout)/organisations/creer/page.tsx b/src/app/(simulation)/(large-layout)/organisations/creer/page.tsx index 7295354b4..c7cf28105 100644 --- a/src/app/(simulation)/(large-layout)/organisations/creer/page.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/creer/page.tsx @@ -22,6 +22,7 @@ export default function CreationPage() { Bienvenue sur votre espace !</Trans>} subtitle={<Trans>Plus que quelques petites questions</Trans>} + hasSeparator={false} /> <CreationForm /> diff --git a/src/app/(simulation)/(large-layout)/organisations/layout.tsx b/src/app/(simulation)/(large-layout)/organisations/layout.tsx index bfcbeb28d..6105eda1f 100644 --- a/src/app/(simulation)/(large-layout)/organisations/layout.tsx +++ b/src/app/(simulation)/(large-layout)/organisations/layout.tsx @@ -22,7 +22,7 @@ export async function generateMetadata() { export default function Layout({ children }: PropsWithChildren) { return ( <div className="bg-white md:-mt-8"> - <FilAriane className="-mt-4 mb-4" /> + <FilAriane className="-mt-4" /> {children} </div> ) diff --git a/src/app/(simulation)/(large-layout)/profil/_components/SimulationList.tsx b/src/app/(simulation)/(large-layout)/profil/_components/SimulationList.tsx index 667734aa2..af2d926d5 100644 --- a/src/app/(simulation)/(large-layout)/profil/_components/SimulationList.tsx +++ b/src/app/(simulation)/(large-layout)/profil/_components/SimulationList.tsx @@ -10,7 +10,7 @@ import { import Button from '@/design-system/inputs/Button' import { useUser } from '@/publicodes-state' import type { Simulation } from '@/publicodes-state/types' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function SimulationList() { const { diff --git a/src/app/(simulation)/(large-layout)/profil/_components/answerList/Category.tsx b/src/app/(simulation)/(large-layout)/profil/_components/answerList/Category.tsx index a2b1e0643..cb9a581b7 100644 --- a/src/app/(simulation)/(large-layout)/profil/_components/answerList/Category.tsx +++ b/src/app/(simulation)/(large-layout)/profil/_components/answerList/Category.tsx @@ -10,7 +10,7 @@ import { } from '@/helpers/getCategoryColorClass' import { getSubcatsOfCategory } from '@/helpers/publicodes/getSubcatsOfCategory' import { useRule, useSimulation } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import { useState } from 'react' import QuestionsWithoutSubcategory from './category/QuestionsWithoutSubcategory' diff --git a/src/app/(simulation)/(large-layout)/profil/_components/answerList/category/Subcategory.tsx b/src/app/(simulation)/(large-layout)/profil/_components/answerList/category/Subcategory.tsx index d3fdf0913..88f04a3e3 100644 --- a/src/app/(simulation)/(large-layout)/profil/_components/answerList/category/Subcategory.tsx +++ b/src/app/(simulation)/(large-layout)/profil/_components/answerList/category/Subcategory.tsx @@ -8,7 +8,7 @@ import { getTextDarkColor, } from '@/helpers/getCategoryColorClass' import { useForm, useRule } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import { useState } from 'react' import Question from './subcategory/Question' diff --git a/src/app/(simulation)/(large-layout)/profil/_components/answerList/category/subcategory/Question.tsx b/src/app/(simulation)/(large-layout)/profil/_components/answerList/category/subcategory/Question.tsx index c34044a72..f1d2d0b4b 100644 --- a/src/app/(simulation)/(large-layout)/profil/_components/answerList/category/subcategory/Question.tsx +++ b/src/app/(simulation)/(large-layout)/profil/_components/answerList/category/subcategory/Question.tsx @@ -7,7 +7,7 @@ import { profilClickQuestion } from '@/constants/tracking/pages/profil' import { getLinkToSimulateur } from '@/helpers/navigation/simulateurPages' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useRule } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import MosaicQuestion from './question/MosaicQuestion' diff --git a/src/app/(simulation)/(large-layout)/profil/_components/localisation/RegionSelector.tsx b/src/app/(simulation)/(large-layout)/profil/_components/localisation/RegionSelector.tsx index 0c319200c..6f8de40d4 100644 --- a/src/app/(simulation)/(large-layout)/profil/_components/localisation/RegionSelector.tsx +++ b/src/app/(simulation)/(large-layout)/profil/_components/localisation/RegionSelector.tsx @@ -19,7 +19,7 @@ import { useClientTranslation } from '@/hooks/useClientTranslation' import { useLocale } from '@/hooks/useLocale' import { useRules } from '@/hooks/useRules' import { useUser } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { SupportedRegions } from '@incubateur-ademe/nosgestesclimat' type Props = { diff --git a/src/app/(simulation)/(large-layout)/quiz/_components/Choices.tsx b/src/app/(simulation)/(large-layout)/quiz/_components/Choices.tsx index 7845416eb..ebd55b182 100644 --- a/src/app/(simulation)/(large-layout)/quiz/_components/Choices.tsx +++ b/src/app/(simulation)/(large-layout)/quiz/_components/Choices.tsx @@ -1,7 +1,7 @@ 'use client' import { quizClickAnswer } from '@/constants/tracking/pages/quiz' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import { useMemo } from 'react' import Choice from './choices/Choice' diff --git a/src/app/(simulation)/(large-layout)/quiz/_components/Navigation.tsx b/src/app/(simulation)/(large-layout)/quiz/_components/Navigation.tsx index 5b8e83b7e..33b62a29e 100644 --- a/src/app/(simulation)/(large-layout)/quiz/_components/Navigation.tsx +++ b/src/app/(simulation)/(large-layout)/quiz/_components/Navigation.tsx @@ -12,7 +12,7 @@ import { getLinkToSimulateur } from '@/helpers/navigation/simulateurPages' import { useEndPage } from '@/hooks/navigation/useEndPage' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useEngine } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' type Props = { answer: string | null @@ -53,7 +53,9 @@ export default function Navigation({ data-cypress-id="button-skip-quiz" onClick={() => { trackEvent( - simulationSimulationCompleted({ bilan: getNumericValue('bilan') }) + simulationSimulationCompleted({ + bilan: getNumericValue('bilan'), + }) ) trackEvent(quizClickPass) }}> @@ -64,11 +66,13 @@ export default function Navigation({ href={getLinkToEndPage({ allowedToGoToGroupDashboard: true, })} - onClick={() => + onClick={() => { trackEvent( - simulationSimulationCompleted({ bilan: getNumericValue('bilan') }) + simulationSimulationCompleted({ + bilan: getNumericValue('bilan'), + }) ) - }> + }}> <Trans>Voir mes résultats →</Trans> </ButtonLink> ) : ( diff --git a/src/app/(simulation)/(large-layout)/quiz/_components/choices/Choice.tsx b/src/app/(simulation)/(large-layout)/quiz/_components/choices/Choice.tsx index 1739ceccf..b6a9ce9d5 100644 --- a/src/app/(simulation)/(large-layout)/quiz/_components/choices/Choice.tsx +++ b/src/app/(simulation)/(large-layout)/quiz/_components/choices/Choice.tsx @@ -4,7 +4,7 @@ import ChoiceInput from '@/components/misc/ChoiceInput' import { quizClickAnswer } from '@/constants/tracking/pages/quiz' import Emoji from '@/design-system/utils/Emoji' import { useRule } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' type Props = { diff --git a/src/app/(simulation)/(large-layout)/quiz/page.tsx b/src/app/(simulation)/(large-layout)/quiz/page.tsx index b79483554..fc272c134 100644 --- a/src/app/(simulation)/(large-layout)/quiz/page.tsx +++ b/src/app/(simulation)/(large-layout)/quiz/page.tsx @@ -9,7 +9,7 @@ import { useQuizGuard } from '@/hooks/navigation/useQuizGuard' import { useSaveQuizAnswer } from '@/hooks/quiz/useSaveQuizAnswer' import { useSortedSubcategoriesByFootprint } from '@/hooks/useSortedSubcategoriesByFootprint' import type { AnswerType } from '@/types/quiz' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import { useMemo, useState } from 'react' import Choices from './_components/Choices' diff --git a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/AgirMainBlock.tsx b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/AgirMainBlock.tsx index eb05fe3fc..cf4535ac0 100644 --- a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/AgirMainBlock.tsx +++ b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/AgirMainBlock.tsx @@ -5,7 +5,7 @@ import Button from '@/design-system/inputs/Button' import Loader from '@/design-system/layout/Loader' import { useExportSituationToAgir } from '@/hooks/simulation/useExportSituationToAgir' import { useClientTranslation } from '@/hooks/useClientTranslation' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import Image from 'next/image' import { useEffect, useState } from 'react' diff --git a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/AgirSecondaryBlock.tsx b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/AgirSecondaryBlock.tsx index 574a01b5a..12bc70d9d 100644 --- a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/AgirSecondaryBlock.tsx +++ b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/AgirSecondaryBlock.tsx @@ -6,7 +6,7 @@ import Badge from '@/design-system/layout/Badge' import Loader from '@/design-system/layout/Loader' import { useExportSituationToAgir } from '@/hooks/simulation/useExportSituationToAgir' import { useClientTranslation } from '@/hooks/useClientTranslation' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import Image from 'next/image' import { useEffect, useState } from 'react' diff --git a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/DocumentationBlock.tsx b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/DocumentationBlock.tsx index 8bb414a22..c075b7761 100644 --- a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/DocumentationBlock.tsx +++ b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/DocumentationBlock.tsx @@ -3,7 +3,7 @@ import Trans from '@/components/translation/Trans' import { endClickDocumentation } from '@/constants/tracking/pages/end' import InlineLink from '@/design-system/inputs/InlineLink' import Title from '@/design-system/layout/Title' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function DocumentationBlock() { return ( diff --git a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/FeedbackBanner.tsx b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/FeedbackBanner.tsx index b063a46e6..dda00008a 100644 --- a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/FeedbackBanner.tsx +++ b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/FeedbackBanner.tsx @@ -9,7 +9,7 @@ import { useSaveNorthstarRating } from '@/hooks/northstar/useSaveNorthstarRating import { useClientTranslation } from '@/hooks/useClientTranslation' import { useUser } from '@/publicodes-state' import type { NorthStarType, NorthStarValue } from '@/types/northstar' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { ReactNode } from 'react' import { twMerge } from 'tailwind-merge' diff --git a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/GetResultsByEmail.tsx b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/GetResultsByEmail.tsx index c26ef458c..017c2d1a8 100644 --- a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/GetResultsByEmail.tsx +++ b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/GetResultsByEmail.tsx @@ -18,13 +18,13 @@ import { useGetNewsletterSubscriptions } from '@/hooks/settings/useGetNewsletter import { useSaveSimulation } from '@/hooks/simulation/useSaveSimulation' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useLocale } from '@/hooks/useLocale' -import { useNumberSubscribers } from '@/hooks/useNumberSubscriber' +import { useMainNewsletter } from '@/hooks/useMainNewsletter' import { useCurrentSimulation, useUser } from '@/publicodes-state' +import { trackEvent } from '@/utils/analytics/trackEvent' import { formatEmail } from '@/utils/format/formatEmail' -import { trackEvent } from '@/utils/matomo/trackEvent' import { captureException } from '@sentry/react' import { useEffect, useRef } from 'react' -import type { SubmitHandler} from 'react-hook-form'; +import type { SubmitHandler } from 'react-hook-form' import { useForm as useReactHookForm } from 'react-hook-form' import { twMerge } from 'tailwind-merge' import Confirmation from './carbone/getResultsByEmail/Confirmation' @@ -100,7 +100,7 @@ export default function GetResultsByEmail({ const { saveSimulation, isPending, isSuccess, isError, error } = useSaveSimulation() - const { data: numberSubscribers } = useNumberSubscribers() + const { data: mainNewsletter } = useMainNewsletter() const onSubmit: SubmitHandler<Inputs> = async (data) => { // If the mutation is pending, we do nothing @@ -175,7 +175,7 @@ export default function GetResultsByEmail({ </strong> {t('comme {{numberSubscribers}} personnes.', { numberSubscribers: - numberSubscribers?.toLocaleString(locale, { + mainNewsletter?.totalSubscribers.toLocaleString(locale, { maximumFractionDigits: 0, }) ?? '---', })} diff --git a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/InformationBlock.tsx b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/InformationBlock.tsx index d579bf008..293b4287b 100644 --- a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/InformationBlock.tsx +++ b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/InformationBlock.tsx @@ -6,7 +6,7 @@ import { carboneMetric } from '@/constants/metric' import { endToggleTargetBlock } from '@/constants/tracking/pages/end' import Button from '@/design-system/inputs/Button' import { useCurrentMetric } from '@/hooks/useCurrentMetric' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useState } from 'react' import { twMerge } from 'tailwind-merge' import CarboneTargetContent from './informationBlock/CarboneTargetContent' diff --git a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/ShareBlock.tsx b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/ShareBlock.tsx index 588cf6ee2..096432e9b 100644 --- a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/ShareBlock.tsx +++ b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/ShareBlock.tsx @@ -3,7 +3,7 @@ import { endClickShare } from '@/constants/tracking/pages/end' import CopyInput from '@/design-system/inputs/CopyInput' import Title from '@/design-system/layout/Title' import { useEndPageSharedUrl } from '@/hooks/useEndPageSharedUrl' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function ShareBlock() { const { sharedUrl } = useEndPageSharedUrl() diff --git a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/carbone/subcategories/subcategory/Actions.tsx b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/carbone/subcategories/subcategory/Actions.tsx index b030596ab..c1312d0a9 100644 --- a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/carbone/subcategories/subcategory/Actions.tsx +++ b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/carbone/subcategories/subcategory/Actions.tsx @@ -2,7 +2,7 @@ import Link from '@/components/Link' import Trans from '@/components/translation/Trans' import { endClickActions } from '@/constants/tracking/pages/end' import { useEngine, useRule } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import Action from './actions/Action' diff --git a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/eau/DomesticWater.tsx b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/eau/DomesticWater.tsx index b29e3f2aa..1e4521d87 100644 --- a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/eau/DomesticWater.tsx +++ b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/eau/DomesticWater.tsx @@ -4,7 +4,7 @@ import Trans from '@/components/translation/Trans' import { endClickDomesticWater } from '@/constants/tracking/pages/end' import Button from '@/design-system/inputs/Button' import Title from '@/design-system/layout/Title' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useState } from 'react' import { twMerge } from 'tailwind-merge' import DomesticWaterContent from './domesticWater/DomesticWaterContent' diff --git a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/informationBlock/Hedgehog.tsx b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/informationBlock/Hedgehog.tsx index 60726e0b0..7d069b49b 100644 --- a/src/app/(simulation)/(large-layout-nosticky)/fin/_components/informationBlock/Hedgehog.tsx +++ b/src/app/(simulation)/(large-layout-nosticky)/fin/_components/informationBlock/Hedgehog.tsx @@ -1,7 +1,7 @@ 'use client' import { endClickHedgehog } from '@/constants/tracking/pages/end' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useEffect, useState } from 'react' import { twMerge } from 'tailwind-merge' diff --git a/src/app/(simulation)/simulateur/[root]/_components/Faq.tsx b/src/app/(simulation)/simulateur/[root]/_components/Faq.tsx index c20a189e9..908187d4d 100644 --- a/src/app/(simulation)/simulateur/[root]/_components/Faq.tsx +++ b/src/app/(simulation)/simulateur/[root]/_components/Faq.tsx @@ -5,7 +5,7 @@ import Trans from '@/components/translation/Trans' import { simulateurClickFaq } from '@/constants/tracking/pages/simulateur' import { useIframe } from '@/hooks/useIframe' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function Faq() { const { isIframeOnlySimulation } = useIframe() diff --git a/src/app/(simulation)/simulateur/[root]/_components/Simulateur.tsx b/src/app/(simulation)/simulateur/[root]/_components/Simulateur.tsx index 5f2941e40..7b61e820b 100644 --- a/src/app/(simulation)/simulateur/[root]/_components/Simulateur.tsx +++ b/src/app/(simulation)/simulateur/[root]/_components/Simulateur.tsx @@ -22,7 +22,7 @@ export default function Simulateur({ } return ( - <div className="flex flex-1 flex-col px-4 pb-16 pt-16 md:pt-20 lg:px-0"> + <div className="flex flex-1 flex-col px-4 py-16 md:pt-20 lg:px-0"> {isQuestionListOpen && ( <Summary toggleQuestionList={toggleQuestionList} diff --git a/src/app/(simulation)/simulateur/[root]/_components/simulateur/Form.tsx b/src/app/(simulation)/simulateur/[root]/_components/simulateur/Form.tsx index b583c255b..461af3a55 100644 --- a/src/app/(simulation)/simulateur/[root]/_components/simulateur/Form.tsx +++ b/src/app/(simulation)/simulateur/[root]/_components/simulateur/Form.tsx @@ -13,7 +13,7 @@ import { useTrackTimeOnSimulation } from '@/hooks/tracking/useTrackTimeOnSimulat import { useDebug } from '@/hooks/useDebug' import { useQuestionInQueryParams } from '@/hooks/useQuestionInQueryParams' import { useCurrentSimulation, useEngine, useForm } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useContext, useEffect, useState } from 'react' import FunFact from './form/FunFact' import ResultsBlocksDesktop from './form/ResultsBlocksDesktop' @@ -56,7 +56,9 @@ export default function Form() { if (!shouldShowQuiz) { trackEvent( - simulationSimulationCompleted({ bilan: getNumericValue('bilan') }) + simulationSimulationCompleted({ + bilan: getNumericValue('bilan'), + }) ) } goToEndPage({ diff --git a/src/app/(simulation)/simulateur/[root]/_components/simulateur/summary/Question.tsx b/src/app/(simulation)/simulateur/[root]/_components/simulateur/summary/Question.tsx index 097064212..c0bea4611 100644 --- a/src/app/(simulation)/simulateur/[root]/_components/simulateur/summary/Question.tsx +++ b/src/app/(simulation)/simulateur/[root]/_components/simulateur/summary/Question.tsx @@ -12,7 +12,7 @@ import { } from '@/helpers/getCategoryColorClass' import { useDebug } from '@/hooks/useDebug' import { useCurrentSimulation, useForm, useRule } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import { twMerge } from 'tailwind-merge' diff --git a/src/app/(simulation)/simulateur/[root]/page.tsx b/src/app/(simulation)/simulateur/[root]/page.tsx index 0ce573078..1e21e2c31 100644 --- a/src/app/(simulation)/simulateur/[root]/page.tsx +++ b/src/app/(simulation)/simulateur/[root]/page.tsx @@ -7,7 +7,7 @@ import { } from '@/constants/tracking/pages/simulateur' import { useSimulateurGuard } from '@/hooks/navigation/useSimulateurGuard' import { useTrackSimulateur } from '@/hooks/tracking/useTrackSimulateur' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useCallback, useState } from 'react' import SaveModal from './_components/SaveModal' import Simulateur from './_components/Simulateur' diff --git a/src/app/(simulation)/tutoriel/_components/AutresQuestions.tsx b/src/app/(simulation)/tutoriel/_components/AutresQuestions.tsx index 6808f698a..3a858777f 100644 --- a/src/app/(simulation)/tutoriel/_components/AutresQuestions.tsx +++ b/src/app/(simulation)/tutoriel/_components/AutresQuestions.tsx @@ -9,7 +9,7 @@ import { tutorielClickQuestion, } from '@/constants/tracking/pages/tutoriel' import ButtonLink from '@/design-system/inputs/ButtonLink' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import Image from 'next/image' import OrganisationPrivacy from './autresQuestions/OrganisationPrivacy' diff --git a/src/app/(simulation)/tutoriel/_components/ButtonBack.tsx b/src/app/(simulation)/tutoriel/_components/ButtonBack.tsx index 4eaef46ed..cecc4db29 100644 --- a/src/app/(simulation)/tutoriel/_components/ButtonBack.tsx +++ b/src/app/(simulation)/tutoriel/_components/ButtonBack.tsx @@ -4,7 +4,7 @@ import Trans from '@/components/translation/Trans' import { tutorielClickPrecedent } from '@/constants/tracking/pages/tutoriel' import ButtonLink from '@/design-system/inputs/ButtonLink' import { useClientTranslation } from '@/hooks/useClientTranslation' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function ButtonBack() { const { t } = useClientTranslation() diff --git a/src/app/(simulation)/tutoriel/_components/ButtonStart.tsx b/src/app/(simulation)/tutoriel/_components/ButtonStart.tsx index 7577e5fa2..80842f33a 100644 --- a/src/app/(simulation)/tutoriel/_components/ButtonStart.tsx +++ b/src/app/(simulation)/tutoriel/_components/ButtonStart.tsx @@ -5,7 +5,7 @@ import { tutorielClickSuivant } from '@/constants/tracking/pages/tutoriel' import ButtonLink from '@/design-system/inputs/ButtonLink' import { useInfosPage } from '@/hooks/navigation/useInfosPage' import { useUser } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useMemo } from 'react' import { useFetchPublicPoll } from '../../../../hooks/organisations/polls/useFetchPublicPoll' diff --git a/src/app/(simulation)/tutoriel/_components/autresQuestions/OrganisationPrivacy.tsx b/src/app/(simulation)/tutoriel/_components/autresQuestions/OrganisationPrivacy.tsx index 717006319..400ce13fc 100644 --- a/src/app/(simulation)/tutoriel/_components/autresQuestions/OrganisationPrivacy.tsx +++ b/src/app/(simulation)/tutoriel/_components/autresQuestions/OrganisationPrivacy.tsx @@ -7,7 +7,7 @@ import Trans from '@/components/translation/Trans' import { tutorielClickQuestion } from '@/constants/tracking/pages/tutoriel' import { usePollQueryParams } from '@/hooks/organisations/usePollQueryParams' import { useClientTranslation } from '@/hooks/useClientTranslation' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function OrganisationPrivacy() { const { pollSlug } = usePollQueryParams() diff --git a/src/app/(simulation)/tutoriel/page.tsx b/src/app/(simulation)/tutoriel/page.tsx index b04b628b6..74635e67a 100644 --- a/src/app/(simulation)/tutoriel/page.tsx +++ b/src/app/(simulation)/tutoriel/page.tsx @@ -32,7 +32,7 @@ export async function generateMetadata() { export default async function Tutoriel() { return ( <ContentLarge className="mt-10 px-4 lg:px-0"> - <div className="mx-auto flex h-screen max-w-3xl flex-col overflow-auto"> + <div className="mx-auto flex max-w-3xl flex-col overflow-auto"> <Title data-cypress-id="tutoriel-title" className="text-lg md:text-2xl" @@ -48,24 +48,15 @@ export default async function Tutoriel() { <AvantDeCommencer /> - <AutresQuestions /> - - {/* Check if body has the "iframe-mode" class name and if so add the static class to the footer */} - <div - className={twMerge( - 'tutorial-footer fixed bottom-0 left-0 right-0 z-50 border-t-2 border-primary-200 bg-gray-100 py-3' - )}> - <div - className={twMerge( - 'relative mx-auto flex w-full max-w-3xl justify-between gap-4 px-4 md:px-0 lg:justify-start' - )}> - <ButtonBack /> + <div className={twMerge('mb-12 flex w-full gap-4 sm:px-4 md:px-0 ')}> + <ButtonBack /> - <OrganisationMessage /> + <OrganisationMessage /> - <ButtonStart /> - </div> + <ButtonStart /> </div> + + <AutresQuestions /> </div> </ContentLarge> ) diff --git a/src/app/_components/MainLayoutProviders.tsx b/src/app/_components/MainLayoutProviders.tsx index eb9ccf2ba..3ca5f31f0 100644 --- a/src/app/_components/MainLayoutProviders.tsx +++ b/src/app/_components/MainLayoutProviders.tsx @@ -8,6 +8,7 @@ import migrationInstructions from '@incubateur-ademe/nosgestesclimat/public/migr import type { PropsWithChildren } from 'react' import { IframeOptionsProvider } from './mainLayoutProviders/IframeOptionsContext' import MainHooks from './mainLayoutProviders/MainHooks' +import { PostHogProvider } from './mainLayoutProviders/PostHogProvider' import { PreventNavigationProvider } from './mainLayoutProviders/PreventNavigationProvider' import QueryClientProviderWrapper from './mainLayoutProviders/QueryClientProviderWrapper' @@ -20,18 +21,24 @@ export default function MainLayoutProviders({ }: PropsWithChildren<Props>) { return ( <ErrorBoundary> - <IframeOptionsProvider> - <QueryClientProviderWrapper> - <UserProvider - storageKey={STORAGE_KEY} - migrationInstructions={migrationInstructions} - initialRegion={initialRegion}> - <PreventNavigationProvider> - <MainHooks>{children}</MainHooks> - </PreventNavigationProvider> - </UserProvider> - </QueryClientProviderWrapper> - </IframeOptionsProvider> + <PostHogProvider> + <IframeOptionsProvider> + {(containerRef: React.RefObject<HTMLDivElement>) => ( + <QueryClientProviderWrapper> + <UserProvider + storageKey={STORAGE_KEY} + migrationInstructions={migrationInstructions} + initialRegion={initialRegion}> + <PreventNavigationProvider> + <MainHooks> + <div ref={containerRef}>{children}</div> + </MainHooks> + </PreventNavigationProvider> + </UserProvider> + </QueryClientProviderWrapper> + )} + </IframeOptionsProvider> + </PostHogProvider> </ErrorBoundary> ) } diff --git a/src/app/_components/mainLayoutProviders/IframeOptionsContext.tsx b/src/app/_components/mainLayoutProviders/IframeOptionsContext.tsx index 464e562c1..918723c41 100644 --- a/src/app/_components/mainLayoutProviders/IframeOptionsContext.tsx +++ b/src/app/_components/mainLayoutProviders/IframeOptionsContext.tsx @@ -1,10 +1,8 @@ 'use client' -import { trackingIframe } from '@/constants/tracking/misc' +import { useTrackIframe } from '@/hooks/tracking/useTrackIframe' import { useIsClient } from '@/hooks/useIsClient' import { getIsIframe } from '@/utils/getIsIframe' -import { trackEvent } from '@/utils/matomo/trackEvent' -import type { PropsWithChildren } from 'react' import { createContext, useEffect, useState } from 'react' export const IframeOptionsContext = createContext<{ @@ -18,7 +16,11 @@ export const IframeOptionsContext = createContext<{ const nullDecode = (string: string) => string == null ? string : decodeURIComponent(string) -export const IframeOptionsProvider = ({ children }: PropsWithChildren) => { +export const IframeOptionsProvider = ({ + children, +}: { + children: (containerRef: React.RefObject<HTMLDivElement>) => JSX.Element +}) => { const isClient = useIsClient() const isIframe = isClient && getIsIframe() @@ -34,26 +36,11 @@ export const IframeOptionsProvider = ({ children }: PropsWithChildren) => { const [isIframeOnlySimulation, setIsIframeOnlySimulation] = useState(false) const [iframeLang, setIframeLang] = useState<string | null>(null) + const containerRef = useTrackIframe(isIframe) + useEffect(() => { const urlParams = new URLSearchParams(window.location.search) - const isIframeParameterDefined = urlParams.get('iframe') !== null - - // Si l'on détecte que l'on est dans un iframe sans paramètre iframe défini - // on essaie de récupérer l'URL du referrer - if (isIframe && !isIframeParameterDefined) { - urlParams.set('iframe', '') - urlParams.set('integratorUrl', document.referrer) - } - - if (isIframe) { - trackEvent( - trackingIframe( - urlParams.get('integratorUrl') || "Pas d'URL d'intégration" - ) - ) - } - setIframeIntegratorOptions( Object.fromEntries( [ @@ -104,7 +91,7 @@ export const IframeOptionsProvider = ({ children }: PropsWithChildren) => { isIframeOnlySimulation, iframeLang, }}> - {children} + {children(containerRef)} </IframeOptionsContext.Provider> ) } diff --git a/src/app/_components/mainLayoutProviders/MainHooks.tsx b/src/app/_components/mainLayoutProviders/MainHooks.tsx index ec168bb34..78dbe6e6a 100644 --- a/src/app/_components/mainLayoutProviders/MainHooks.tsx +++ b/src/app/_components/mainLayoutProviders/MainHooks.tsx @@ -10,7 +10,6 @@ import { useSetCurrentSimulationFromParams } from '@/hooks/simulation/useSetCurr import { useTrackLocale } from '@/hooks/tracking/useTrackLocale' import { useTrackPageView } from '@/hooks/tracking/useTrackPageView' import { useTrackRegion } from '@/hooks/tracking/useTrackRegion' -import { useTrackSplitTesting } from '@/hooks/tracking/useTrackSplitTesting' import { useFixedRegion } from '@/hooks/useFixedRegion' import { useInitSimulationParam } from '@/hooks/useInitSimulationParam' import { useRedirectIfInAppBrowser } from '@/hooks/useRedirectIfInAppBrowser' @@ -19,7 +18,8 @@ import type { PropsWithChildren } from 'react' export default function MainHooks({ children }: PropsWithChildren) { useSetCurrentSimulationFromParams() - useTrackSplitTesting() + // We disable split testing tracking for now + // useTrackSplitTesting() useTrackPageView() useTrackLocale() useTrackRegion() diff --git a/src/app/_components/mainLayoutProviders/PostHogProvider.tsx b/src/app/_components/mainLayoutProviders/PostHogProvider.tsx new file mode 100644 index 000000000..2f1ed86ef --- /dev/null +++ b/src/app/_components/mainLayoutProviders/PostHogProvider.tsx @@ -0,0 +1,23 @@ +// app/providers.jsx +'use client' +import posthog from 'posthog-js' +import { PostHogProvider as PHProvider } from 'posthog-js/react' +import type { PropsWithChildren } from 'react' +import { useEffect } from 'react' + +export function PostHogProvider({ children }: PropsWithChildren) { + useEffect(() => { + if (!process.env.NEXT_PUBLIC_POSTHOG_KEY) { + return + } + posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, { + api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, + person_profiles: 'identified_only', // or 'always' to create profiles for anonymous users as well + autocapture: false, // Disable automatic event capture, as we capture manually + capture_pageview: false, // Disable automatic pageview capture, as we capture manually + capture_pageleave: true, // Enable pageleave capture + }) + }, []) + + return <PHProvider client={posthog}>{children}</PHProvider> +} diff --git a/src/app/_components/mobilise/CreateGroupLink.tsx b/src/app/_components/mobilise/CreateGroupLink.tsx index 5e6adf80d..1b8df1cf3 100644 --- a/src/app/_components/mobilise/CreateGroupLink.tsx +++ b/src/app/_components/mobilise/CreateGroupLink.tsx @@ -3,7 +3,7 @@ import Trans from '@/components/translation/Trans' import { createGroupLink } from '@/constants/tracking/pages/mainLanding' import ButtonLink from '@/design-system/inputs/ButtonLink' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function CreateGroupLink() { return ( diff --git a/src/app/_components/mobilise/CreateOrganisationLink.tsx b/src/app/_components/mobilise/CreateOrganisationLink.tsx index 606d12a2d..c75bac4a0 100644 --- a/src/app/_components/mobilise/CreateOrganisationLink.tsx +++ b/src/app/_components/mobilise/CreateOrganisationLink.tsx @@ -3,7 +3,7 @@ import Trans from '@/components/translation/Trans' import { createOrganisationLink } from '@/constants/tracking/pages/mainLanding' import ButtonLink from '@/design-system/inputs/ButtonLink' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function CreateOrganisationLink() { return ( diff --git a/src/app/_components/twoFootprints/LearnMoreCarbonLink.tsx b/src/app/_components/twoFootprints/LearnMoreCarbonLink.tsx index f2ba371c8..3008d4738 100644 --- a/src/app/_components/twoFootprints/LearnMoreCarbonLink.tsx +++ b/src/app/_components/twoFootprints/LearnMoreCarbonLink.tsx @@ -3,7 +3,7 @@ import Link from '@/components/Link' import Trans from '@/components/translation/Trans' import { learnMoreCarbonLink } from '@/constants/tracking/pages/mainLanding' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function LearnMoreCarbonLink() { return ( diff --git a/src/app/_components/twoFootprints/LearnMoreWaterLink.tsx b/src/app/_components/twoFootprints/LearnMoreWaterLink.tsx index 0a580c010..7abcbf7d5 100644 --- a/src/app/_components/twoFootprints/LearnMoreWaterLink.tsx +++ b/src/app/_components/twoFootprints/LearnMoreWaterLink.tsx @@ -3,7 +3,7 @@ import Link from '@/components/Link' import Trans from '@/components/translation/Trans' import { learnMoreWaterLink } from '@/constants/tracking/pages/mainLanding' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' export default function LearnMoreCarbonLink() { return ( diff --git a/src/app/accueil-iframe/page.tsx b/src/app/accueil-iframe/page.tsx new file mode 100644 index 000000000..21a5412ed --- /dev/null +++ b/src/app/accueil-iframe/page.tsx @@ -0,0 +1,102 @@ +import DynamicCTAButtons from '@/components/cta/DynamicCTAButtons' +import Partners from '@/components/landing-pages/Partners' +import Trans from '@/components/translation/Trans' +import { noIndexObject } from '@/constants/metadata' +import { trackingActionClickCTA } from '@/constants/tracking/actions' +import LandingPage from '@/design-system/layout/LandingPage' +import { getServerTranslation } from '@/helpers/getServerTranslation' +import { getMetadataObject } from '@/helpers/metadata/getMetadataObject' +import { + getLandingClickCTARestart, + getLandingClickCTAResults, + getLandingClickCTAResume, + getLandingClickCTAStart, +} from '@/helpers/tracking/landings' +import { headers } from 'next/headers' +import InteractiveIllustration from '../_components/InteractiveIllustration' + +export async function generateMetadata() { + const { t } = await getServerTranslation() + return getMetadataObject({ + title: t('Calculez votre empreinte carbone et eau en 10 minutes !'), + description: t( + "2 millions de personnes ont déjà calculé leur empreinte sur le climat avec le calculateur Nos Gestes Climat ! Et vous, qu'attendez-vous pour faire le test ?" + ), + image: '/images/misc/calculer-empreinte-carbone-et-eau.png', + alternates: { + canonical: '', + }, + robots: noIndexObject, + }) +} + +export default async function Homepage() { + const headersList = headers() + const pathname = headersList.get('x-pathname') || '/' + + return ( + <> + <LandingPage + heroIllustration={<InteractiveIllustration />} + heroTitle={<Trans>Connaissez-vous votre empreinte écologique ?</Trans>} + heroDescription={ + <div className="flex flex-col items-center gap-6 md:items-start md:gap-10"> + <p className="mb-0 text-base md:order-1 md:text-2xl"> + <Trans> + Calculez votre{' '} + <strong className="text-primary-700">empreinte carbone</strong>{' '} + et votre{' '} + <strong className="text-primary-700">empreinte eau</strong> en{' '} + <strong className="text-secondary-700"> + seulement 10 minutes + </strong> + . + </Trans> + </p> + + <div className="flex flex-col items-center gap-6 md:order-2 md:mt-0 md:max-w-[300px] md:items-start"> + <DynamicCTAButtons + trackingEvents={{ + start: getLandingClickCTAStart( + pathname, + trackingActionClickCTA + ), + resume: getLandingClickCTAResume( + pathname, + trackingActionClickCTA + ), + results: getLandingClickCTAResults( + pathname, + trackingActionClickCTA + ), + restart: getLandingClickCTARestart( + pathname, + trackingActionClickCTA + ), + }} + className="w-full" + /> + + {/* Displayed on mobile only */} + <div className="mx-auto mt-4 max-w-80 md:mt-0 md:hidden"> + <InteractiveIllustration /> + </div> + + {/* Displayed on desktop only */} + <p> + <Trans> + <strong className="text-primary-700"> + 2 millions de personnes + </strong>{' '} + ont déjà calculé leur empreinte ! + </Trans> + </p> + </div> + </div> + } + heroPartners={<Partners />}> + <></> + </LandingPage> + </> + ) +} diff --git a/src/app/api/get-newsletter-subscribers-number/route.ts b/src/app/api/get-newsletter-subscribers-number/route.ts deleted file mode 100644 index 72bb686c2..000000000 --- a/src/app/api/get-newsletter-subscribers-number/route.ts +++ /dev/null @@ -1,25 +0,0 @@ -import axios from 'axios' -import { NextResponse } from 'next/server' - -const axiosConf = { - headers: { - 'api-key': process.env.BREVO_API_KEY, - }, -} - -export async function GET() { - if (!process.env.BREVO_API_KEY) { - return new NextResponse('0', { - status: 200, - }) - } - const listInfos = await axios.get( - 'https://api.brevo.com/v3/contacts/lists/22', - - axiosConf - ) - - return new NextResponse(listInfos?.data.totalSubscribers, { - status: 200, - }) -} diff --git a/src/app/empreinte-carbone/page.tsx b/src/app/empreinte-carbone/page.tsx index 8e587f09c..993dac66c 100644 --- a/src/app/empreinte-carbone/page.tsx +++ b/src/app/empreinte-carbone/page.tsx @@ -1,4 +1,4 @@ -import DynamicCTAButton from '@/components/cta/DynamicCTAButtons' +import CTAButtonsPlaceholder from '@/components/cta/CTAButtonsPlaceholder' import Partners from '@/components/landing-pages/Partners' import JSONLD from '@/components/seo/JSONLD' import Trans from '@/components/translation/Trans' @@ -12,6 +12,7 @@ import { getLandingClickCTAResume, getLandingClickCTAStart, } from '@/helpers/tracking/landings' +import dynamic from 'next/dynamic' import Image from 'next/image' import DailyGestureCarbonFootprint from './_components/DailyGestureCarbonFootprint' import DidYouKnowCarbon from './_components/DidYouKnowCarbonFootprint' @@ -22,6 +23,14 @@ import WhatDoWeMeasureCarbon from './_components/WhatDoWeMeasureCarbonFootprint' import WhatItIsCarbon from './_components/WhatItIsCarbon' import { carbonFAQJsonLd } from './_constants/carbonFAQJsonLd' +const DynamicCTAButtons = dynamic( + () => import('@/components/cta/DynamicCTAButtons'), + { + ssr: false, + loading: () => <CTAButtonsPlaceholder />, + } +) + export async function generateMetadata() { const { t } = await getServerTranslation() @@ -85,7 +94,7 @@ export default function CarbonFootprintLandingPage() { </Trans> </p> <div className="flex w-full justify-center md:justify-start"> - <DynamicCTAButton + <DynamicCTAButtons trackingEvents={{ start: getLandingClickCTAStart( '/empreinte-carbone', diff --git a/src/app/empreinte-eau/page.tsx b/src/app/empreinte-eau/page.tsx index 1ce5ab1c4..fb2eee72f 100644 --- a/src/app/empreinte-eau/page.tsx +++ b/src/app/empreinte-eau/page.tsx @@ -1,4 +1,4 @@ -import DynamicCTAButton from '@/components/cta/DynamicCTAButtons' +import CTAButtonsPlaceholder from '@/components/cta/CTAButtonsPlaceholder' import JSONLD from '@/components/seo/JSONLD' import Trans from '@/components/translation/Trans' import { trackingActionClickCTA } from '@/constants/tracking/actions' @@ -11,6 +11,7 @@ import { getLandingClickCTAResume, getLandingClickCTAStart, } from '@/helpers/tracking/landings' +import dynamic from 'next/dynamic' import Image from 'next/image' import DailyGestureWaterFootprint from './_components/DailyGestureWaterFootprint' import DidYouKnowWaterFootprint from './_components/DidYouKnowWaterFootprint' @@ -22,6 +23,14 @@ import WhatDoWeMeasureWaterFootprint from './_components/WhatDoWeMeasureWaterFoo import WhatItIsWaterFootprint from './_components/WhatItIsWaterFootprint' import { waterFAQJsonLd } from './_constants/waterFAQJsonLd' +const DynamicCTAButtons = dynamic( + () => import('@/components/cta/DynamicCTAButtons'), + { + ssr: false, + loading: () => <CTAButtonsPlaceholder />, + } +) + export async function generateMetadata() { const { t } = await getServerTranslation() @@ -84,7 +93,7 @@ export default async function WaterFootprintLandingPage() { </Trans> </p> <div className="flex w-full justify-center md:justify-start"> - <DynamicCTAButton + <DynamicCTAButtons trackingEvents={{ start: getLandingClickCTAStart( '/empreinte-eau', diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 547775abc..dce8d1d4e 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,20 +1,16 @@ +import ErrorContent from '@/components/error/ErrorContent' import Footer from '@/components/layout/Footer' import { getGeolocation } from '@/helpers/getGeolocation' import '@/locales/initClient' import '@/locales/initServer' import { dir } from 'i18next' import { currentLocale } from 'next-i18n-router' -import dynamic from 'next/dynamic' import localFont from 'next/font/local' import Script from 'next/script' import type { PropsWithChildren } from 'react' import MainLayoutProviders from './_components/MainLayoutProviders' import './globals.css' -const ClientErrorContent = dynamic( - () => import('@/components/error/ErrorContent') -) - export const marianne = localFont({ src: [ { @@ -82,6 +78,7 @@ export default async function RootLayout({ children }: PropsWithChildren) { /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(["setDocumentTitle", document.domain + "/" + document.title]); _paq.push(["setCookieDomain", "*.nosgestesclimat.fr"]); + _paq.push(['setCookieSameSite', 'None']); _paq.push(['enableLinkTracking']); (function() { var u="https://stats.beta.gouv.fr/"; @@ -105,6 +102,7 @@ export default async function RootLayout({ children }: PropsWithChildren) { /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(["setDocumentTitle", document.domain + "/" + document.title]); _paq.push(["setCookieDomain", "*.nosgestesclimat.fr"]); + _paq.push(['setCookieSameSite', 'None']); _paq.push(['enableLinkTracking']); (function() { var u="https://stats.beta.gouv.fr/"; @@ -140,7 +138,7 @@ export default async function RootLayout({ children }: PropsWithChildren) { <html lang="fr"> <body className={`${marianne.className} bg-white text-default`}> <div className="flex h-screen flex-col items-center justify-center"> - <ClientErrorContent /> + <ErrorContent /> </div> </body> </html> diff --git a/src/app/page.tsx b/src/app/page.tsx index 1c16bb01b..755ccb2af 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,4 +1,4 @@ -import DynamicCTAButtons from '@/components/cta/DynamicCTAButtons' +import CTAButtonsPlaceholder from '@/components/cta/CTAButtonsPlaceholder' import JSONLD from '@/components/seo/JSONLD' import Trans from '@/components/translation/Trans' import { trackingActionClickCTA } from '@/constants/tracking/actions' @@ -11,6 +11,7 @@ import { getLandingClickCTAResume, getLandingClickCTAStart, } from '@/helpers/tracking/landings' +import dynamic from 'next/dynamic' import { headers } from 'next/headers' import Partners from '../components/landing-pages/Partners' import CollectivelyCommit from './_components/CollectivelyCommit' @@ -22,6 +23,11 @@ import ModelInfo from './_components/ModelInfo' import TheySpeakAboutUs from './_components/TheySpeakAboutUs' import TwoFootprints from './_components/TwoFootprints' +const DynamicCTAButtons = dynamic( + () => import('@/components/cta/DynamicCTAButtons'), + { ssr: false, loading: () => <CTAButtonsPlaceholder /> } +) + export async function generateMetadata() { const { t } = await getServerTranslation() return getMetadataObject({ diff --git a/src/components/actions/howToAct/recommendedActions/RecommendedAction.tsx b/src/components/actions/howToAct/recommendedActions/RecommendedAction.tsx index ec09a015f..f03fd0233 100644 --- a/src/components/actions/howToAct/recommendedActions/RecommendedAction.tsx +++ b/src/components/actions/howToAct/recommendedActions/RecommendedAction.tsx @@ -8,7 +8,7 @@ import { getBorderColor, } from '@/helpers/getCategoryColorClass' import { useRule } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' export default function RecommendedAction({ diff --git a/src/components/charts/RavijenChart.tsx b/src/components/charts/RavijenChart.tsx index bc552e7e2..312959209 100644 --- a/src/components/charts/RavijenChart.tsx +++ b/src/components/charts/RavijenChart.tsx @@ -5,7 +5,7 @@ import { trackingDownloadRavijenChart } from '@/constants/tracking/misc' import Button from '@/design-system/inputs/Button' import { getSubcatsOfCategory } from '@/helpers/publicodes/getSubcatsOfCategory' import { useEngine } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import { toPng } from 'html-to-image' import CategoryChart from './ravijenChart/CategoryChart' diff --git a/src/components/cta/CTAButtonsPlaceholder.tsx b/src/components/cta/CTAButtonsPlaceholder.tsx new file mode 100644 index 000000000..01002e22e --- /dev/null +++ b/src/components/cta/CTAButtonsPlaceholder.tsx @@ -0,0 +1,9 @@ +import Loader from '@/design-system/layout/Loader' + +export default function CTAButtonsPlaceholder() { + return ( + <div className="flex h-[56px] w-full items-center justify-center"> + <Loader color="dark" /> + </div> + ) +} diff --git a/src/components/cta/DynamicCTAButtons.tsx b/src/components/cta/DynamicCTAButtons.tsx index 10cc0d4e8..9ee269b8f 100644 --- a/src/components/cta/DynamicCTAButtons.tsx +++ b/src/components/cta/DynamicCTAButtons.tsx @@ -2,9 +2,8 @@ import ButtonLink from '@/design-system/inputs/ButtonLink' import { useSimulateurPage } from '@/hooks/navigation/useSimulateurPage' -import { useIsClient } from '@/hooks/useIsClient' import { useCurrentSimulation } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useState } from 'react' import { twMerge } from 'tailwind-merge' import RestartIcon from '../icons/RestartIcon' @@ -24,16 +23,14 @@ export default function DynamicCTAButtons({ } withRestart?: boolean }) { - const { progression } = useCurrentSimulation() - - const isClient = useIsClient() - const { getLinkToSimulateurPage, - linkToSimulateurPageLabel, goToSimulateurPage, + linkToSimulateurPageLabel, } = useSimulateurPage() + const { progression } = useCurrentSimulation() + const [isHover, setIsHover] = useState(false) return ( @@ -42,7 +39,6 @@ export default function DynamicCTAButtons({ size="xl" className={twMerge( 'transition-all duration-300 hover:bg-primary-900', - isClient ? 'opacity-100' : 'opacity-0', className )} href={getLinkToSimulateurPage()} @@ -69,7 +65,7 @@ export default function DynamicCTAButtons({ : '', 'leading-none' )}> - <Trans>{linkToSimulateurPageLabel}</Trans> + {linkToSimulateurPageLabel} </span> </ButtonLink> diff --git a/src/components/fin/metricSlider/heading/HeadingButtons.tsx b/src/components/fin/metricSlider/heading/HeadingButtons.tsx index 2882bb1ae..8fe819bfd 100644 --- a/src/components/fin/metricSlider/heading/HeadingButtons.tsx +++ b/src/components/fin/metricSlider/heading/HeadingButtons.tsx @@ -12,7 +12,7 @@ import { displayErrorToast } from '@/helpers/toasts/displayErrorToast' import { displaySuccessToast } from '@/helpers/toasts/displaySuccessToast' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useEndPageSharedUrl } from '@/hooks/useEndPageSharedUrl' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import isMobile from 'is-mobile' import { useEffect, useRef, useState } from 'react' import { twMerge } from 'tailwind-merge' diff --git a/src/components/form/Navigation.tsx b/src/components/form/Navigation.tsx index 6a8bf5f59..d4456ed1c 100644 --- a/src/components/form/Navigation.tsx +++ b/src/components/form/Navigation.tsx @@ -14,7 +14,7 @@ import { useClientTranslation } from '@/hooks/useClientTranslation' import { useMagicKey } from '@/hooks/useMagicKey' import { useCurrentSimulation, useForm, useRule } from '@/publicodes-state' import getValueIsOverFloorOrCeiling from '@/publicodes-state/helpers/getValueIsOverFloorOrCeiling' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import type { MouseEvent } from 'react' import { useCallback, useMemo } from 'react' diff --git a/src/components/form/Question.tsx b/src/components/form/Question.tsx index 73cfd8752..2757ecce2 100644 --- a/src/components/form/Question.tsx +++ b/src/components/form/Question.tsx @@ -18,7 +18,7 @@ import { } from '@/constants/tracking/question' import Button from '@/design-system/inputs/Button' import { useRule } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import { useEffect, useRef, useState } from 'react' import { twMerge } from 'tailwind-merge' diff --git a/src/components/form/question/Label.tsx b/src/components/form/question/Label.tsx index 2813d5a36..74fd29a34 100644 --- a/src/components/form/question/Label.tsx +++ b/src/components/form/question/Label.tsx @@ -14,7 +14,7 @@ import Button from '@/design-system/inputs/Button' import Markdown from '@/design-system/utils/Markdown' import { useClientTranslation } from '@/hooks/useClientTranslation' import type { QuestionSize } from '@/types/values' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import { motion } from 'framer-motion' import { useState } from 'react' diff --git a/src/components/form/question/Suggestions.tsx b/src/components/form/question/Suggestions.tsx index 3a7d0c60a..e28b43642 100644 --- a/src/components/form/question/Suggestions.tsx +++ b/src/components/form/question/Suggestions.tsx @@ -12,8 +12,8 @@ import { getTextCategoryColor, } from '@/helpers/getCategoryColorClass' import { useForm, useRule } from '@/publicodes-state' +import { trackEvent } from '@/utils/analytics/trackEvent' import { capitalizeString } from '@/utils/capitalizeString' -import { trackEvent } from '@/utils/matomo/trackEvent' import type { DottedName, NodeValue } from '@incubateur-ademe/nosgestesclimat' import { twMerge } from 'tailwind-merge' diff --git a/src/components/form/question/mosaic/MosaicQuestion.tsx b/src/components/form/question/mosaic/MosaicQuestion.tsx index b1885fe36..6dee1f160 100644 --- a/src/components/form/question/mosaic/MosaicQuestion.tsx +++ b/src/components/form/question/mosaic/MosaicQuestion.tsx @@ -5,7 +5,7 @@ import { questionTypeAnswer, } from '@/constants/tracking/question' import { useRule } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import MosaicBooleanInput from './mosaicQuestion/MosaicBooleanInput' import MosaicNumberInput from './mosaicQuestion/MosaicNumberInput' diff --git a/src/components/landing-pages/DailyGestures.tsx b/src/components/landing-pages/DailyGestures.tsx index 4d7036e50..aca4c999e 100644 --- a/src/components/landing-pages/DailyGestures.tsx +++ b/src/components/landing-pages/DailyGestures.tsx @@ -2,10 +2,19 @@ import Separator from '@/design-system/layout/Separator' import type { GesturesType } from '@/types/landing-page' +import dynamic from 'next/dynamic' import type { ReactNode } from 'react' -import DynamicCTAButton from '../cta/DynamicCTAButtons' +import CTAButtonsPlaceholder from '../cta/CTAButtonsPlaceholder' import GestureSelector from './dailyGestures/GestureSelector' +const DynamicCTAButtons = dynamic( + () => import('@/components/cta/DynamicCTAButtons'), + { + ssr: false, + loading: () => <CTAButtonsPlaceholder />, + } +) + export default function DailyGestures({ title, description, @@ -34,7 +43,10 @@ export default function DailyGestures({ </div> <div className="mt-10 text-center"> - <DynamicCTAButton trackingEvents={trackingEvents} withRestart={false} /> + <DynamicCTAButtons + trackingEvents={trackingEvents} + withRestart={false} + /> </div> </div> ) diff --git a/src/components/landing-pages/DidYouKnowSlider.tsx b/src/components/landing-pages/DidYouKnowSlider.tsx index e4548ea9e..3ec7f584b 100644 --- a/src/components/landing-pages/DidYouKnowSlider.tsx +++ b/src/components/landing-pages/DidYouKnowSlider.tsx @@ -6,6 +6,7 @@ import { getLandingDidYouKnowSlider, getLandingDidYouKnowSliderValue, } from '@/helpers/tracking/landings' +import dynamic from 'next/dynamic' import Image from 'next/image' import { usePathname } from 'next/navigation' import type { ReactNode } from 'react' @@ -13,9 +14,14 @@ import { useState } from 'react' import Slider from 'react-slick' import 'slick-carousel/slick/slick.css' import { twMerge } from 'tailwind-merge' -import DynamicCTAButton from '../cta/DynamicCTAButtons' +import CTAButtonsPlaceholder from '../cta/CTAButtonsPlaceholder' import Trans from '../translation/Trans' +const DynamicCTAButtons = dynamic( + () => import('@/components/cta/DynamicCTAButtons'), + { ssr: false, loading: () => <CTAButtonsPlaceholder /> } +) + export default function DidYouKnowSlider({ slides, className, @@ -81,7 +87,7 @@ export default function DidYouKnowSlider({ ))} </Slider> <div> - <DynamicCTAButton + <DynamicCTAButtons trackingEvents={{ start: getLandingDidYouKnowSlider( pathname, diff --git a/src/components/landing-pages/FAQ.tsx b/src/components/landing-pages/FAQ.tsx index 835c33a8b..2077507ba 100644 --- a/src/components/landing-pages/FAQ.tsx +++ b/src/components/landing-pages/FAQ.tsx @@ -50,7 +50,7 @@ export default function FAQ({ {question} </h3> - <PlusIcon className="inline-block h-8 w-8 min-w-8 origin-center transform transition-transform duration-300 group-open:rotate-45 group-open:fill-primary-700" /> + <PlusIcon className="inline-block h-6 w-6 min-w-6 origin-center transform transition-transform duration-300 group-open:rotate-45 group-open:fill-primary-700" /> </summary> <div className="grid grid-rows-[0fr] transition-all duration-200 ease-in-out group-open:grid-rows-[1fr]"> diff --git a/src/components/landing-pages/UnderstandToAct.tsx b/src/components/landing-pages/UnderstandToAct.tsx index 86accf544..99aeb0590 100644 --- a/src/components/landing-pages/UnderstandToAct.tsx +++ b/src/components/landing-pages/UnderstandToAct.tsx @@ -40,6 +40,7 @@ export default function UnderstandToAct({ <PostThumbnail key={`${index}-post-thumbnail`} {...post} + className="bg-white" trackingEvent={getLandingClickPostThumbnail( pathname, `${trackingActionClickPostThumbnail} ${index + 1}` diff --git a/src/components/landing-pages/titleDescLinkBlock/TitleDescLink.tsx b/src/components/landing-pages/titleDescLinkBlock/TitleDescLink.tsx index c1bcde0c9..dcd9bea0b 100644 --- a/src/components/landing-pages/titleDescLinkBlock/TitleDescLink.tsx +++ b/src/components/landing-pages/titleDescLinkBlock/TitleDescLink.tsx @@ -1,7 +1,7 @@ 'use client' import Link from '@/components/Link' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { ReactNode } from 'react' export default function TitleDescLink({ diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index 302255ec2..5b748c832 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -20,7 +20,7 @@ import { import InlineLink from '@/design-system/inputs/InlineLink' import { useIframe } from '@/hooks/useIframe' import { useLocale } from '@/hooks/useLocale' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { usePathname } from 'next/navigation' import { twMerge } from 'tailwind-merge' import Link from '../Link' diff --git a/src/components/layout/header/HeaderDesktop.tsx b/src/components/layout/header/HeaderDesktop.tsx index dfbc378e7..0487ce59a 100644 --- a/src/components/layout/header/HeaderDesktop.tsx +++ b/src/components/layout/header/HeaderDesktop.tsx @@ -17,8 +17,9 @@ import { HIDE_CTA_PATHS } from '@/constants/urls' import { linkToClassement } from '@/helpers/navigation/classementPages' import { useSimulateurPage } from '@/hooks/navigation/useSimulateurPage' import { useClientTranslation } from '@/hooks/useClientTranslation' +import { useIframe } from '@/hooks/useIframe' import { useUser } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { usePathname } from 'next/navigation' import { twMerge } from 'tailwind-merge' import NavLink from './NavLink' @@ -26,7 +27,6 @@ import OrganisationLink from './_components/OrganisationLink' import ProfileIcon from './_components/ProfileIcon' import DebugIndicator from './headerDesktop/DebugIndicator' import CTAButton from './headerDesktop/MenuCTAButton' - type Props = { isSticky: boolean } @@ -39,6 +39,8 @@ export default function HeaderDesktop({ isSticky }: Props) { const { getLinkToSimulateurPage } = useSimulateurPage() + const { isIframeOnlySimulation } = useIframe() + return ( <header className={twMerge( @@ -51,67 +53,71 @@ export default function HeaderDesktop({ isSticky }: Props) { <Logo onClick={() => trackEvent(headerClickLogo)} /> </div> - <nav className="h-full"> - <ul className="flex h-full flex-1 justify-start gap-4"> - <li> - <NavLink - href={getLinkToSimulateurPage()} - onClick={() => trackEvent(headerClickTest)} - activeMatches={['/tutoriel', '/simulateur', '/fin']} - icon={BilanIcon} - title={t('Mon empreinte')}> - <Trans>Mon empreinte</Trans> - </NavLink> - </li> + {!isIframeOnlySimulation && ( + <> + <nav className="h-full"> + <ul className="flex h-full flex-1 justify-start gap-4"> + <li> + <NavLink + href={getLinkToSimulateurPage()} + onClick={() => trackEvent(headerClickTest)} + activeMatches={['/tutoriel', '/simulateur', '/fin']} + icon={BilanIcon} + title={t('Mon empreinte')}> + <Trans>Mon empreinte</Trans> + </NavLink> + </li> - <li> - <NavLink - href="/actions" - onClick={() => trackEvent(headerClickActions)} - icon={ActionsIcon} - title={t('Mes gestes')}> - <Trans>Mes gestes</Trans> - </NavLink> - </li> + <li> + <NavLink + href="/actions" + onClick={() => trackEvent(headerClickActions)} + icon={ActionsIcon} + title={t('Mes gestes')}> + <Trans>Mes gestes</Trans> + </NavLink> + </li> - <li> - <NavLink - href={linkToClassement} - onClick={() => trackEvent(headerClickClassements)} - icon={AmisIcon} - activeMatches={['/classement', '/amis']} - title={t('Mes classements')} - data-cypress-id="amis-link"> - <Trans>Mes groupes</Trans> - </NavLink> - </li> - </ul> - </nav> + <li> + <NavLink + href={linkToClassement} + onClick={() => trackEvent(headerClickClassements)} + icon={AmisIcon} + activeMatches={['/classement', '/amis']} + title={t('Mes classements')} + data-cypress-id="amis-link"> + <Trans>Mes groupes</Trans> + </NavLink> + </li> + </ul> + </nav> - <div className="flex h-full items-center gap-3"> - <PRIndicator /> + <div className="flex h-full items-center gap-3"> + <PRIndicator /> - <DebugIndicator /> + <DebugIndicator /> - <NavLink - href="/profil" - icon={ProfileIcon} - title={t('Profil')} - className="px-4" - onClick={() => trackEvent(headerClickProfil)}> - <Trans>Profil</Trans> - </NavLink> + <NavLink + href="/profil" + icon={ProfileIcon} + title={t('Profil')} + className="px-4" + onClick={() => trackEvent(headerClickProfil)}> + <Trans>Profil</Trans> + </NavLink> - {user?.organisation?.administratorEmail ? ( - <> - <div className="my-auto h-8 w-[1px] bg-gray-200" /> + {user?.organisation?.administratorEmail ? ( + <> + <div className="my-auto h-8 w-[1px] bg-gray-200" /> - <OrganisationLink /> - </> - ) : !HIDE_CTA_PATHS.find((path) => pathname.includes(path)) ? ( - <CTAButton /> - ) : null} - </div> + <OrganisationLink /> + </> + ) : !HIDE_CTA_PATHS.find((path) => pathname.includes(path)) ? ( + <CTAButton /> + ) : null} + </div> + </> + )} </div> </div> </header> diff --git a/src/components/layout/header/_components/OrganisationLink.tsx b/src/components/layout/header/_components/OrganisationLink.tsx index 7b8948d5e..a7f427a44 100644 --- a/src/components/layout/header/_components/OrganisationLink.tsx +++ b/src/components/layout/header/_components/OrganisationLink.tsx @@ -6,7 +6,7 @@ import { headerClickOrganisation } from '@/constants/tracking/layout' import useFetchOrganisations from '@/hooks/organisations/useFetchOrganisations' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useUser } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import NavLink from '../NavLink' export default function OrganisationLink({ diff --git a/src/components/layout/header/headerDesktop/MenuCTAButton.tsx b/src/components/layout/header/headerDesktop/MenuCTAButton.tsx index 228b22762..513c76dcf 100644 --- a/src/components/layout/header/headerDesktop/MenuCTAButton.tsx +++ b/src/components/layout/header/headerDesktop/MenuCTAButton.tsx @@ -11,7 +11,7 @@ import { } from '@/helpers/tracking/landings' import { useSimulateurPage } from '@/hooks/navigation/useSimulateurPage' import { useCurrentSimulation } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { usePathname } from 'next/navigation' export default function MenuCTAButton() { diff --git a/src/components/layout/header/headerMobile/BottomMenu.tsx b/src/components/layout/header/headerMobile/BottomMenu.tsx index 76ce4a872..60ddc07e2 100644 --- a/src/components/layout/header/headerMobile/BottomMenu.tsx +++ b/src/components/layout/header/headerMobile/BottomMenu.tsx @@ -11,7 +11,7 @@ import { } from '@/constants/tracking/layout' import { linkToClassement } from '@/helpers/navigation/classementPages' import { useSimulateurPage } from '@/hooks/navigation/useSimulateurPage' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import NavLink from '../NavLink' export default function BottomMenu() { diff --git a/src/components/layout/header/headerMobile/FoldableMenu.tsx b/src/components/layout/header/headerMobile/FoldableMenu.tsx index 5804037d2..4cdc8ad68 100644 --- a/src/components/layout/header/headerMobile/FoldableMenu.tsx +++ b/src/components/layout/header/headerMobile/FoldableMenu.tsx @@ -6,7 +6,7 @@ import { } from '@/constants/tracking/layout' import BurgerMenu from '@/design-system/layout/BurgerMenu' import { useUser } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { Suspense } from 'react' import NavLink from '../NavLink' import OrganisationLink from '../_components/OrganisationLink' diff --git a/src/components/organisations/orgaStatistics/DetailedStatistics.tsx b/src/components/organisations/orgaStatistics/DetailedStatistics.tsx index 709e86a83..9213b2aa3 100644 --- a/src/components/organisations/orgaStatistics/DetailedStatistics.tsx +++ b/src/components/organisations/orgaStatistics/DetailedStatistics.tsx @@ -5,7 +5,7 @@ import Trans from '@/components/translation/Trans' import { organisationsDashboardClickFunFacts } from '@/constants/tracking/pages/organisationsDashboard' import Button from '@/design-system/inputs/Button' import type { Entries } from '@/publicodes-state/types' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName, FunFacts } from '@incubateur-ademe/nosgestesclimat' import importedFunFacts from '@incubateur-ademe/nosgestesclimat/public/funFactsRules.json' import { utils } from 'publicodes' diff --git a/src/components/organisations/orgaStatistics/funFacts/DetailedFunFacts.tsx b/src/components/organisations/orgaStatistics/funFacts/DetailedFunFacts.tsx index 4a979e203..2445bc6aa 100644 --- a/src/components/organisations/orgaStatistics/funFacts/DetailedFunFacts.tsx +++ b/src/components/organisations/orgaStatistics/funFacts/DetailedFunFacts.tsx @@ -3,7 +3,7 @@ import Trans from '@/components/translation/Trans' import { organisationsDashboardClickFunFactsDownload } from '@/constants/tracking/pages/organisationsDashboard' import Button from '@/design-system/inputs/Button' import type { Entries } from '@/publicodes-state/types' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName, FunFacts } from '@incubateur-ademe/nosgestesclimat' import { toPng } from 'html-to-image' import { useParams } from 'next/navigation' diff --git a/src/components/organisations/questionsComplementaires/CustomQuestionForm.tsx b/src/components/organisations/questionsComplementaires/CustomQuestionForm.tsx index aef82f70e..634ee4531 100644 --- a/src/components/organisations/questionsComplementaires/CustomQuestionForm.tsx +++ b/src/components/organisations/questionsComplementaires/CustomQuestionForm.tsx @@ -1,5 +1,6 @@ import Trans from '@/components/translation/Trans' import Button from '@/design-system/inputs/Button' +import { useClientTranslation } from '@/hooks/useClientTranslation' import type { Organisation, OrganisationPoll } from '@/types/organisations' import { useEffect, useState } from 'react' import type { SubmitHandler } from 'react-hook-form' @@ -20,6 +21,7 @@ type Props = { submitLabel?: string | JSX.Element isEditMode?: boolean onCompleted?: (changes: Record<string, unknown>) => void + onCancel?: () => void question?: string } @@ -32,10 +34,23 @@ export default function CustomQuestionForm({ isEditMode, organisation, onCompleted = () => {}, + onCancel, }: Props) { const [isFormDisplayed, setIsFormDisplayed] = useState(isEditMode ?? false) - const { register, handleSubmit, setValue, reset } = useReactHookForm<Inputs>() + const { t } = useClientTranslation() + + const { + register, + handleSubmit, + setValue, + reset, + formState: { errors }, + } = useReactHookForm<Inputs>({ + defaultValues: { + question: '', + }, + }) useEffect(() => { if (question) { @@ -50,6 +65,7 @@ export default function CustomQuestionForm({ ...(poll?.customAdditionalQuestions || []), ] + // Editing an existing question if (isEditMode && question !== questionValue) { const questionIndex = customAdditionalQuestions.findIndex( ({ question: questionSearched }) => questionSearched === question @@ -61,9 +77,11 @@ export default function CustomQuestionForm({ customAdditionalQuestions[questionIndex].question = questionValue } else { + // Adding a new question customAdditionalQuestions.push({ question: questionValue, - isEnabled: false, + // Enabled by default + isEnabled: true, }) } @@ -74,6 +92,7 @@ export default function CustomQuestionForm({ function handleCancel() { setIsFormDisplayed(false) + onCancel?.() } // Show the form only for organisations with access @@ -94,7 +113,6 @@ export default function CustomQuestionForm({ hasReachedMaxQuestions ? () => {} : () => { - // Reset the form if it was previously used reset() setIsFormDisplayed(true) } @@ -103,13 +121,10 @@ export default function CustomQuestionForm({ </Button> ) } + return ( <form - id="custom-question-form" - onSubmit={(event) => { - event.preventDefault() - handleSubmit(onSubmit)(event) - }} + onSubmit={handleSubmit(onSubmit)} className="flex w-full flex-col items-start"> {!isEditMode && ( <label htmlFor="question" className="mb-2 text-sm"> @@ -117,7 +132,10 @@ export default function CustomQuestionForm({ </label> )} - <EditableToggleField {...register('question')} /> + <EditableToggleField + {...register('question', { required: t('Ce champ est requis') })} + error={errors.question?.message} + /> <div className={twMerge('mt-2 flex gap-4', `${isEditMode ? 'mt-1' : ''}`)}> diff --git a/src/components/organisations/questionsComplementaires/EditableToggleField.tsx b/src/components/organisations/questionsComplementaires/EditableToggleField.tsx index 941f2f0c0..feb27fd9c 100644 --- a/src/components/organisations/questionsComplementaires/EditableToggleField.tsx +++ b/src/components/organisations/questionsComplementaires/EditableToggleField.tsx @@ -1,4 +1,4 @@ -import type { ChangeEventHandler, ForwardedRef} from 'react'; +import type { ChangeEventHandler, ForwardedRef } from 'react' import { forwardRef } from 'react' import { DebounceInput } from 'react-debounce-input' import { twMerge } from 'tailwind-merge' @@ -7,30 +7,36 @@ type Props = { onChange: ChangeEventHandler<HTMLInputElement> name: string className?: string + error?: string } export default forwardRef(function EditableToggleField( - { name = 'newQuestion', onChange, className }: Props, + { name = 'newQuestion', onChange, className, error }: Props, ref: ForwardedRef<HTMLInputElement> ) { return ( - <div - className={twMerge( - 'relative flex w-full flex-col items-center overflow-hidden rounded-xl border-2 border-gray-200 p-4 transition-colors', - className - )}> - <div className="flex w-full justify-between"> - <DebounceInput - inputRef={ref} - onChange={onChange} - debounceTimeout={500} - name={name} - type="text" - // eslint-disable-next-line jsx-a11y/no-autofocus - autoFocus - className="mr-2 w-full bg-transparent px-1 pb-1 text-base outline-none focus:!border-b-2 focus:border-primary-500" - /> + <> + <div + className={twMerge( + 'relative flex w-full flex-col items-center overflow-hidden rounded-xl border-2 border-gray-200 p-4 transition-colors', + className + )}> + <div className="flex w-full justify-between"> + <DebounceInput + inputRef={ref} + onChange={onChange} + debounceTimeout={500} + name={name} + type="text" + // eslint-disable-next-line jsx-a11y/no-autofocus + autoFocus + className="mr-2 w-full bg-transparent px-1 pb-1 text-base outline-none focus:!border-b-2 focus:border-primary-500" + /> + </div> </div> - </div> + {error && ( + <p className="mb-2 mt-1 text-left text-sm text-red-700">{error}</p> + )} + </> ) }) diff --git a/src/components/organisations/questionsComplementaires/customQuestions/CustomQuestion.tsx b/src/components/organisations/questionsComplementaires/customQuestions/CustomQuestion.tsx index 5432ba4a2..f7fd25071 100644 --- a/src/components/organisations/questionsComplementaires/customQuestions/CustomQuestion.tsx +++ b/src/components/organisations/questionsComplementaires/customQuestions/CustomQuestion.tsx @@ -76,6 +76,7 @@ export default function CustomQuestion({ onChange(changes) setIsEditing(false) }} + onCancel={() => setIsEditing(false)} isEditMode question={question} /> diff --git a/src/components/results/categoriesAccordion/AccordionItemWithRule.tsx b/src/components/results/categoriesAccordion/AccordionItemWithRule.tsx index 8cbb1ff9c..bb8360c31 100644 --- a/src/components/results/categoriesAccordion/AccordionItemWithRule.tsx +++ b/src/components/results/categoriesAccordion/AccordionItemWithRule.tsx @@ -10,7 +10,7 @@ import { formatFootprint } from '@/helpers/formatters/formatFootprint' import { getBackgroundColor } from '@/helpers/getCategoryColorClass' import { useRule, useSimulation } from '@/publicodes-state' import type { Metric } from '@/publicodes-state/types' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { DottedName } from '@incubateur-ademe/nosgestesclimat' import SubcategoriesList from './accordionItemWithRule/SubcategoriesList' diff --git a/src/components/simulation/topBar/Explanation.tsx b/src/components/simulation/topBar/Explanation.tsx index 1b0836d01..402aaa506 100644 --- a/src/components/simulation/topBar/Explanation.tsx +++ b/src/components/simulation/topBar/Explanation.tsx @@ -8,7 +8,7 @@ import Button from '@/design-system/inputs/Button' import Emoji from '@/design-system/utils/Emoji' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useCurrentSimulation, useUser } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { motion } from 'framer-motion' import { useEffect, useState } from 'react' diff --git a/src/components/simulation/topBar/TotalButtons.tsx b/src/components/simulation/topBar/TotalButtons.tsx index 7f4b829a5..c6336f5d2 100644 --- a/src/components/simulation/topBar/TotalButtons.tsx +++ b/src/components/simulation/topBar/TotalButtons.tsx @@ -9,7 +9,7 @@ import { simulateurOpenScoreInfo } from '@/constants/tracking/pages/simulateur' import { TUTORIALS } from '@/constants/tutorial' import Button from '@/design-system/inputs/Button' import { useCurrentSimulation, useUser } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { twMerge } from 'tailwind-merge' type Props = { diff --git a/src/components/translation/LanguageSwitchButton.tsx b/src/components/translation/LanguageSwitchButton.tsx index 5506dcf82..8bea20fa0 100644 --- a/src/components/translation/LanguageSwitchButton.tsx +++ b/src/components/translation/LanguageSwitchButton.tsx @@ -7,7 +7,7 @@ import { updateLang } from '@/helpers/language/updateLang' import { updateLangCookie } from '@/helpers/language/updateLangCookie' import { useClientTranslation } from '@/hooks/useClientTranslation' import i18nConfig from '@/i18nConfig' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useCurrentLocale } from 'next-i18n-router/client' import { useCallback, useEffect } from 'react' diff --git a/src/components/translation/LocalisationBanner.tsx b/src/components/translation/LocalisationBanner.tsx index 6a4336cf3..73770a926 100644 --- a/src/components/translation/LocalisationBanner.tsx +++ b/src/components/translation/LocalisationBanner.tsx @@ -9,8 +9,8 @@ import Card from '@/design-system/layout/Card' import { useIframe } from '@/hooks/useIframe' import { useLocale } from '@/hooks/useLocale' import { useUser } from '@/publicodes-state' +import { trackEvent } from '@/utils/analytics/trackEvent' import { capitalizeString } from '@/utils/capitalizeString' -import { trackEvent } from '@/utils/matomo/trackEvent' import type { SupportedRegions } from '@incubateur-ademe/nosgestesclimat' import { usePathname } from 'next/navigation' import { twMerge } from 'tailwind-merge' @@ -56,11 +56,11 @@ export default function LocalisationBanner({ supportedRegions }: Props) { return ( <Card className={twMerge( - 'fixed bottom-0 right-8 z-50 mx-auto mb-8 max-w-full flex-row bg-primary-50', + 'fixed bottom-0 left-4 right-4 z-50 mx-auto mb-8 flex-row bg-primary-50 sm:left-auto sm:right-8', isTutorialOrTest && 'bottom-12' )}> - <div className="flex gap-4"> - <div className="flex-1"> + <div className="flex w-full gap-4"> + <div className="w-full flex-1"> {regionParams && ( <> <p className="mb-0 inline flex-1 items-baseline gap-1"> diff --git a/src/constants/organisations/administrator.ts b/src/constants/organisations/administrator.ts new file mode 100644 index 000000000..a1db80426 --- /dev/null +++ b/src/constants/organisations/administrator.ts @@ -0,0 +1 @@ +export const ADMINISTRATOR_SEPARATOR = '\n_\n' diff --git a/src/constants/organisations/organisationTypes.ts b/src/constants/organisations/organisationTypes.ts index 3db03cab7..0bf17ba23 100644 --- a/src/constants/organisations/organisationTypes.ts +++ b/src/constants/organisations/organisationTypes.ts @@ -12,11 +12,9 @@ export enum OrganisationTypeEnum { export const ORGANISATION_TYPES = { [OrganisationTypeEnum.company]: t('Entreprise'), - [OrganisationTypeEnum.publicOrRegionalAuthority]: t( - 'Public ou collectivité territoriale' - ), [OrganisationTypeEnum.cooperative]: t('Coopérative'), [OrganisationTypeEnum.association]: t('Association'), + [OrganisationTypeEnum.publicOrRegionalAuthority]: t('Service public'), [OrganisationTypeEnum.universityOrSchool]: t('Université ou école'), [OrganisationTypeEnum.groupOfFriends]: t("Groupe d'amis"), [OrganisationTypeEnum.other]: t('Autre'), diff --git a/src/constants/tracking/misc.ts b/src/constants/tracking/misc.ts index 56aee3256..08d24f92d 100644 --- a/src/constants/tracking/misc.ts +++ b/src/constants/tracking/misc.ts @@ -1,13 +1,20 @@ // Return tracking data in format // [ 'trackEvent', 'Category', 'Action', 'Name', 'Value' ] -export const trackingIframe = (url: string) => [ +export const trackingIframeVisit = (url: string) => [ 'trackEvent', 'Misc', 'Iframe visit', `Iframe visit from ${url}`, ] +export const trackingIframeInteraction = (url: string) => [ + 'trackEvent', + 'Misc', + 'Iframe interaction', + `Iframe interaction from ${url}`, +] + export const trackingLocale = (locale: string) => [ 'trackEvent', 'Misc', diff --git a/src/constants/tracking/question.ts b/src/constants/tracking/question.ts index 3384a1bda..ac89c3d21 100644 --- a/src/constants/tracking/question.ts +++ b/src/constants/tracking/question.ts @@ -73,9 +73,10 @@ export const questionTypeAnswer = ({ question, mosaicValue }: Props) => [ ] // Figma comment #50 -export const questionClickSuggestion = ({ question }: Props) => [ +export const questionClickSuggestion = ({ question, answer }: Props) => [ 'trackEvent', 'Simulateur', 'Click Suggestion', question, + String(answer), ] diff --git a/src/constants/urls.ts b/src/constants/urls.ts index 06ace13ef..856adb9f7 100644 --- a/src/constants/urls.ts +++ b/src/constants/urls.ts @@ -10,6 +10,8 @@ export const AUTHENTICATION_URL = SERVER_URL + '/authentication/v1' export const GROUP_URL = SERVER_URL + '/groups/v1' +export const NEWSLETTER_URL = SERVER_URL + '/newsletters/v1' + export const NORTHSTAR_RATING_URL = SERVER_URL + '/northstar-ratings/v1' export const ORGANISATION_URL = SERVER_URL + '/organisations/v1' diff --git a/src/design-system/cms/NewslettersBlock.tsx b/src/design-system/cms/NewslettersBlock.tsx index e55f0baf1..6e4938824 100644 --- a/src/design-system/cms/NewslettersBlock.tsx +++ b/src/design-system/cms/NewslettersBlock.tsx @@ -11,10 +11,10 @@ import { subscribeToNewsletterBlog } from '@/constants/tracking/pages/newsletter import { useGetNewsletterSubscriptions } from '@/hooks/settings/useGetNewsletterSubscriptions' import { useUpdateUserSettings } from '@/hooks/settings/useUpdateUserSettings' import { useLocale } from '@/hooks/useLocale' -import { useNumberSubscribers } from '@/hooks/useNumberSubscriber' +import { useMainNewsletter } from '@/hooks/useMainNewsletter' import { useUser } from '@/publicodes-state' +import { trackEvent } from '@/utils/analytics/trackEvent' import { formatEmail } from '@/utils/format/formatEmail' -import { trackEvent } from '@/utils/matomo/trackEvent' import { useEffect, useRef } from 'react' import type { SubmitHandler } from 'react-hook-form' import { useForm as useReactHookForm } from 'react-hook-form' @@ -50,7 +50,7 @@ function SuccessMessage() { } export default function NewslettersBlock() { - const { data: numberSubscribers } = useNumberSubscribers() + const { data: mainNewsletter } = useMainNewsletter() const locale = useLocale() @@ -143,7 +143,7 @@ export default function NewslettersBlock() { <CheckIcon className="mr-2 h-4 w-4 stroke-green-500" /> <span className="text-sm text-gray-600"> - {numberSubscribers?.toLocaleString(locale) ?? 0}{' '} + {mainNewsletter?.totalSubscribers.toLocaleString(locale) ?? 0}{' '} <Trans>personnes inscrites</Trans> </span> </p> diff --git a/src/design-system/cms/PostThumbnail.tsx b/src/design-system/cms/PostThumbnail.tsx index 64d1625f4..b2db19f07 100644 --- a/src/design-system/cms/PostThumbnail.tsx +++ b/src/design-system/cms/PostThumbnail.tsx @@ -1,7 +1,7 @@ 'use client' import Trans from '@/components/translation/Trans' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { ReactNode } from 'react' import { twMerge } from 'tailwind-merge' import ImageWithCategory from './ImageWithCategory' diff --git a/src/design-system/inputs/ButtonLink.tsx b/src/design-system/inputs/ButtonLink.tsx index 31ccbc31e..bc16aefc6 100644 --- a/src/design-system/inputs/ButtonLink.tsx +++ b/src/design-system/inputs/ButtonLink.tsx @@ -2,7 +2,7 @@ import Link from '@/components/Link' import type { ButtonSize } from '@/types/values' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import type { HtmlHTMLAttributes, PropsWithChildren } from 'react' import { twMerge } from 'tailwind-merge' import { baseClassNames, colorClassNames, sizeClassNames } from './Button' diff --git a/src/design-system/inputs/GoBackLink.tsx b/src/design-system/inputs/GoBackLink.tsx index e0937ff21..681f85105 100644 --- a/src/design-system/inputs/GoBackLink.tsx +++ b/src/design-system/inputs/GoBackLink.tsx @@ -2,7 +2,7 @@ import Link from '@/components/Link' import Trans from '@/components/translation/Trans' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' type Props = { href: string diff --git a/src/design-system/inputs/Select.tsx b/src/design-system/inputs/Select.tsx index e49133ed3..f49633dff 100644 --- a/src/design-system/inputs/Select.tsx +++ b/src/design-system/inputs/Select.tsx @@ -2,10 +2,9 @@ import type { ChangeEvent, ForwardedRef, PropsWithChildren, - ReactNode} from 'react'; -import { - forwardRef, + ReactNode, } from 'react' +import { forwardRef } from 'react' import { twMerge } from 'tailwind-merge' export default forwardRef(function Select( @@ -60,7 +59,7 @@ export default forwardRef(function Select( aria-describedby={`error-${name}`} required={required} className={twMerge( - 'max-w-[30rem] !cursor-pointer rounded-xl border-2 border-solid border-gray-300 bg-gray-100 p-4 text-sm transition-colors focus:border-primary-700 focus:ring-2 focus:ring-primary-700', + 'mt-3 h-[56px] max-w-[30rem] !cursor-pointer rounded-xl border-2 border-solid border-gray-300 bg-gray-100 p-4 text-sm transition-colors focus:border-primary-700 focus:ring-2 focus:ring-primary-700', `${className} ${helperText || label ? ' mt-3' : ''} ${ error ? '!border-red-200 !bg-red-50 ring-2 !ring-red-700' : '' }` diff --git a/src/design-system/layout/Breadcrumbs.tsx b/src/design-system/layout/Breadcrumbs.tsx index d2dffe33d..cff36d6ba 100644 --- a/src/design-system/layout/Breadcrumbs.tsx +++ b/src/design-system/layout/Breadcrumbs.tsx @@ -2,7 +2,7 @@ import Link from '@/components/Link' import { breadcrumbClickLink } from '@/constants/tracking/layout' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { Fragment } from 'react' import { twMerge } from 'tailwind-merge' diff --git a/src/helpers/organisations/unformatAdministratorName.ts b/src/helpers/organisations/unformatAdministratorName.ts new file mode 100644 index 000000000..ce694b0ae --- /dev/null +++ b/src/helpers/organisations/unformatAdministratorName.ts @@ -0,0 +1,6 @@ +import { ADMINISTRATOR_SEPARATOR } from '@/constants/organisations/administrator' + +// Removes the separator between the first and last name of an administrator +export function unformatAdministratorName(name: string) { + return name.replace(ADMINISTRATOR_SEPARATOR, ' ') +} diff --git a/src/helpers/tracking/landings.ts b/src/helpers/tracking/landings.ts index abfd4cddd..7b2f7a0d5 100644 --- a/src/helpers/tracking/landings.ts +++ b/src/helpers/tracking/landings.ts @@ -3,7 +3,6 @@ function getLandingCategory(pathname: string) { case '/empreinte-eau': return 'LP eau' case '/empreinte-carbone': - console.log('empreinte-carbone') return 'LP carbone' case '/': default: diff --git a/src/hooks/organisations/polls/useUpdatePoll.ts b/src/hooks/organisations/polls/useUpdatePoll.ts index 0bd73b189..3c8d79eed 100644 --- a/src/hooks/organisations/polls/useUpdatePoll.ts +++ b/src/hooks/organisations/polls/useUpdatePoll.ts @@ -9,7 +9,7 @@ import { useParams } from 'next/navigation' export type PollToUpdate = { name?: string - expectedNumberOfParticipants?: number + expectedNumberOfParticipants?: number | null defaultAdditionalQuestions?: PollDefaultAdditionalQuestion[] customAdditionalQuestions?: { question: string; isEnabled: boolean }[] } diff --git a/src/hooks/organisations/useCreateOrganisation.ts b/src/hooks/organisations/useCreateOrganisation.ts index ff22d82c3..2de7ed1b9 100644 --- a/src/hooks/organisations/useCreateOrganisation.ts +++ b/src/hooks/organisations/useCreateOrganisation.ts @@ -6,7 +6,7 @@ import axios from 'axios' type OrganisationToCreate = { name: string - type?: OrganisationTypeEnum | null + type: OrganisationTypeEnum numberOfCollaborators?: number administrators?: [ { diff --git a/src/hooks/organisations/useFetchOrganisation.ts b/src/hooks/organisations/useFetchOrganisation.ts index dbc8de4d5..b1f436dbf 100644 --- a/src/hooks/organisations/useFetchOrganisation.ts +++ b/src/hooks/organisations/useFetchOrganisation.ts @@ -1,11 +1,17 @@ import { ORGANISATION_URL } from '@/constants/urls' +import { useUser } from '@/publicodes-state' import type { Organisation } from '@/types/organisations' import { useQuery } from '@tanstack/react-query' import axios from 'axios' import { useParams } from 'next/navigation' export default function useFetchOrganisation() { - const { orgaSlug: organisationIdOrSlug } = useParams() + const { orgaSlug } = useParams() + + const { user } = useUser() + + // Use organisationIdOrSlug or organisationId from the localstate + const organisationIdOrSlug = orgaSlug || user?.organisation?.slug return useQuery({ queryKey: ['organisations', organisationIdOrSlug], diff --git a/src/hooks/organisations/useUpdateOrganisation.ts b/src/hooks/organisations/useUpdateOrganisation.ts index bb92a39d1..c95091886 100644 --- a/src/hooks/organisations/useUpdateOrganisation.ts +++ b/src/hooks/organisations/useUpdateOrganisation.ts @@ -1,3 +1,4 @@ +import { ADMINISTRATOR_SEPARATOR } from '@/constants/organisations/administrator' import type { OrganisationTypeEnum } from '@/constants/organisations/organisationTypes' import { ORGANISATION_URL } from '@/constants/urls' import type { @@ -46,8 +47,10 @@ export function useUpdateOrganisation() { : { numberOfCollaborators: null }), administrators: [ { - ...(formData.administratorName - ? { name: formData.administratorName } + ...(formData.administratorFirstName + ? { + name: `${formData.administratorFirstName}${ADMINISTRATOR_SEPARATOR}${formData.administratorLastName ?? ''}`, + } : { name: null }), ...(formData.administratorTelephone ? { telephone: formData.administratorTelephone } diff --git a/src/hooks/tracking/useGetTrackedUrl.ts b/src/hooks/tracking/useGetTrackedUrl.ts new file mode 100644 index 000000000..647655ea7 --- /dev/null +++ b/src/hooks/tracking/useGetTrackedUrl.ts @@ -0,0 +1,70 @@ +import { locales } from '@/i18nConfig' +import { useSearchParams } from 'next/navigation' + +import { usePathname } from 'next/navigation' + +function handleOrganisationModifications(url: string) { + // Replace the organisation slug by the placeholder + const pathNameSegment = url.split('/').filter((segment) => segment !== '') + + let urlModified = url + if ( + pathNameSegment[0] === 'organisations' && + !['connexion', 'creer', 'demander-demo', 'creer-campagne'].includes( + pathNameSegment[1] + ) + ) { + urlModified = urlModified.replace(pathNameSegment[1], 'orga_slug') + } + + // Replace the poll slug by the placeholder + if (pathNameSegment[2] === 'campagnes') { + urlModified = urlModified.replace(pathNameSegment[3], 'poll_slug') + } + + return urlModified +} + +export function useGetTrackedUrl() { + const pathname = usePathname() + const searchParams = useSearchParams() + + let url = pathname + + // We remove the lang prefix from the pathname + locales.map((locale) => { + if (pathname?.startsWith(`/${locale}`)) { + url = pathname.slice(3) + } + }) + + // We don't want to track the slugs of the organisations and theirs polls + url = handleOrganisationModifications(url) + + // We convert the question searchParams to a real url + const questionParams = searchParams.get('question') + if (questionParams) { + const category = questionParams.split('.')[0] + const question = questionParams.replace(category + '.', '') + url += `/${category}/${question}` + } + + // We convert the groupId to a real url + const groupId = searchParams.get('groupId') + if (groupId) { + url += `/${groupId}` + } + + // We add a trailing slash + if (!url.endsWith('/')) { + url += '/' + } + + // We add the searchParams to the url + const search = searchParams.toString() + if (search) { + url += `?${search}` + } + + return url +} diff --git a/src/hooks/tracking/useTrackIframe.ts b/src/hooks/tracking/useTrackIframe.ts new file mode 100644 index 000000000..e1b5135ee --- /dev/null +++ b/src/hooks/tracking/useTrackIframe.ts @@ -0,0 +1,109 @@ +import { + trackingIframeInteraction, + trackingIframeVisit, +} from '@/constants/tracking/misc' +import { trackEvent, trackPageView } from '@/utils/analytics/trackEvent' +import { usePathname } from 'next/navigation' +import { useEffect, useRef, useState } from 'react' +import { useGetTrackedUrl } from './useGetTrackedUrl' +export function useTrackIframe(isIframe: boolean) { + const path = usePathname() + + const url = useGetTrackedUrl() + + // inspired from https://usehooks-ts.com/react-hook/use-intersection-observer + const ref = useRef<HTMLDivElement | null>(null) + const [entry, setEntry] = useState<IntersectionObserverEntry>() + const [observed, setObserved] = useState(false) + const [hasInteracted, setHasInteracted] = useState(false) + + const getIntegratorUrl = (isIframe: boolean) => { + const urlParams = new URLSearchParams(window.location.search) + + const isIframeParameterDefined = urlParams.get('iframe') !== null + + if (isIframe && !isIframeParameterDefined) { + urlParams.set('iframe', '') + urlParams.set( + 'integratorUrl', + document.location.ancestorOrigins && + document.location.ancestorOrigins.length > 0 + ? document.location.ancestorOrigins[0] + : document.referrer + ) + } + + return urlParams.get('integratorUrl') || "Pas d'URL d'intégration" + } + + // Set up the intersection observer + useEffect(() => { + if (!isIframe) { + return + } + + const node = ref.current + if (!node) return + + // Add interaction listeners + const handleInteraction = () => { + setHasInteracted(true) + } + + node.addEventListener('click', handleInteraction) + node.addEventListener('touchstart', handleInteraction) + + const hasIOSupport = !!window.IntersectionObserver + if (!hasIOSupport) { + return () => { + node.removeEventListener('mouseenter', handleInteraction) + node.removeEventListener('click', handleInteraction) + node.removeEventListener('touchstart', handleInteraction) + } + } + + const observer = new IntersectionObserver(([entry]) => setEntry(entry)) + observer.observe(node) + + return () => { + observer.disconnect() + node.removeEventListener('mouseenter', handleInteraction) + node.removeEventListener('click', handleInteraction) + node.removeEventListener('touchstart', handleInteraction) + } + }, [ref, isIframe]) + + // Track the page view when the iframe is visible + useEffect(() => { + if (!isIframe) { + return + } + + if (!observed && entry && entry.isIntersecting) { + // Track the page view + trackPageView(url) + + // And with an event + const urlInteractor = getIntegratorUrl(isIframe) + + trackEvent(trackingIframeVisit(urlInteractor)) + } + }, [entry, observed, url, isIframe]) + + // Track the iframe event when the iframe is visible AND has been interacted with + useEffect(() => { + if (!isIframe || !hasInteracted) { + return + } + + if (!observed && entry && entry.isIntersecting) { + setObserved(true) + + const urlInteractor = getIntegratorUrl(isIframe) + + trackEvent(trackingIframeInteraction(urlInteractor)) + } + }, [entry, observed, path, isIframe, hasInteracted]) + + return ref +} diff --git a/src/hooks/tracking/useTrackLocale.ts b/src/hooks/tracking/useTrackLocale.ts index 2d2977b03..a0c0da100 100644 --- a/src/hooks/tracking/useTrackLocale.ts +++ b/src/hooks/tracking/useTrackLocale.ts @@ -1,5 +1,5 @@ import { trackingLocale } from '@/constants/tracking/misc' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useEffect } from 'react' import { useLocale } from '../useLocale' diff --git a/src/hooks/tracking/useTrackPageView.ts b/src/hooks/tracking/useTrackPageView.ts index fceec411e..63633f985 100644 --- a/src/hooks/tracking/useTrackPageView.ts +++ b/src/hooks/tracking/useTrackPageView.ts @@ -1,72 +1,19 @@ -import { locales } from '@/i18nConfig' -import { trackPageView } from '@/utils/matomo/trackEvent' -import { usePathname, useSearchParams } from 'next/navigation' +import { trackPageView } from '@/utils/analytics/trackEvent' +import { useSearchParams } from 'next/navigation' import { useEffect } from 'react' - -function handleOrganisationModifications(url: string) { - // Replace the organisation slug by the placeholder - const pathNameSegment = url.split('/').filter((segment) => segment !== '') - - let urlModified = url - if ( - pathNameSegment[0] === 'organisations' && - !['connexion', 'creer', 'demander-demo', 'creer-campagne'].includes( - pathNameSegment[1] - ) - ) { - urlModified = urlModified.replace(pathNameSegment[1], 'orga_slug') - } - - // Replace the poll slug by the placeholder - if (pathNameSegment[2] === 'campagnes') { - urlModified = urlModified.replace(pathNameSegment[3], 'poll_slug') - } - - return urlModified -} +import { useGetTrackedUrl } from './useGetTrackedUrl' export function useTrackPageView() { - const pathname = usePathname() const searchParams = useSearchParams() - useEffect(() => { - let url = pathname - - // We remove the lang prefix from the pathname - locales.map((locale) => { - if (pathname?.startsWith(`/${locale}`)) { - url = pathname.slice(3) - } - }) - - // We don't want to track the slugs of the organisations and theirs polls - url = handleOrganisationModifications(url) + const url = useGetTrackedUrl() - // We convert the question searchParams to a real url - const questionParams = searchParams.get('question') - if (questionParams) { - const category = questionParams.split('.')[0] - const question = questionParams.replace(category + '.', '') - url += `/${category}/${question}` - } - - // We convert the groupId to a real url - const groupId = searchParams.get('groupId') - if (groupId) { - url += `/${groupId}` - } - - // We add a trailing slash - if (!url.endsWith('/')) { - url += '/' - } - - // We add the searchParams to the url - const search = searchParams.toString() - if (search) { - url += `?${search}` + useEffect(() => { + // Skip tracking if iframe=true is present + if (searchParams.get('iframe') === 'true') { + return } trackPageView(url) - }, [pathname, searchParams]) + }, [url, searchParams]) } diff --git a/src/hooks/tracking/useTrackRegion.ts b/src/hooks/tracking/useTrackRegion.ts index fbe377ea0..9f3a62a0f 100644 --- a/src/hooks/tracking/useTrackRegion.ts +++ b/src/hooks/tracking/useTrackRegion.ts @@ -1,6 +1,6 @@ import { trackingRegion } from '@/constants/tracking/misc' import { useUser } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useEffect } from 'react' export function useTrackRegion() { diff --git a/src/hooks/tracking/useTrackSimulateur.ts b/src/hooks/tracking/useTrackSimulateur.ts index be3e395a6..4ccbc6e42 100644 --- a/src/hooks/tracking/useTrackSimulateur.ts +++ b/src/hooks/tracking/useTrackSimulateur.ts @@ -5,7 +5,7 @@ import { simulationSimulationStarted, } from '@/constants/tracking/simulation' import { useCurrentSimulation, useForm } from '@/publicodes-state' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useEffect, useRef } from 'react' export function useTrackSimulateur() { diff --git a/src/hooks/tracking/useTrackSplitTesting.ts b/src/hooks/tracking/useTrackSplitTesting.ts index 74b2fc31a..adee35cf3 100644 --- a/src/hooks/tracking/useTrackSplitTesting.ts +++ b/src/hooks/tracking/useTrackSplitTesting.ts @@ -1,5 +1,5 @@ import { trackingSplitTesting } from '@/constants/tracking/misc' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useEffect } from 'react' export function useTrackSplitTesting() { diff --git a/src/hooks/tracking/useTrackTimeOnSimulation.ts b/src/hooks/tracking/useTrackTimeOnSimulation.ts index 642788f77..bb3cfbe71 100644 --- a/src/hooks/tracking/useTrackTimeOnSimulation.ts +++ b/src/hooks/tracking/useTrackTimeOnSimulation.ts @@ -1,5 +1,5 @@ import { simulationSimulationCompletedTime } from '@/constants/tracking/simulation' -import { trackEvent } from '@/utils/matomo/trackEvent' +import { trackEvent } from '@/utils/analytics/trackEvent' import { useCallback, useMemo } from 'react' export function useTrackTimeOnSimulation() { @@ -8,7 +8,11 @@ export function useTrackTimeOnSimulation() { const trackTimeOnSimulation = useCallback(() => { const endTime = Date.now() const timeSpentOnSimulation = endTime - startTime - trackEvent(simulationSimulationCompletedTime({ timeSpentOnSimulation })) + trackEvent( + simulationSimulationCompletedTime({ + timeSpentOnSimulation, + }) + ) }, [startTime]) return { trackTimeOnSimulation } diff --git a/src/hooks/useMainNewsletter.ts b/src/hooks/useMainNewsletter.ts new file mode 100644 index 000000000..568cbe20f --- /dev/null +++ b/src/hooks/useMainNewsletter.ts @@ -0,0 +1,21 @@ +import { keepPreviousData, useQuery } from '@tanstack/react-query' +import axios from 'axios' +import { LIST_MAIN_NEWSLETTER } from '../constants/brevo' +import { NEWSLETTER_URL } from '../constants/urls' + +export type Newsletter = { + id: number + name: string + totalSubscribers: number +} + +export function useMainNewsletter() { + return useQuery({ + queryKey: ['mainNewsletter'], + queryFn: () => + axios + .get<Newsletter>(`${NEWSLETTER_URL}/${LIST_MAIN_NEWSLETTER}`) + .then((res) => res.data), + placeholderData: keepPreviousData, + }) +} diff --git a/src/hooks/useNumberSubscriber.ts b/src/hooks/useNumberSubscriber.ts deleted file mode 100644 index 7fd216149..000000000 --- a/src/hooks/useNumberSubscriber.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { keepPreviousData, useQuery } from '@tanstack/react-query' -import axios from 'axios' - -export function useNumberSubscribers(): { - data: number | undefined -} { - return useQuery({ - queryKey: ['number subscribers'], - queryFn: () => - axios - .get('/api/get-newsletter-subscribers-number') - .then((res) => res.data as string), - placeholderData: keepPreviousData, - }) -} diff --git a/src/locales/nouveautes/en/las-neous.mdx b/src/locales/nouveautes/en/las-neous.mdx index cfd405c3f..b96176080 100644 --- a/src/locales/nouveautes/en/las-neous.mdx +++ b/src/locales/nouveautes/en/las-neous.mdx @@ -80,7 +80,7 @@ In particular, we've optimized the footprint distribution graph, integrating tex ### Site hosting -We've <a href="https://answers.netlify.com/t/low-carbon-european-cdn/48784">asked</a> our hosting provider (Netlify) if it would be possible for them to implement a server in France so that our users can see their site served from France, rather than from Germany at present. +~~We've <a href="https://answers.netlify.com/t/low-carbon-european-cdn/48784">asked</a> our hosting provider (Netlify) if it would be possible for them to implement a server in France so that our users can see their site served from France, rather than from Germany at present.~~ (deprecated) ## Coming in 2022 diff --git a/src/locales/nouveautes/en/lempreinte-climat-des-services-societaux.mdx b/src/locales/nouveautes/en/lempreinte-climat-des-services-societaux.mdx index 41296eafa..b98123c99 100644 --- a/src/locales/nouveautes/en/lempreinte-climat-des-services-societaux.mdx +++ b/src/locales/nouveautes/en/lempreinte-climat-des-services-societaux.mdx @@ -71,9 +71,7 @@ On the other hand, things are more complicated for the "🏗️ construction" li </details> -As far as market services are concerned, we have tried to include in the basic footprint consumption that is relatively universal (e.g., everyone has to take out home insurance) or that is not yet taken into account by our micro models (e.g., consumption of telecommunications services), but which may be one day. - -If you're interested, you can explore our documentation explaining and justifying this allocation via the <a href="https://nosgestesclimat.fr/documentation/services-publics">public services</a> and <a href="https://nosgestesclimat.netlify.app/documentation/services-marchands">market services</a> pages. It's quite "expert", but we've done our best for a first version, and your feedback will be invaluable. +If you're interested, you can explore our documentation explaining and justifying this allocation via the <a href="https://nosgestesclimat.fr/documentation/services%20soci%C3%A9taux%20.%20services%20publics">public services</a> and <a href="https://nosgestesclimat.fr/documentation/services-soci%C3%A9taux/services-marchands">market services</a> pages. It's quite "expert", but we've done our best for a first version, and your feedback will be invaluable. ## The result diff --git a/src/locales/nouveautes/en/periades.mdx b/src/locales/nouveautes/en/periades.mdx index 1750e8c84..3abaaf5a0 100644 --- a/src/locales/nouveautes/en/periades.mdx +++ b/src/locales/nouveautes/en/periades.mdx @@ -46,7 +46,7 @@ On PR number <a href="https://github.com/incubateur-ademe/nosgestesclimat-site/p It will be useful for conferences and workshops, as well as for testing with friends. -To test it, click <a href="https://conf--nosgestesclimat.netlify.app/conférence">here 🏹 🏹</a> +~~To test it, click <a href="">here 🏹 🏹</a>~~ (deprecated) ![Capture d’écran du 2021-04-27 17-59-21](https://user-images.githubusercontent.com/1177762/116273752-5515a100-a782-11eb-8483-c378c2c7406e.png) diff --git a/src/locales/nouveautes/es/las-neous.mdx b/src/locales/nouveautes/es/las-neous.mdx index ce258da67..fb6ba6ca0 100644 --- a/src/locales/nouveautes/es/las-neous.mdx +++ b/src/locales/nouveautes/es/las-neous.mdx @@ -80,7 +80,7 @@ En particular, hemos optimizado el gráfico de distribución de la huella, integ ### Alojamiento del sitio -Hemos <a href="https://answers.netlify.com/t/low-carbon-european-cdn/48784">preguntado</a> a nuestro proveedor de alojamiento (Netlify) si sería posible que instalara un servidor en Francia para que nuestros usuarios puedan ver su sitio servido desde Francia, en lugar de desde Alemania en la actualidad. +~~Hemos <a href="https://answers.netlify.com/t/low-carbon-european-cdn/48784">preguntado</a> a nuestro proveedor de alojamiento (Netlify) si sería posible que instalara un servidor en Francia para que nuestros usuarios puedan ver su sitio servido desde Francia, en lugar de desde Alemania en la actualidad.~~ (obsoleto) ## Próximamente en 2022 diff --git a/src/locales/nouveautes/es/lempreinte-climat-des-services-societaux.mdx b/src/locales/nouveautes/es/lempreinte-climat-des-services-societaux.mdx index 9f7e68957..a2283ae8a 100644 --- a/src/locales/nouveautes/es/lempreinte-climat-des-services-societaux.mdx +++ b/src/locales/nouveautes/es/lempreinte-climat-des-services-societaux.mdx @@ -75,7 +75,7 @@ En cambio, las cosas son más complicadas para la partida "🏗️ construcción En cuanto a los servicios de mercado, hemos intentado incluir en la huella básica consumos que son relativamente universales (por ejemplo, todo el mundo tiene que contratar un seguro de hogar) o que todavía no se tienen en cuenta en nuestros modelos micro (por ejemplo, el consumo de servicios de telecomunicaciones), pero que podrían llegar a serlo algún día. -Si le interesa, puede explorar nuestra documentación explicativa y justificativa de esta asignación en las páginas de <a href="https://nosgestesclimat.fr/documentation/services-publics">servicios públicos</a> y <a href="https://nosgestesclimat.netlify.app/documentation/services-marchands">servicios de mercado</a>. Hemos hecho todo lo posible para una primera versión, pero sus comentarios serán inestimables. +Si le interesa, puede explorar nuestra documentación explicativa y justificativa de esta asignación en las páginas de <a href="https://nosgestesclimat.fr/documentation/services%20soci%C3%A9taux%20.%20services%20publics">servicios públicos</a> y <a href="https://nosgestesclimat.fr/documentation/services-soci%C3%A9taux/services-marchands">servicios de mercado</a>. Hemos hecho todo lo posible para una primera versión, pero sus comentarios serán inestimables. ## El resultado diff --git a/src/locales/nouveautes/es/periades.mdx b/src/locales/nouveautes/es/periades.mdx index 394b83a09..d656b110c 100644 --- a/src/locales/nouveautes/es/periades.mdx +++ b/src/locales/nouveautes/es/periades.mdx @@ -46,7 +46,7 @@ En el RP número <a href="https://github.com/incubateur-ademe/nosgestesclimat-si Será útil para conferencias y talleres, así como para simplemente hacer pruebas con amigos. -Para probarlo, <a href="https://conf--nosgestesclimat.netlify.app/conférence">haz clic aquí 🏹🏹🏹</a> +~~Para probarlo, <a href="">haz clic aquí 🏹🏹🏹</a>~~ (obsoleto) ![Capture d’écran du 2021-04-27 17-59-21](https://user-images.githubusercontent.com/1177762/116273752-5515a100-a782-11eb-8483-c378c2c7406e.png) diff --git a/src/locales/nouveautes/fr/las-neous.mdx b/src/locales/nouveautes/fr/las-neous.mdx index 952eed49f..17c9c81e9 100644 --- a/src/locales/nouveautes/fr/las-neous.mdx +++ b/src/locales/nouveautes/fr/las-neous.mdx @@ -80,7 +80,7 @@ Pour ce faire, nous avons notamment optimisé le graphique de répartition de l' ### Hébergement du site -Nous avons [demandé](https://answers.netlify.com/t/low-carbon-european-cdn/48784) à notre hébergeur (Netlify), s'il serait possible qu'ils implémentent un serveur en France pour que nos utilisateurs voient leur site servi depuis la France, plutôt que depuis l'Allemagne actuellement. +~~Nous avons [demandé](https://answers.netlify.com/t/low-carbon-european-cdn/48784) à notre hébergeur (Netlify), s'il serait possible qu'ils implémentent un serveur en France pour que nos utilisateurs voient leur site servi depuis la France, plutôt que depuis l'Allemagne actuellement.~~ (obsolète) ## À venir en 2022 diff --git a/src/locales/nouveautes/fr/lempreinte-climat-des-services-societaux.mdx b/src/locales/nouveautes/fr/lempreinte-climat-des-services-societaux.mdx index 16dd2c44f..d26e1180c 100644 --- a/src/locales/nouveautes/fr/lempreinte-climat-des-services-societaux.mdx +++ b/src/locales/nouveautes/fr/lempreinte-climat-des-services-societaux.mdx @@ -75,7 +75,7 @@ En revanche, les choses se compliquent par exemple pour le poste \"🏗️ const En ce qui concerne les services marchands, nous avons tâché d'inclure dans l'empreinte de base les consommations relativement universelles (tout le monde doit par exemple souscrire à une assurance habitation) ou celles qui ne sont pas encore prises en compte par nos modèles micro (par exemple, la consommation de services de télécommunications) mais qui le seront peut-être un jour. -Si cela vous intéresse, vous pouvez explorer notre documentation qui explique et justifie cette attribution via les pages [services publics](https://nosgestesclimat.fr/documentation/services-publics) et [services marchands](https://nosgestesclimat.netlify.app/documentation/services-marchands). C'est assez \"expert\", nous avons fait au mieux pour une première version, vos retours seront précieux. +Si cela vous intéresse, vous pouvez explorer notre documentation qui explique et justifie cette attribution via les pages [services publics](https://nosgestesclimat.fr/documentation/services%20soci%C3%A9taux%20.%20services%20publics) et [services marchands](https://nosgestesclimat.fr/documentation/services-soci%C3%A9taux/services-marchands). C'est assez \"expert\", nous avons fait au mieux pour une première version, vos retours seront précieux. ## Le résultat diff --git a/src/locales/nouveautes/fr/periades.mdx b/src/locales/nouveautes/fr/periades.mdx index 70645745c..f7cb45208 100644 --- a/src/locales/nouveautes/fr/periades.mdx +++ b/src/locales/nouveautes/fr/periades.mdx @@ -46,7 +46,7 @@ Sur la PR numéro [222](https://github.com/incubateur-ademe/nosgestesclimat-site Elle sera utile pour les conférence, pour les ateliers, mais aussi pour simplement faire le test avec des amis. -Pour la tester, [c'est par ici 🏹 🏹](https://conf--nosgestesclimat.netlify.app/conférence) +~~Pour la tester, [c'est par ici 🏹 🏹]()~~ (obsolète) ![Capture d’écran du 2021-04-27 17-59-21](https://user-images.githubusercontent.com/1177762/116273752-5515a100-a782-11eb-8483-c378c2c7406e.png) diff --git a/src/locales/ui/ui-en.yaml b/src/locales/ui/ui-en.yaml index bd997774e..5fba591ec 100644 --- a/src/locales/ui/ui-en.yaml +++ b/src/locales/ui/ui-en.yaml @@ -1568,3 +1568,9 @@ entries: Super, vous êtes déjà inscrit !: Great, you're already registered! Diffuser Nos Gestes Climat: Spreading Our Gestes Climat 'Oups, une erreur est survenue lors de la copie du lien, voici le lien à copier / coller :': 'Oops, there was an error copying the link, here is the link to copy / paste :' + Vous devez renseigner le type de votre organisation: You must enter the type of organisation + Nombre de participants attendus: Number of participants expected + Service public: Public services + Votre poste: Your position + Le nombre de participants doit être supérieur à 0: The number of participants must be greater than 0 + Veuillez entrer un nombre positif: Please enter a positive number diff --git a/src/locales/ui/ui-es.yaml b/src/locales/ui/ui-es.yaml index 7802e0517..97def877b 100644 --- a/src/locales/ui/ui-es.yaml +++ b/src/locales/ui/ui-es.yaml @@ -1561,3 +1561,9 @@ entries: Diffuser Nos Gestes Climat: Difundir Nos Gestes Climat Super, vous êtes déjà inscrit !: Genial, ¡ya estás registrado! 'Oups, une erreur est survenue lors de la copie du lien, voici le lien à copier / coller :': 'Oops, hubo un error al copiar el enlace, aquí está el enlace para copiar / pegar :' + Vous devez renseigner le type de votre organisation: Debe introducir el tipo de organización + Votre poste: Su posición + Service public: Servicios públicos + Nombre de participants attendus: Número previsto de participantes + Le nombre de participants doit être supérieur à 0: El número de participantes debe ser superior a 0 + Veuillez entrer un nombre positif: Introduzca un número positivo diff --git a/src/locales/ui/ui-fr.yaml b/src/locales/ui/ui-fr.yaml index bd3429682..79f1fb83f 100644 --- a/src/locales/ui/ui-fr.yaml +++ b/src/locales/ui/ui-fr.yaml @@ -131,7 +131,6 @@ entries: Ce modèle a été conçu par: Ce modèle a été conçu par model.questions: Découvrez <2>la liste des questions disponibles dans le modèle</2>. Oups, nous n'avons pas d'article correspondant: Oups, nous n'avons pas d'article correspondant - Retour à la liste des articles: Retour à la liste des articles Blog: Blog simulations terminées: simulations terminées Statistiques Northstar: Statistiques Northstar @@ -188,14 +187,12 @@ entries: Comparez vos résultats avec votre famille ou un groupe d’ami·e·s: Comparez vos résultats avec votre famille ou un groupe d’ami·e·s Consultez la FAQ: Consultez la FAQ 'Date complète :': 'Date complète :' - 'Découvrez nos articles de blog :': 'Découvrez nos articles de blog :' disponibles: disponibles Entrez des mots-clefs de recherche: Entrez des mots-clefs de recherche Fermer le bandeau de feedback: Fermer le bandeau de feedback 'Identifiant :': 'Identifiant :' Il concerne votre vie personnelle, et non pas votre boulot.: Il concerne votre vie personnelle, et non pas votre boulot. international.comment.2: Explorez en détail les spécificités de chaque pays. - Le Blog: Le Blog Les personas nous servent à tester le calculateur sous toutes ses coutures, et à vérifier qu’il s’adapte bien à toutes les situations de vie des citoyens métropolitains. De par leur présence, ils nous forcent à penser à tous les cas d’usage, pour nous projeter dans différentes réalités, et inclure ces réalités dans nos refontes du parcours de test et des actions proposées à la fin de ce dernier.: Les personas nous servent à tester le calculateur sous toutes ses coutures, et à vérifier qu’il s’adapte bien à toutes les situations de vie des citoyens métropolitains. De par leur présence, ils nous forcent à penser à tous les cas d’usage, pour nous projeter dans différentes réalités, et inclure ces réalités dans nos refontes du parcours de test et des actions proposées à la fin de ce dernier. Logo de l'Association pour la transition Bas Carbone: Logo de l'Association pour la transition Bas Carbone Mes réponses: Mes réponses @@ -311,7 +308,6 @@ entries: Votre prénom: Votre prénom Code renvoyé: Code renvoyé L’adresse e-mail est invalide: L’adresse e-mail est invalide - Vous devez renseigner le nom de votre organisation: Vous devez renseigner le nom de votre organisation Vous devez renseigner votre adresse e-mail: Vous devez renseigner votre adresse e-mail Accueil: Accueil Animez un atelier: Animez un atelier @@ -447,8 +443,6 @@ entries: Accessibilité - Nos Gestes Climat: Accessibilité - Nos Gestes Climat 'Actions : comment réduire votre empreinte climat ? - Nos Gestes Climat': 'Actions : comment réduire votre empreinte climat ? - Nos Gestes Climat' Actions, suite à votre simulation d'empreinte climat - Nos Gestes Climat: Actions, suite à votre simulation d'empreinte climat - Nos Gestes Climat - article du blog - Nos Gestes Climat: article du blog - Nos Gestes Climat - Blog - Nos Gestes Climat: Blog - Nos Gestes Climat Budget - Nos Gestes Climat: Budget - Nos Gestes Climat Calculer votre empreinte carbone avec vos amis - Nos Gestes Climat: Calculer votre empreinte carbone avec vos amis - Nos Gestes Climat Calculer votre empreinte carbone individuelle - Nos Gestes Climat: Calculer votre empreinte carbone individuelle - Nos Gestes Climat @@ -464,7 +458,6 @@ entries: Découvrez comment nous utilisons vos données personnelles pour vous proposer un calculateur de bilan carbone personnel.: Découvrez comment nous utilisons vos données personnelles pour vous proposer un calculateur de bilan carbone personnel. Découvrez le modèle de données de notre calculateur d'empreinte climat: Découvrez le modèle de données de notre calculateur d'empreinte climat Découvrez les actions que vous pouvez mettre en place pour réduire votre empreinte carbone.: Découvrez les actions que vous pouvez mettre en place pour réduire votre empreinte carbone. - Découvrez les articles de blog du site Nos Gestes Climat.: Découvrez les articles de blog du site Nos Gestes Climat. Découvrez les nouveautés du site Nos Gestes Climat.: Découvrez les nouveautés du site Nos Gestes Climat. Découvrez les personas d'utilisateurs types qui nous servent à tester le calculateur sous toutes ses coutures.: Découvrez les personas d'utilisateurs types qui nous servent à tester le calculateur sous toutes ses coutures. Diffuser notre calculateur d'empreinte climat - Nos Gestes Climat: Diffuser notre calculateur d'empreinte climat - Nos Gestes Climat @@ -549,16 +542,12 @@ entries: Questions complémentaires: Questions complémentaires Association: Association Autre: Autre - 'Avez-vous essayé <2>notre fonctionnalité “Groupes d’amis”</2> ? Elle vous permettra de vous comparer dans un classement : que celui ou celle ayant la plus faible empreinte gagne !': 'Avez-vous essayé <2>notre fonctionnalité “Groupes d’amis”</2> ? Elle vous permettra de vous comparer dans un classement : que celui ou celle ayant la plus faible empreinte gagne !' - Coopérative: Coopérative Créer ma première campagne: Créer ma première campagne Entreprise: Entreprise Groupe d'amis: Groupe d'amis Le mode organisation est un mode <1>100% anonyme</1> pour les participants.: Le mode organisation est un mode <1>100% anonyme</1> pour les participants. - Public ou collectivité territoriale: Public ou collectivité territoriale Type d'organisation: Type d'organisation Université ou école: Université ou école - Vous devez renseigner votre nom: Vous devez renseigner votre nom Voir moins: Voir moins Voir plus: Voir plus (Attendre: (Attendre @@ -668,10 +657,7 @@ entries: Tableau de bord: Tableau de bord vous souhaitez lancer une campagne Nos Gestes Climat et sensibiliser toutes vos parties prenantes ? Découvrez nos outils 100% gratuits !: vous souhaitez lancer une campagne Nos Gestes Climat et sensibiliser toutes vos parties prenantes ? Découvrez nos outils 100% gratuits ! Ils ont testé: Ils ont testé - mis à jour le: mis à jour le - 'Un article de ': 'Un article de ' 'Découvrez les relais de Nos Gestes Climat : organisations, collectivités, médias, influenceurs, etc.': 'Découvrez les relais de Nos Gestes Climat : organisations, collectivités, médias, influenceurs, etc.' - Nos relais: Nos relais Nos relais - Nos Gestes Climat: Nos relais - Nos Gestes Climat 'N.B. : aucun acteur cité ci-dessous ne finance Nos Gestes Climat, qui est et restera un service public, indépendant et gratuit de l’ADEME.': 'N.B. : aucun acteur cité ci-dessous ne finance Nos Gestes Climat, qui est et restera un service public, indépendant et gratuit de l’ADEME.' ', le': ', le' @@ -780,7 +766,6 @@ entries: chrono pour calculer votre empreinte carbone et eau: chrono pour calculer votre empreinte carbone et eau Comment <1>agir</1> ?: Comment <1>agir</1> ? Comment on la mesure ?: Comment on la mesure ? - d'eau <1>par jour</1>: d'eau <1>par jour</1> d’eau domestique par jour: d’eau domestique par jour D’où vient mon empreinte ?: D’où vient mon empreinte ? Découvre mes empreintes: Découvre mes empreintes @@ -1084,7 +1069,6 @@ entries: Un tee-shirt, symbolisant la consommation d'eau pour l'industrie textile: Un tee-shirt, symbolisant la consommation d'eau pour l'industrie textile Une balance indiquant la quantité d'eau nécessaire pour produire un ordinateur: Une balance indiquant la quantité d'eau nécessaire pour produire un ordinateur Une pomme, symbolisant le lien entre eau et agriculture: Une pomme, symbolisant le lien entre eau et agriculture - <0>2 millions de personnes</0> ont déjà <3></3>calculé leur empreinte !: <0>2 millions de personnes</0> ont déjà <3></3>calculé leur empreinte ! Libre et documenté: Libre et documenté L’empreinte eau d'un jean est de 30 000 litres d'eau.: L’empreinte eau d'un jean est de 30 000 litres d'eau. La production d’un ordinateur nécessite 195 000 litres d’eau.: La production d’un ordinateur nécessite 195 000 litres d’eau. @@ -1149,8 +1133,6 @@ entries: La valeur pour ce champ est comprise entre: La valeur pour ce champ est comprise entre En participant vous acceptez que vos résultats soient partagés anonymement avec cette organisation.: En participant vous acceptez que vos résultats soient partagés anonymement avec cette organisation. '{{signe}} {{value}} {{unit}} sur votre empreinte {{metric}}': '{{signe}} {{value}} {{unit}} sur votre empreinte {{metric}}' - d'eau / jour: d'eau / jour - de CO₂e / an: de CO₂e / an Aide: Aide Cette section statistique est générée via Metabase.: Cette section statistique est générée via Metabase. Il est question ici des modes "Organisations" et "Challenge tes amis". Cette section est générée via Metabase.: Il est question ici des modes "Organisations" et "Challenge tes amis". Cette section est générée via Metabase. @@ -1160,11 +1142,16 @@ entries: Empreinte carbone, voir le détail ci-dessous: Empreinte carbone, voir le détail ci-dessous Empreinte eau, sélectionné, voir le détail ci-dessous: Empreinte eau, sélectionné, voir le détail ci-dessous Empreinte eau, voir le détail ci-dessous: Empreinte eau, voir le détail ci-dessous - Bien noté ! Vous aurez prochainement de nos nouvelles.: Bien noté ! Vous aurez prochainement de nos nouvelles. Diffuser Nos Gestes Climat: Diffuser Nos Gestes Climat - Inscrivez-vous à notre infolettre: Inscrivez-vous à notre infolettre Qui sommes-nous: Qui sommes-nous Relais et partenaires: Relais et partenaires Ressources: Ressources - Super, vous êtes déjà inscrit !: Super, vous êtes déjà inscrit ! 'Oups, une erreur est survenue lors de la copie du lien, voici le lien à copier / coller :': 'Oups, une erreur est survenue lors de la copie du lien, voici le lien à copier / coller :' + Le nombre de participants doit être supérieur à 0: Le nombre de participants doit être supérieur à 0 + Nombre de participants attendus: Nombre de participants attendus + Service public: Service public + Votre poste: Votre poste + Vous devez renseigner le type de votre organisation: Vous devez renseigner le type de votre organisation + 'Avez-vous essayé <2>notre fonctionnalité “Groupes d’amis”</2> ? Elle vous permettra de vous comparer dans un classement : que celui ou celle ayant la plus faible empreinte gagne !': 'Avez-vous essayé <2>notre fonctionnalité “Groupes d’amis”</2> ? Elle vous permettra de vous comparer dans un classement : que celui ou celle ayant la plus faible empreinte gagne !' + Coopérative: Coopérative + Veuillez entrer un nombre positif: Veuillez entrer un nombre positif diff --git a/src/types/organisations.d.ts b/src/types/organisations.d.ts index 74187f88b..9127b841a 100644 --- a/src/types/organisations.d.ts +++ b/src/types/organisations.d.ts @@ -33,7 +33,7 @@ type BaseOrganisation = { slug: string administrators?: [VerifiedUser] polls?: Omit<OrganisationPoll, 'simulations'>[] - type?: OrganisationTypeEnum | null + type?: OrganisationTypeEnum numberOfCollaborators?: number | null hasCustomQuestionEnabled?: boolean createdAt?: string @@ -110,7 +110,9 @@ export type OrgaSettingsInputsType = { name: string email: string position?: string - administratorName?: string + administratorFirstName?: string + administratorLastName?: string + administratorPosition?: string numberOfCollaborators?: number administratorTelephone?: string hasOptedInForCommunications?: boolean diff --git a/src/utils/matomo/trackEvent.ts b/src/utils/analytics/trackEvent.ts similarity index 54% rename from src/utils/matomo/trackEvent.ts rename to src/utils/analytics/trackEvent.ts index efe838cb1..12fc19264 100644 --- a/src/utils/matomo/trackEvent.ts +++ b/src/utils/analytics/trackEvent.ts @@ -1,3 +1,5 @@ +import posthog from 'posthog-js' + const shouldUseDevTracker = process.env.NODE_ENV === 'development' declare global { @@ -8,10 +10,25 @@ declare global { export const trackEvent = (args: (string | null)[]) => { if (shouldUseDevTracker || !window?._paq) { + console.log(args) console.debug(args.join(' => ')) return } + // Matomo: [ 'trackEvent', 'Category', 'Action', 'Name', 'Value' ] + // Exemple : ['trackEvent', 'Misc', 'Region', 'Region used: FR'] + // Or : ['trackEvent', 'Accueil', 'CTA Click', 'Click Reprendre le test'] + // Or : ['trackEvent', 'Simulation', 'Simulation Completed', null, '8.9'] + // Or : ['trackEvent', 'Simulation', 'Simulation Time', null, '3'] + // Or : ['trackEvent', 'Fin', 'Toggle Target block'] + // FIXME: Convert properly events to posthog with better precision + + posthog.capture(args[2] ? args[2] : 'Fix Event Name', { + category: args[1], + description: args[3], + value: args[4], + }) + // Pass a copy of the array to avoid mutation window?._paq?.push([...args]) } @@ -22,6 +39,8 @@ export const trackPageView = (url: string) => { return } + posthog.capture('$pageview', { $current_url: url }) + window?._paq?.push(['setCustomUrl', url]) window?._paq?.push(['setDocumentTitle', document?.title]) diff --git a/yarn.lock b/yarn.lock index 0a500b9a6..2050cb1bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1143,10 +1143,10 @@ prompt-sync "^4.2.0" yargs "^17.7.2" -"@incubateur-ademe/nosgestesclimat@3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@incubateur-ademe/nosgestesclimat/-/nosgestesclimat-3.5.1.tgz#4c156b558aa1a79d3cce9192e3525963390d965f" - integrity sha512-OrlU6gVZKQerGl+8NknOghr7upOe7EgZT4cY18+b/Di40D8jtnXiqZqsHT3Jz8b6xpBruyTgHU38ztnek5hYHg== +"@incubateur-ademe/nosgestesclimat@3.5.4": + version "3.5.4" + resolved "https://registry.yarnpkg.com/@incubateur-ademe/nosgestesclimat/-/nosgestesclimat-3.5.4.tgz#d815600d4024b35aa52ba90bac2c7a1bbbf5ad72" + integrity sha512-AiJg2sm4jV6jZWOkHYQV+qLkEptEAcU0ACLfcdTUhcm8wDz2AzrcMxMgexmTnguh3T6FcSamBAjvc4gZQwbQwQ== "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" @@ -4339,6 +4339,11 @@ core-js@^3.33.2: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.37.0.tgz#d8dde58e91d156b2547c19d8a4efd5c7f6c426bb" integrity sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug== +core-js@^3.38.1: + version "3.40.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.40.0.tgz#2773f6b06877d8eda102fc42f828176437062476" + integrity sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ== + core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -5794,6 +5799,11 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" +fflate@^0.4.8: + version "0.4.8" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" + integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== + figures@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -8998,6 +9008,21 @@ postgres-range@^1.1.1: resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863" integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== +posthog-js@^1.217.2: + version "1.217.2" + resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.217.2.tgz#d1a7ab37632954a5e24591d1ca3f3a2116c939d5" + integrity sha512-3KC+UjI0UT5zh8kAOVqe/AfvRjBMKynRIBQNlv0TXnfpZG0+h3r/1ONecDgCCGLs/a/55SJCExrugDlx+HPH3w== + dependencies: + core-js "^3.38.1" + fflate "^0.4.8" + preact "^10.19.3" + web-vitals "^4.2.0" + +preact@^10.19.3: + version "10.25.4" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.25.4.tgz#c1d00bee9d7b9dcd06a2311d9951973b506ae8ac" + integrity sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -10941,6 +10966,11 @@ watchpack@^2.4.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" +web-vitals@^4.2.0: + version "4.2.4" + resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.4.tgz#1d20bc8590a37769bd0902b289550936069184b7" + integrity sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"