Skip to content

Commit

Permalink
Affine l'affichage du comparateur avec des meilleurs liens et meilleu…
Browse files Browse the repository at this point in the history
…rs textes
  • Loading branch information
martinratinaud committed Feb 12, 2025
1 parent 9911924 commit ab16745
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 87 deletions.
215 changes: 129 additions & 86 deletions src/components/ComparateurPublicodes/ComparateurPublicodes.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { type DottedName } from '@betagouv/france-chaleur-urbaine-publicodes';
import { fr } from '@codegouvfr/react-dsfr';
import Alert from '@codegouvfr/react-dsfr/Alert';
import ToggleSwitch from '@codegouvfr/react-dsfr/ToggleSwitch';
import Drawer from '@mui/material/Drawer';
import { parseAsStringLiteral, useQueryState } from 'nuqs';
Expand All @@ -10,13 +9,18 @@ import AddressAutocomplete from '@/components/form/dsfr/AddressAutocompleteInput
import { FormProvider } from '@/components/form/publicodes/FormProvider';
import Label from '@/components/form/publicodes/Label';
import Accordion from '@/components/ui/Accordion';
import Alert from '@/components/ui/Alert';
import Box from '@/components/ui/Box';
import Button from '@/components/ui/Button';
import Heading from '@/components/ui/Heading';
import { FCUArrowIcon } from '@/components/ui/Icon';
import Link from '@/components/ui/Link';
import Notice from '@/components/ui/Notice';
import Text from '@/components/ui/Text';
import useEligibilityForm from '@/hooks/useEligibilityForm';
import { type LocationInfoResponse } from '@/pages/api/location-infos';
import { useServices } from '@/services';
import { type AddressDetail } from '@/types/HeatNetworksResponse';
import cx from '@/utils/cx';
import { postFetchJSON } from '@/utils/network';
import { slugify } from '@/utils/strings';
Expand Down Expand Up @@ -75,13 +79,14 @@ const ComparateurPublicodes: React.FC<ComparateurPublicodesProps> = ({
});

const [address, setAddress] = useQueryState('address');
const [addressDetail, setAddressDetail] = React.useState<AddressDetail>();
const [modesDeChauffage] = useQueryState('modes-de-chauffage');
const [lngLat, setLngLat] = React.useState<[number, number]>();
const [nearestReseauDeChaleur, setNearestReseauDeChaleur] = React.useState<LocationInfoResponse['nearestReseauDeChaleur']>();
const [addressError, setAddressError] = React.useState<boolean>(false);
const [nearestReseauDeFroid, setNearestReseauDeFroid] = React.useState<LocationInfoResponse['nearestReseauDeFroid']>();
const inclureLaClimatisation = engine.getField('Inclure la climatisation');

