Skip to content

Commit

Permalink
feat(dashboard): regroupe les statistiques des personnes suivies par …
Browse files Browse the repository at this point in the history
…section
  • Loading branch information
Arnaud AMBROSELLI committed Nov 6, 2023
1 parent eb95612 commit 0dff3ef
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Block } from './Blocks';
import CustomFieldsStats from './CustomFieldsStats';
import Filters from '../../components/Filters';

const ConsultationsStats = ({ consultations, personsWithConsultations, filterBase, filterPersons, setFilterPersons }) => {
export default function ConsultationsStats({ consultations, personsWithConsultations, filterBase, filterPersons, setFilterPersons }) {
const organisation = useRecoilValue(organisationState);

const filterTitle = useMemo(() => {
Expand Down Expand Up @@ -35,7 +35,15 @@ const ConsultationsStats = ({ consultations, personsWithConsultations, filterBas
<div className="tw-flex tw-basis-full tw-items-center">
<Filters title={filterTitle} base={filterBase} filters={filterPersons} onChange={setFilterPersons} />
</div>
<details open>
<details
open={window.localStorage.getItem('consultations-stats-general-open') === 'true'}
onToggle={(e) => {
if (e.target.open) {
window.localStorage.setItem('consultations-stats-general-open', 'true');
} else {
window.localStorage.removeItem('consultations-stats-general-open');
}
}}>
<summary className="tw-my-8 tw-mx-0">
<h4 className="tw-inline tw-text-xl tw-text-black75">Global</h4>
</summary>
Expand All @@ -59,7 +67,16 @@ const ConsultationsStats = ({ consultations, personsWithConsultations, filterBas
</details>
{organisation.consultations.map((c) => {
return (
<details key={c.name}>
<details
open={window.localStorage.getItem(`person-stats-${c.name.replace(' ', '-').toLocaleLowerCase()}-open`) === 'true'}
onToggle={(e) => {
if (e.target.open) {
window.localStorage.setItem(`person-stats-${c.name.replace(' ', '-').toLocaleLowerCase()}-open`, 'true');
} else {
window.localStorage.removeItem(`person-stats-${c.name.replace(' ', '-').toLocaleLowerCase()}-open`);
}
}}
key={c.name}>
<summary className="tw-my-8 tw-mx-0">
<h4 className="tw-inline tw-text-xl tw-text-black75">
Statistiques des consultations de type « {c.name} » ({consultationsByType[c.name]?.length ?? 0})
Expand All @@ -76,6 +93,4 @@ const ConsultationsStats = ({ consultations, personsWithConsultations, filterBas
})}
</>
);
};

export default ConsultationsStats;
}
2 changes: 1 addition & 1 deletion dashboard/src/scenes/stats/MedicalFiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CustomResponsivePie } from './charts';
import { getPieData } from './utils';
import CustomFieldsStats from './CustomFieldsStats';
import Filters from '../../components/Filters';
import { AgeRangeBar } from './Persons';
import { AgeRangeBar } from './PersonsStats';

const MedicalFilesStats = ({ filterBase, filterPersons, setFilterPersons, personsForStats, customFieldsMedicalFile, personFields, title }) => {
return (
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/scenes/stats/Passages.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import { CustomResponsivePie } from './charts';
import { getPieData } from './utils';
import { AgeRangeBar } from './Persons';
import { AgeRangeBar } from './PersonsStats';
import Filters from '../../components/Filters';

const PassagesStats = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,16 @@ import { Block } from './Blocks';
import CustomFieldsStats from './CustomFieldsStats';
import { ModalBody, ModalContainer, ModalFooter, ModalHeader } from '../../components/tailwind/Modal';
import { organisationState, teamsState } from '../../recoil/auth';
import { personFieldsIncludingCustomFieldsSelector, sortPersons } from '../../recoil/persons';
import { customFieldsPersonsSelector, personFieldsIncludingCustomFieldsSelector, sortPersons } from '../../recoil/persons';
import TagTeam from '../../components/TagTeam';
import Table from '../../components/table';
import { dayjsInstance, formatDateWithFullMonth } from '../../services/date';
import CustomFieldDisplay from '../../components/CustomFieldDisplay';
import { groupsState } from '../../recoil/groups';

const PersonStats = ({
title,
firstBlockHelp,
filterBase,
filterPersons,
setFilterPersons,
personsForStats,
personFields,
flattenedCustomFieldsPersons,
}) => {
export default function PersonStats({ title, firstBlockHelp, filterBase, filterPersons, setFilterPersons, personsForStats, personFields }) {
const allGroups = useRecoilValue(groupsState);
const customFieldsPersons = useRecoilValue(customFieldsPersonsSelector);

const [personsModalOpened, setPersonsModalOpened] = useState(false);
const [sliceField, setSliceField] = useState(null);
Expand Down Expand Up @@ -65,95 +57,125 @@ const PersonStats = ({
<>
<h3 className="tw-my-5 tw-text-xl">Statistiques des {title}</h3>
<Filters base={filterBase} filters={filterPersons} onChange={setFilterPersons} />
<div className="-tw-mx-4 tw-flex tw-flex-wrap tw-justify-around">
<Block data={personsForStats} title={`Nombre de ${title}`} help={firstBlockHelp} />
<BlockCreatedAt persons={personsForStats} />
<BlockWanderingAt persons={personsForStats} />
<BlockGroup groups={groupsForPersons} title={`Nombre de familles dans lesquelles se trouvent des ${title}`} />
</div>
<CustomResponsivePie
title="Genre"
field="gender"
onItemClick={(newSlice) => {
onSliceClick(newSlice, 'gender');
}}
data={getPieData(personsForStats, 'gender', { options: personFields.find((f) => f.name === 'gender').options })}
help={`Genre des ${title} dans la période définie.\n\nSi aucune période n'est définie, on considère l'ensemble des personnes.`}
/>
<AgeRangeBar
persons={personsForStats}
onItemClick={(newSlice, data) => {
setSliceField(personFields.find((f) => f.name === 'birthdate'));
setSliceValue(newSlice);
setSlicedData(data);
setPersonsModalOpened(true);
}}
/>
<StatsCreatedAtRangeBar
persons={personsForStats}
onItemClick={(newSlice, data) => {
setSliceField(personFields.find((f) => f.name === 'followedSince'));
setSliceValue(newSlice);
setSlicedData(data);
setPersonsModalOpened(true);
}}
/>
<StatsWanderingAtRangeBar
persons={personsForStats}
onItemClick={(newSlice, data) => {
setSliceField(personFields.find((f) => f.name === 'wanderingAt'));
setSliceValue(newSlice);
setSlicedData(data);
setPersonsModalOpened(true);
}}
/>
<CustomResponsivePie
title="Personnes très vulnérables"
field="alertness"
onItemClick={(newSlice) => {
onSliceClick(newSlice, 'alertness');
}}
data={getPieData(personsForStats, 'alertness', { isBoolean: true })}
help={`${title.capitalize()} vulnérables dans la période définie.\n\nSi aucune période n'est définie, on considère l'ensemble des personnes.`}
/>
<CustomResponsivePie
title="Sortie de file active"
field="outOfActiveList"
onItemClick={(newSlice) => {
onSliceClick(newSlice, 'outOfActiveList');
}}
data={getPieData(personsForStats, 'outOfActiveList', { isBoolean: true })}
help={`${title} dans la période définie, sorties de la file active. La date de sortie de la file active n'est pas nécessairement dans la période définie.\n\nSi aucune période n'est définie, on considère l'ensemble des personnes.`}
/>
<CustomResponsiveBar
title="Raison de sortie de file active"
help={`Raisons de sortie de file active des ${title} dans la période définie, sorties de la file active. La date de sortie de la file active n'est pas nécessairement dans la période définie.\n\nSi aucune période n'est définie, on considère l'ensemble des personnes.`}
onItemClick={(newSlice) => {
onSliceClick(
newSlice,
'outOfActiveListReasons',
personsForStats.filter((p) => !!p.outOfActiveList)
);
}}
axisTitleY="File active"
axisTitleX="Raison de sortie de file active"
isMultiChoice
totalForMultiChoice={personsForStats.filter((p) => !!p.outOfActiveList).length}
totalTitleForMultiChoice={<span className="tw-font-bold">Nombre de personnes concernées</span>}
data={getMultichoiceBarData(
personsForStats.filter((p) => !!p.outOfActiveList),
'outOfActiveListReasons'
)}
/>
<CustomFieldsStats
data={personsForStats}
customFields={flattenedCustomFieldsPersons}
onSliceClick={onSliceClick}
help={(label) =>
`${label.capitalize()} des ${title} dans la période définie.\n\nSi aucune période n'est définie, on considère l'ensemble des personnes.`
}
totalTitleForMultiChoice={<span className="tw-font-bold">Nombre de personnes concernées</span>}
/>
<details
open={window.localStorage.getItem('person-stats-general-open') === 'true'}
onToggle={(e) => {
if (e.target.open) {
window.localStorage.setItem('person-stats-general-open', 'true');
} else {
window.localStorage.removeItem('person-stats-general-open');
}
}}>
<summary className="tw-my-8 tw-mx-0">
<h4 className="tw-inline tw-text-xl tw-text-black75">Général</h4>
</summary>
<div className="-tw-mx-4 tw-flex tw-flex-wrap tw-justify-around">
<Block data={personsForStats} title={`Nombre de ${title}`} help={firstBlockHelp} />
<BlockCreatedAt persons={personsForStats} />
<BlockWanderingAt persons={personsForStats} />
<BlockGroup groups={groupsForPersons} title={`Nombre de familles dans lesquelles se trouvent des ${title}`} />
</div>
<CustomResponsivePie
title="Genre"
field="gender"
onItemClick={(newSlice) => {
onSliceClick(newSlice, 'gender');
}}
data={getPieData(personsForStats, 'gender', { options: personFields.find((f) => f.name === 'gender').options })}
help={`Genre des ${title} dans la période définie.\n\nSi aucune période n'est définie, on considère l'ensemble des personnes.`}
/>
<AgeRangeBar
persons={personsForStats}
onItemClick={(newSlice, data) => {
setSliceField(personFields.find((f) => f.name === 'birthdate'));
setSliceValue(newSlice);
setSlicedData(data);
setPersonsModalOpened(true);
}}
/>
<StatsCreatedAtRangeBar
persons={personsForStats}
onItemClick={(newSlice, data) => {
setSliceField(personFields.find((f) => f.name === 'followedSince'));
setSliceValue(newSlice);
setSlicedData(data);
setPersonsModalOpened(true);
}}
/>
<StatsWanderingAtRangeBar
persons={personsForStats}
onItemClick={(newSlice, data) => {
setSliceField(personFields.find((f) => f.name === 'wanderingAt'));
setSliceValue(newSlice);
setSlicedData(data);
setPersonsModalOpened(true);
}}
/>
<CustomResponsivePie
title="Personnes très vulnérables"
field="alertness"
onItemClick={(newSlice) => {
onSliceClick(newSlice, 'alertness');
}}
data={getPieData(personsForStats, 'alertness', { isBoolean: true })}
help={`${title.capitalize()} vulnérables dans la période définie.\n\nSi aucune période n'est définie, on considère l'ensemble des personnes.`}
/>
<CustomResponsivePie
title="Sortie de file active"
field="outOfActiveList"
onItemClick={(newSlice) => {
onSliceClick(newSlice, 'outOfActiveList');
}}
data={getPieData(personsForStats, 'outOfActiveList', { isBoolean: true })}
help={`${title} dans la période définie, sorties de la file active. La date de sortie de la file active n'est pas nécessairement dans la période définie.\n\nSi aucune période n'est définie, on considère l'ensemble des personnes.`}
/>
<CustomResponsiveBar
title="Raison de sortie de file active"
help={`Raisons de sortie de file active des ${title} dans la période définie, sorties de la file active. La date de sortie de la file active n'est pas nécessairement dans la période définie.\n\nSi aucune période n'est définie, on considère l'ensemble des personnes.`}
onItemClick={(newSlice) => {
onSliceClick(
newSlice,
'outOfActiveListReasons',
personsForStats.filter((p) => !!p.outOfActiveList)
);
}}
axisTitleY="File active"
axisTitleX="Raison de sortie de file active"
isMultiChoice
totalForMultiChoice={personsForStats.filter((p) => !!p.outOfActiveList).length}
totalTitleForMultiChoice={<span className="tw-font-bold">Nombre de personnes concernées</span>}
data={getMultichoiceBarData(
personsForStats.filter((p) => !!p.outOfActiveList),
'outOfActiveListReasons'
)}
/>
</details>
{customFieldsPersons.map((section) => {
return (
<details
open={window.localStorage.getItem(`person-stats-${section.name.replace(' ', '-').toLocaleLowerCase()}-open`) === 'true'}
onToggle={(e) => {
if (e.target.open) {
window.localStorage.setItem(`person-stats-${section.name.replace(' ', '-').toLocaleLowerCase()}-open`, 'true');
} else {
window.localStorage.removeItem(`person-stats-${section.name.replace(' ', '-').toLocaleLowerCase()}-open`);
}
}}>
<summary className="tw-my-8 tw-mx-0">
<h4 className="tw-inline tw-text-xl tw-text-black75">{section.name}</h4>
</summary>
<CustomFieldsStats
data={personsForStats}
customFields={section.fields}
onSliceClick={onSliceClick}
help={(label) =>
`${label.capitalize()} des ${title} dans la période définie.\n\nSi aucune période n'est définie, on considère l'ensemble des personnes.`
}
totalTitleForMultiChoice={<span className="tw-font-bold">Nombre de personnes concernées</span>}
/>
</details>
);
})}
<SelectedPersonsModal
open={personsModalOpened}
onClose={() => {
Expand All @@ -170,7 +192,7 @@ const PersonStats = ({
/>
</>
);
};
}

const BlockWanderingAt = ({ persons }) => {
persons = persons.filter((p) => Boolean(p.wanderingAt));
Expand Down Expand Up @@ -571,5 +593,3 @@ const SelectedPersonsModal = ({ open, onClose, persons, title, onAfterLeave, sli
</ModalContainer>
);
};

export default PersonStats;
4 changes: 2 additions & 2 deletions dashboard/src/scenes/stats/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ import { getDataForPeriod } from './utils';
import GeneralStats from './General';
import ServicesStats from './Services';
import ActionsStats from './Actions';
import PersonStats from './Persons';
import PersonStats from './PersonsStats';
import PassagesStats from './Passages';
import RencontresStats from './Rencontres';
import ObservationsStats from './Observations';
import ReportsStats from './Reports';
import ConsultationsStats from './Consultations';
import ConsultationsStats from './ConsultationsStats';
import MedicalFilesStats from './MedicalFiles';
import ButtonCustom from '../../components/ButtonCustom';
import dayjs from 'dayjs';
Expand Down

0 comments on commit 0dff3ef

Please sign in to comment.