diff --git a/app.territoiresentransitions.react/src/app/pages/collectivite/Indicateurs/detail/FichesLiees.tsx b/app.territoiresentransitions.react/src/app/pages/collectivite/Indicateurs/detail/FichesLiees.tsx new file mode 100644 index 0000000000..d566b5e836 --- /dev/null +++ b/app.territoiresentransitions.react/src/app/pages/collectivite/Indicateurs/detail/FichesLiees.tsx @@ -0,0 +1,85 @@ +import { Button, EmptyCard } from '@/ui'; +import { useState } from 'react'; +import { objectToSnake } from 'ts-case-convert'; +import FichePicto from '../../PlansActions/FicheAction/FichesLiees/FichePicto'; +import ModaleFichesLiees from '../../PlansActions/FicheAction/FichesLiees/ModaleFichesLiees'; +import FichesActionListe from '../../PlansActions/ToutesLesFichesAction/FichesActionListe'; +import { + useFichesActionLiees, + useUpdateFichesActionLiees, +} from '../Indicateur/useFichesActionLiees'; +import { TIndicateurDefinition } from '../types'; + +type Props = { + definition: TIndicateurDefinition; + isReadonly: boolean; +}; + +const FichesLiees = ({ definition, isReadonly }: Props) => { + const [isModalOpen, setIsModalOpen] = useState(false); + + const { data: fiches } = useFichesActionLiees(definition); + const fichesLiees = (fiches ? objectToSnake(fiches) : []).map((f) => f.id); + + const { mutate: updateFichesActionLiees } = + useUpdateFichesActionLiees(definition); + + const isEmpty = fiches.length === 0; + + return ( + <> + {isEmpty ? ( + } + title="Aucune fiche action de vos plans d'actions n'est liée !" + isReadonly={isReadonly} + actions={[ + { + children: 'Lier une fiche action', + icon: 'link', + onClick: () => setIsModalOpen(true), + }, + ]} + size="xs" + /> + ) : ( +
+
+
Fiches des plans liées
+ {!isReadonly && ( + + )} +
+ +
+ )} + + {isModalOpen && ( + + )} + + ); +}; + +export default FichesLiees; diff --git a/app.territoiresentransitions.react/src/app/pages/collectivite/Indicateurs/detail/IndicateurLayout.tsx b/app.territoiresentransitions.react/src/app/pages/collectivite/Indicateurs/detail/IndicateurLayout.tsx index a769a2e8b3..f92ad44fe1 100644 --- a/app.territoiresentransitions.react/src/app/pages/collectivite/Indicateurs/detail/IndicateurLayout.tsx +++ b/app.territoiresentransitions.react/src/app/pages/collectivite/Indicateurs/detail/IndicateurLayout.tsx @@ -5,12 +5,12 @@ import ScrollTopButton from '@/app/ui/buttons/ScrollTopButton'; import { BadgeACompleter } from '@/app/ui/shared/Badge/BadgeACompleter'; import { Badge, Tab, Tabs } from '@/ui'; import ActionsLieesListe from '../../PlansActions/FicheAction/ActionsLiees/ActionsLieesListe'; -import { FichesActionLiees } from '../Indicateur/FichesActionLiees'; import { HeaderIndicateur } from '../Indicateur/detail/HeaderIndicateur'; import { useUpdateIndicateurDefinition } from '../Indicateur/useUpdateIndicateurDefinition'; import BadgeOpenData from '../components/BadgeOpenData'; import { TIndicateurDefinition } from '../types'; import DonneesIndicateur from './DonneesIndicateur'; +import FichesLiees from './FichesLiees'; import IndicateurToolbar from './IndicateurToolbar'; import SousIndicateurs from './SousIndicateurs'; @@ -114,7 +114,10 @@ const IndicateurLayout = ({ ) : ( // Indicateur sans enfant, groupe d'indicateurs avec agrégation, // ou indicateur personnalisé - + {/* Données */} - + )} diff --git a/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/Carte/FicheActionCard.tsx b/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/Carte/FicheActionCard.tsx index 968435debd..20bb480b0f 100644 --- a/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/Carte/FicheActionCard.tsx +++ b/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/Carte/FicheActionCard.tsx @@ -7,8 +7,8 @@ import { useState } from 'react'; import { QueryKey } from 'react-query'; import BadgePriorite from '../../components/BadgePriorite'; import BadgeStatut from '../../components/BadgeStatut'; -import { generateTitle } from '../data/utils'; import ModaleSuppression from '../Header/actions/ModaleSuppression'; +import { generateTitle } from '../data/utils'; import FicheActionFooterInfo from './FicheActionFooterInfo'; import ModifierFicheModale from './ModifierFicheModale'; @@ -118,7 +118,7 @@ const FicheActionCard = ({ dataTest="FicheActionCarte" id={carteId} className={classNames( - 'h-full px-4 py-[1.125rem] !gap-3 !text-grey-8 !shadow-none transition', + 'h-full !p-4 !gap-2 !text-grey-8 !shadow-none transition', { 'hover:border-primary-3 hover:!bg-primary-1': !isNotClickable, } @@ -155,23 +155,27 @@ const FicheActionCard = ({ } footer={ // Bas de la carte -
- {/* Date de dernière modification */} - {!!ficheAction.modifiedAt && ( - - Modifié {getModifiedSince(ficheAction.modifiedAt)} - - )} - +
{/* Personnes pilote et date de fin prévisionnelle */} + + {/* Date de dernière modification */} + {!!ficheAction.modifiedAt && ( + <> +
+ + Modifié {getModifiedSince(ficheAction.modifiedAt)} + + + )}
} > diff --git a/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/Carte/FicheActionFooterInfo.tsx b/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/Carte/FicheActionFooterInfo.tsx index bf3b0bdd01..734eb6f8d5 100644 --- a/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/Carte/FicheActionFooterInfo.tsx +++ b/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/Carte/FicheActionFooterInfo.tsx @@ -1,80 +1,109 @@ import { Personne } from '@/api/collectivites'; import { getTextFormattedDate } from '@/app/utils/formatUtils'; +import { Tag } from '@/domain/collectivites'; import { Icon, Tooltip } from '@/ui'; import classNames from 'classnames'; import { isBefore, startOfToday } from 'date-fns'; -import { Fragment } from 'react'; type FicheActionFooterInfoProps = { pilotes: Personne[] | null | undefined; + services: Tag[] | null | undefined; dateDeFin: string | null | undefined; ameliorationContinue: boolean | null | undefined; }; const FicheActionFooterInfo = ({ pilotes, + services, dateDeFin, ameliorationContinue, }: FicheActionFooterInfoProps) => { const hasPilotes = !!pilotes && pilotes.length > 0; + const hasServices = !!services && services.length > 0; const hasDateDeFin = !!dateDeFin; - if (!hasPilotes && !hasDateDeFin && !ameliorationContinue) return null; - const isLate = hasDateDeFin && isBefore(new Date(dateDeFin), startOfToday()); return ( -
- {/* Personnes pilote */} - {hasPilotes && ( - - - {pilotes[0].nom} - {pilotes.length > 1 && ( - - {pilotes.map((pilote, i) => ( -
  • {pilote.nom}
  • - ))} - - } - > - - +{pilotes.length - 1} - -
    - )} -
    - )} - +
    {/* Date de fin prévisionnelle */} {!!dateDeFin && ( - - {hasPilotes &&
    } - - - {getTextFormattedDate({ - date: dateDeFin, - shortMonth: true, - })} - - + + + {getTextFormattedDate({ + date: dateDeFin, + shortMonth: true, + })} + )} {/* Action récurrente */} {!hasDateDeFin && ameliorationContinue && ( - - {hasPilotes &&
    } - - - Tous les ans + + + Tous les ans + + )} + + {/* Personnes pilote */} + {hasPilotes && ( + <> + {(hasDateDeFin || ameliorationContinue) && ( +
    + )} + + + {pilotes[0].nom} + {pilotes.length > 1 && ( + + {pilotes.map((pilote, i) => ( +
  • {pilote.nom}
  • + ))} + + } + > + + +{pilotes.length - 1} + +
    + )} +
    + + )} + + {/* Services pilote */} + {hasServices && ( + <> + {(hasDateDeFin || ameliorationContinue || hasPilotes) && ( +
    + )}{' '} + + + {services[0].nom} + {services.length > 1 && ( + + {services.map((service, i) => ( +
  • {service.nom}
  • + ))} + + } + > + + +{services.length - 1} + +
    + )}
    - + )}
    ); diff --git a/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/FichesLiees/ModaleFichesLiees.tsx b/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/FichesLiees/ModaleFichesLiees.tsx index 83ec36f38f..4d5e9dd7f6 100644 --- a/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/FichesLiees/ModaleFichesLiees.tsx +++ b/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/FicheAction/FichesLiees/ModaleFichesLiees.tsx @@ -5,7 +5,7 @@ import { useEffect, useState } from 'react'; type ModaleFichesLieesProps = { isOpen: boolean; setIsOpen: (opened: boolean) => void; - currentFicheId: number; + currentFicheId: number | null; linkedFicheIds: number[]; updateLinkedFicheIds: (ficheIds: number[]) => void; }; diff --git a/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/ToutesLesFichesAction/FichesActionListe.tsx b/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/ToutesLesFichesAction/FichesActionListe.tsx index 0754829b50..71324e0e9e 100644 --- a/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/ToutesLesFichesAction/FichesActionListe.tsx +++ b/app.territoiresentransitions.react/src/app/pages/collectivite/PlansActions/ToutesLesFichesAction/FichesActionListe.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames'; -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { FetchOptions, @@ -23,6 +23,7 @@ import FilterBadges, { CustomFilterBadges, useFiltersToBadges, } from '@/app/ui/shared/filters/filter-badges'; +import _ from 'lodash'; import { FicheResume } from 'packages/api/src/plan-actions'; import ActionsGroupeesMenu from '../ActionsGroupees/ActionsGroupeesMenu'; import EmptyFichePicto from '../FicheAction/FichesLiees/EmptyFichePicto'; @@ -60,7 +61,7 @@ const sortByOptions: sortByOptionsType[] = [ ]; type Props = { - settings: (openState: OpenState) => React.ReactNode; + settings?: (openState: OpenState) => React.ReactNode; filtres: Filtre; customFilterBadges?: CustomFilterBadges; resetFilters?: () => void; @@ -68,6 +69,7 @@ type Props = { sortSettings?: SortFicheActionSettings; enableGroupedActions?: boolean; isReadOnly?: boolean; + containeClassName?: string; }; /** Liste de fiches action avec tri et options de fitlre */ @@ -82,9 +84,12 @@ const FichesActionListe = ({ maxNbOfCards = 15, enableGroupedActions = false, isReadOnly, + containeClassName, }: Props) => { const collectiviteId = useCollectiviteId(); + const filtresLocal = useRef(filtres); + const [isSettingsOpen, setIsSettingsOpen] = useState(false); const [isGroupedActionsOn, setIsGroupedActionsOn] = useState(false); const [selectedFiches, setSelectedFiches] = useState([]); @@ -153,7 +158,10 @@ const FichesActionListe = ({ }; useEffect(() => { - setCurrentPage(1); + if (!_.isEqual(filtres, filtresLocal.current)) { + filtresLocal.current = filtres; + setCurrentPage(1); + } }, [filtres]); useEffect(() => { @@ -198,9 +206,14 @@ const FichesActionListe = ({ )} {hasFiches && ( - <> -
    -
    +
    +
    +
    {/** Tri */}
    @@ -257,7 +270,7 @@ const FichesActionListe = ({ displaySize="sm" /> {/** Bouton d'édition des filtres (une modale avec bouton ou un ButtonMenu) */} - {settings({ + {settings?.({ isOpen: isSettingsOpen, setIsOpen: setIsSettingsOpen, })} @@ -365,7 +378,7 @@ const FichesActionListe = ({ )} - +
    )} );