const { heatNetworkService } = useServices();
const advancedMode = displayMode === 'technicien';
const [selectedTabId, setSelectedTabId] = useQueryState(
'tabId',
Expand Down Expand Up @@ -112,20 +117,31 @@ const ComparateurPublicodes: React.FC<ComparateurPublicodesProps> = ({

const isAddressSelected = engine.getField('code département') !== undefined;

const results =
isAddressSelected && !!modesDeChauffage ? (
<Graph
engine={engine}
advancedMode={advancedMode}
usedReseauDeChaleurLabel={nearestReseauDeChaleur?.nom_reseau || 'Valeur moyenne'}
captureImageName={`${new Date().getFullYear()}-${slugify(address)}`}
/>
) : (
<ResultsNotAvailable />
);
const displayResults = isAddressSelected && !!modesDeChauffage;

const results = displayResults ? (
<Graph
engine={engine}
advancedMode={advancedMode}
usedReseauDeChaleurLabel={nearestReseauDeChaleur?.nom_reseau || 'Valeur moyenne'}
captureImageName={`${new Date().getFullYear()}-${slugify(address)}`}
/>
) : (
<ResultsNotAvailable />
);

const { open: displayContactForm, EligibilityFormModal } = useEligibilityForm({
id: `eligibility-form-comparateur`,
address: {
address,
coordinates: lngLat,
addressDetails: addressDetail,
},
});

return (
<>
<EligibilityFormModal />
<div className={cx(fr.cx('fr-container'), className)} {...props}>
<FormProvider engine={engine}>
<Section>
Expand Down Expand Up @@ -199,7 +215,11 @@ const ComparateurPublicodes: React.FC<ComparateurPublicodesProps> = ({
if (addressLabel !== address) {
setAddress(null);
}

const network = await heatNetworkService.findByCoords(selectedAddress);
setAddressDetail({
network,
geoAddress: selectedAddress,
});
const infos: LocationInfoResponse = await postFetchJSON('/api/location-infos', {
lon,
lat,
Expand Down Expand Up @@ -275,83 +295,106 @@ const ComparateurPublicodes: React.FC<ComparateurPublicodesProps> = ({
)}
</Box>
<Results>
{!loading && address && (
<Alert
className="fr-text--sm fr-mb-2w"
description={
nearestReseauDeChaleur ? (
<>
Le réseau de chaleur{' '}
<Link
href={`/reseaux/${nearestReseauDeChaleur['Identifiant reseau']}?address=${encodeURIComponent(
address as string
)}`}
isExternal
>
<strong>{nearestReseauDeChaleur.nom_reseau}</strong>
</Link>{' '}
est à <strong>{nearestReseauDeChaleur.distance}m</strong> de votre adresse.
{!nearestReseauDeChaleur?.PM && (
<Text color="warning" my="1v" size="xs">
À noter qu’en l'absence de données tarifaires pour ce réseau, les simulations se basent sur le prix de la
chaleur moyen des réseaux français.
</Text>
)}
{lngLat && (
<div className="fr-text--xs">
<Link isExternal href={`/carte?coord=${lngLat.join(',')}&zoom=17`} className="fr-block">
<strong>Visualiser sur la carte</strong>
</Link>
</div>
)}
</>
) : (
<>
En l'absence d'un <strong>réseau de chaleur</strong> à proximité, les simulations se basent sur le réseau de
chaleur français moyen
</>
)
}
severity={nearestReseauDeChaleur ? 'info' : 'warning'}
small
/>
{!displayResults && (
<Notice variant="info" className="mb-5">
{!isAddressSelected
? '1. Commencez par sélectionner une adresse'
: !modesDeChauffage
? '2. Maintenant, sélectionnez au moins un mode de chauffage'
: ''}
</Notice>
)}
{!loading && inclureLaClimatisation && address && (
<Alert
className="fr-text--sm fr-mb-2w"
description={
nearestReseauDeFroid ? (
<>
Le réseau de froid{' '}
<Link
href={`/reseaux/${nearestReseauDeFroid['Identifiant reseau']}?address=${encodeURIComponent(address as string)}`}
isExternal
>
<strong>{nearestReseauDeFroid.nom_reseau}</strong>
</Link>{' '}
est à <strong>{nearestReseauDeFroid.distance}m</strong> de votre adresse.

{!loading && address && displayResults && (
<Alert size="sm" className="mb-5" variant={nearestReseauDeChaleur ? 'info' : 'warning'}>
{nearestReseauDeChaleur ? (
<>
Le réseau de chaleur{' '}
<Link
href={`/reseaux/${nearestReseauDeChaleur['Identifiant reseau']}?address=${encodeURIComponent(address as string)}`}
isExternal
>
<strong>{nearestReseauDeChaleur.nom_reseau}</strong>
</Link>{' '}
est à <strong>{nearestReseauDeChaleur.distance}m</strong> de votre adresse.
{!nearestReseauDeChaleur?.PM && (
<Text color="warning" my="1v" size="xs">
À noter qu’en l'absence de données tarifaires pour ce réseau, les simulations se basent sur le prix du froid
moyen des réseaux français.
À noter qu’en l'absence de données tarifaires pour ce réseau, les simulations se basent sur le prix de la
chaleur moyen des réseaux français.
</Text>
)}
<p className="text-sm my-5">
Vous souhaitez recevoir des informations adaptées à votre bâtiment de la part du gestionnaire du réseau ? Nous
assurons votre mise en relation !
</p>
<div className="flex gap-5 items-center justify-end">
{lngLat && (
<div className="fr-text--xs">
<Link isExternal href={`/carte?coord=${lngLat.join(',')}&zoom=17`} className="fr-block">
<strong>Visualiser sur la carte</strong>
</Link>
</div>
<Link
isExternal
href={`/carte?coord=${lngLat.join(',')}&zoom=17&address=${encodeURIComponent(address as string)}`}
className="fr-block"
>
<strong>Visualiser sur la carte</strong>
</Link>
)}
</>
) : (
<>
En l'absence d'un <strong>réseau de froid</strong> à proximité, les simulations se basent sur le réseau de froid
français moyen
</>
)
}
severity={nearestReseauDeFroid ? 'info' : 'warning'}
small
/>
<Button onClick={displayContactForm} size="small">
Etre mis en relation avec le gestionnaire
</Button>
</div>
</>
) : (
<>
<p className="text-sm">
Il n'y a pas de réseau de chaleur à proximité de l'adresse testée.{' '}
<strong>Les simulations se basent sur le réseau de chaleur français moyen.</strong>
</p>
<p className="text-sm my-5">
Vous souhaitez faire connaître à la collectivité votre intérêt pour ce mode de chauffage ?
</p>
<div className="flex gap-5 items-center justify-end">
<Button onClick={displayContactForm} size="small">
Laissez vos coordonnées
</Button>
</div>
</>
)}
</Alert>
)}
{!loading && inclureLaClimatisation && address && displayResults && (
<Alert size="sm" className="mb-5" variant={nearestReseauDeFroid ? 'info' : 'warning'}>
{nearestReseauDeFroid ? (
<>
Le réseau de froid{' '}
<Link
href={`/reseaux/${nearestReseauDeFroid['Identifiant reseau']}?address=${encodeURIComponent(address as string)}`}
isExternal
>
<strong>{nearestReseauDeFroid.nom_reseau}</strong>
</Link>{' '}
est à <strong>{nearestReseauDeFroid.distance}m</strong> de votre adresse.
<Text color="warning" my="1v" size="xs">
À noter qu’en l'absence de données tarifaires pour ce réseau, les simulations se basent sur le prix du froid moyen
des réseaux français.
</Text>
{lngLat && (
<div className="fr-text--xs">
<Link
isExternal
href={`/carte?coord=${lngLat.join(',')}&zoom=17&address=${encodeURIComponent(address as string)}`}
className="fr-block"
>
<strong>Visualiser sur la carte</strong>
</Link>
</div>
)}
</>
) : (
<>
En l'absence d'un <strong>réseau de froid</strong> à proximité, les simulations se basent sur le réseau de froid
français moyen
</>
)}
</Alert>
)}
{results}
</Results>
Expand Down
5 changes: 4 additions & 1 deletion src/components/Map/components/MapSearchForm.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useQueryState } from 'nuqs';
import { useState } from 'react';

import AddressAutocomplete, { type AddressAutocompleteInputProps } from '@/components/form/dsfr/AddressAutocompleteInput';
Expand All @@ -8,11 +9,13 @@ import { type HandleAddressSelect } from '@/types/HeatNetworksResponse';
const MapSearchForm = ({ onAddressSelect }: { onAddressSelect?: HandleAddressSelect }) => {
const [eligibilityError, setEligibilityError] = useState(false);
const { heatNetworkService } = useServices();
const [defaultAddress, setDefaultAddress] = useQueryState('address');

const handleAddressSelected: AddressAutocompleteInputProps['onSelect'] = async (geoAddress) => {
if (!geoAddress) {
return;
}
setDefaultAddress(null);
try {
setEligibilityError(false);
const network = await heatNetworkService.findByCoords(geoAddress);
Expand Down Expand Up @@ -40,7 +43,7 @@ const MapSearchForm = ({ onAddressSelect }: { onAddressSelect?: HandleAddressSel
</>
) : undefined
}
defaultValue={''}
defaultValue={defaultAddress || ''}
onClear={() => {
setEligibilityError(false);
}}
Expand Down

0 comments on commit ab16745

Please sign in to comment.