Skip to content

Commit

Permalink
fix(dashboard): statistiques pour plusieurs équipes prend en compte s…
Browse files Browse the repository at this point in the history
…i chaque équipe est de nuit ou pas (#1787)

* chore: fix test

* fix(dashboard): statistiques pour plusieurs équipes prend en compte si chaque équipe est de nuit ou pas
  • Loading branch information
arnaudambro authored Nov 23, 2023
1 parent c13d675 commit 341d86b
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 108 deletions.
162 changes: 85 additions & 77 deletions dashboard/src/scenes/stats/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { selectorFamily, useRecoilValue } from 'recoil';
import { useLocalStorage } from '../../services/useLocalStorage';
import {
Expand All @@ -21,7 +21,6 @@ import { HeaderStyled, Title as HeaderTitle } from '../../components/header';
import Loading from '../../components/loading';
import SelectTeamMultiple from '../../components/SelectTeamMultiple';
import ExportFormattedData from '../data-import-export/ExportFormattedData';
import { getDataForPeriod } from './utils';
import GeneralStats from './General';
import ServicesStats from './Services';
import ActionsStats from './Actions';
Expand Down Expand Up @@ -88,27 +87,23 @@ const StatsLoader = () => {
const itemsForStatsSelector = selectorFamily({
key: 'itemsForStatsSelector',
get:
({ period, filterPersons, selectedTeamsIdsObject, viewAllOrganisationData, allSelectedTeamsAreNightSession }) =>
({ period, filterPersons, selectedTeamsObjectWithOwnPeriod, viewAllOrganisationData }) =>
({ get }) => {
const activeFilters = filterPersons.filter((f) => f.value);
const filterItemByTeam = (item, key) => {
if (viewAllOrganisationData) return true;
if (Array.isArray(item[key])) {
for (const team of item[key]) {
if (selectedTeamsIdsObject[team]) return true;
if (selectedTeamsObjectWithOwnPeriod[team]) return true;
}
}
return !!selectedTeamsIdsObject[item[key]];
return !!selectedTeamsObjectWithOwnPeriod[item[key]];
};
const filtersExceptOutOfActiveList = activeFilters.filter((f) => f.field !== 'outOfActiveList');
const outOfActiveListFilter = activeFilters.find((f) => f.field === 'outOfActiveList')?.value;

const allPersons = get(personsForStatsSelector);

const offsetHours = allSelectedTeamsAreNightSession ? 12 : 0;
const isoStartDate = period.startDate ? dayjs(period.startDate).startOf('day').add(offsetHours, 'hour').toISOString() : null;
const isoEndDate = period.endDate ? dayjs(period.endDate).startOf('day').add(1, 'day').add(offsetHours, 'hour').toISOString() : null;

const personsCreated = [];
const personsUpdated = [];
const personsWithActions = {};
Expand All @@ -121,7 +116,7 @@ const itemsForStatsSelector = selectorFamily({
const rencontresFilteredByPersons = [];
const personsWithRencontres = {};
const personsInRencontresBeforePeriod = {};
const noPeriodSelected = !isoStartDate || !isoEndDate;
const noPeriodSelected = !period.startDate || !period.endDate;
for (let person of allPersons) {
// get the persons concerned by filters
if (!filterItem(filtersExceptOutOfActiveList)(person)) continue;
Expand All @@ -135,6 +130,7 @@ const itemsForStatsSelector = selectorFamily({
personsUpdated[person._id] = person;
personsCreated[person._id] = person;
} else {
const { isoStartDate, isoEndDate } = selectedTeamsObjectWithOwnPeriod[person.assignedTeams];
if (createdDate >= isoStartDate && createdDate < isoEndDate) {
personsCreated[person._id] = person;
personsUpdated[person._id] = person;
Expand All @@ -156,8 +152,16 @@ const itemsForStatsSelector = selectorFamily({
continue;
}
const date = action.completedAt || action.dueAt;
if (date < isoStartDate) continue;
if (date >= isoEndDate) continue;
if (Array.isArray(action.teams)) {
let isIncluded = false;
for (const team of action.teams) {
const { isoStartDate, isoEndDate } = selectedTeamsObjectWithOwnPeriod[team];
if (date < isoStartDate) continue;
if (date >= isoEndDate) continue;
isIncluded = true;
}
if (!isIncluded) continue;
}
actionsFilteredByPersons[action._id] = action;
personsWithActions[person._id] = person;
}
Expand All @@ -169,8 +173,16 @@ const itemsForStatsSelector = selectorFamily({
continue;
}
const date = consultation.completedAt || consultation.dueAt;
if (date < isoStartDate) continue;
if (date >= isoEndDate) continue;
if (Array.isArray(consultation.teams)) {
let isIncluded = false;
for (const team of consultation.teams) {
const { isoStartDate, isoEndDate } = selectedTeamsObjectWithOwnPeriod[team];
if (date < isoStartDate) continue;
if (date >= isoEndDate) continue;
isIncluded = true;
}
if (!isIncluded) continue;
}
consultationsFilteredByPersons.push(consultation);
personsWithConsultations[person._id] = person;
}
Expand All @@ -183,6 +195,7 @@ const itemsForStatsSelector = selectorFamily({
continue;
}
const date = passage.date;
const { isoStartDate, isoEndDate } = selectedTeamsObjectWithOwnPeriod[passage.team];
if (date < isoStartDate) continue;
if (date >= isoEndDate) continue;
passagesFilteredByPersons.push(passage);
Expand All @@ -201,6 +214,7 @@ const itemsForStatsSelector = selectorFamily({
continue;
}
const date = rencontre.date;
const { isoStartDate, isoEndDate } = selectedTeamsObjectWithOwnPeriod[rencontre.team];
if (date < isoStartDate) continue;
if (date >= isoEndDate) continue;
rencontresFilteredByPersons.push(rencontre);
Expand Down Expand Up @@ -271,8 +285,7 @@ const Stats = () => {
Options are: we clicked on 'view all organisation data' or we selected manually some teams
Base on those options we get
- selectedTeams: the teams we want to display
- selectedTeamsIdsObject: an object with the ids of the selected teams as keys, to loop faster - O(1) instead of O(n)
- allSelectedTeamsAreNightSession: a boolean to know if all the selected teams are night sessions
- selectedTeamsObjectWithOwnPeriod: an object with the ids of the selected teams as keys, to loop faster - O(1) instead of O(n)
- filterArrayByTeam: a function to filter an array of elements by team
*
*/
Expand All @@ -281,36 +294,19 @@ const Stats = () => {
if (viewAllOrganisationData) return teams;
return manuallySelectedTeams;
}, [manuallySelectedTeams, viewAllOrganisationData, teams]);
const selectedTeamsIdsObject = useMemo(() => {
const selectedTeamsObjectWithOwnPeriod = useMemo(() => {
const teamsIdsObject = {};
for (const team of selectedTeams) {
teamsIdsObject[team._id] = true;
const offsetHours = team.nightSession ? 12 : 0;
const isoStartDate = period.startDate ? dayjs(period.startDate).startOf('day').add(offsetHours, 'hour').toISOString() : null;
const isoEndDate = period.endDate ? dayjs(period.endDate).startOf('day').add(1, 'day').add(offsetHours, 'hour').toISOString() : null;
teamsIdsObject[team._id] = {
isoStartDate,
isoEndDate,
};
}
return teamsIdsObject;
}, [selectedTeams]);
const allSelectedTeamsAreNightSession = useMemo(() => {
for (const team of selectedTeams) {
if (!team.nightSession) return false;
}
return true;
}, [selectedTeams]);

const filterArrayByTeam = useCallback(
(elements, key) => {
if (viewAllOrganisationData) return elements;
const filteredElements = elements.filter((e) => {
if (Array.isArray(e[key])) {
for (const team of e[key]) {
if (selectedTeamsIdsObject[team]) return true;
}
}
return !!selectedTeamsIdsObject[e[key]];
});
return filteredElements;
},
[selectedTeamsIdsObject, viewAllOrganisationData]
);

}, [selectedTeams, period]);
/*
*
FILTERS THE PERSONS
Expand All @@ -322,16 +318,6 @@ const Stats = () => {
*
*/

// const persons = useMemo(
// () =>
// getDataForPeriod(filterArrayByTeam(allPersons, 'assignedTeams'), period, {
// filters: filterPersons.filter((f) => f.field !== 'outOfActiveList'),
// field: 'followedSince',
// allSelectedTeamsAreNightSession,
// }),
// [allPersons, filterArrayByTeam, filterPersons, period, allSelectedTeamsAreNightSession]
// );

/*
*
FILTERS THE ACTIONS/PASSAGES/RENCONTRES/CONSULTATIONS BY PERSONS AND BY TEAM
Expand Down Expand Up @@ -360,9 +346,8 @@ const Stats = () => {
itemsForStatsSelector({
period,
filterPersons,
selectedTeamsIdsObject,
selectedTeamsObjectWithOwnPeriod,
viewAllOrganisationData,
allSelectedTeamsAreNightSession,
})
);

Expand Down Expand Up @@ -415,30 +400,53 @@ const Stats = () => {
if (filter.type !== filterMakingThingsClearAboutOutOfActiveListStatus.type) return passagesFilteredByPersons;
if (filter.value !== filterMakingThingsClearAboutOutOfActiveListStatus.value) return passagesFilteredByPersons;
}
const teamsPassages = filterArrayByTeam(allPassagesPopulated, 'team');
return getDataForPeriod(teamsPassages, period, { field: 'date', allSelectedTeamsAreNightSession });
}, [allPassagesPopulated, filterArrayByTeam, period, allSelectedTeamsAreNightSession, passagesFilteredByPersons, filterPersons]);

const observations = useMemo(
() =>
getDataForPeriod(
filterArrayByTeam(allObservations, 'team').filter(
(e) => !selectedTerritories.length || selectedTerritories.some((t) => e.territory === t._id)
),
period,
{ field: 'observedAt', allSelectedTeamsAreNightSession }
),
[allObservations, filterArrayByTeam, period, selectedTerritories, allSelectedTeamsAreNightSession]
);
const passagesFiltered = [];
for (const passage of allPassagesPopulated) {
if (!viewAllOrganisationData) {
if (!selectedTeamsObjectWithOwnPeriod[passage.team]) continue;
}
const { isoStartDate, isoEndDate } = selectedTeamsObjectWithOwnPeriod[passage.team];
const date = passage.date ?? passage.createdAt;
if (date < isoStartDate) continue;
if (date >= isoEndDate) continue;
passagesFiltered.push(passage);
}
return passagesFiltered;
}, [allPassagesPopulated, passagesFilteredByPersons, filterPersons, selectedTeamsObjectWithOwnPeriod, viewAllOrganisationData]);

const observations = useMemo(() => {
const observationsFiltered = [];
for (const observation of allObservations) {
if (!viewAllOrganisationData) {
if (!selectedTeamsObjectWithOwnPeriod[observation.team]) continue;
}
if (!!selectedTerritories.length) {
if (!selectedTerritories.some((t) => t._id === observation.territory)) continue;
}
const { isoStartDate, isoEndDate } = selectedTeamsObjectWithOwnPeriod[observation.team];
const date = observation.observedAt ?? observation.createdAt;
if (date < isoStartDate) continue;
if (date >= isoEndDate) continue;
observationsFiltered.push(observation);
}
return observationsFiltered;
}, [allObservations, selectedTerritories, selectedTeamsObjectWithOwnPeriod, viewAllOrganisationData]);

const reports = useMemo(() => {
const reportsFiltered = [];
for (const report of allreports) {
if (!viewAllOrganisationData) {
if (!selectedTeamsObjectWithOwnPeriod[report.team]) continue;
}
const { isoStartDate, isoEndDate } = selectedTeamsObjectWithOwnPeriod[report.team];
const date = report.date;
if (date < isoStartDate) continue;
if (date >= isoEndDate) continue;
reportsFiltered.push(report);
}
return reportsFiltered;
}, [allreports, selectedTeamsObjectWithOwnPeriod, viewAllOrganisationData]);

const reports = useMemo(
() =>
getDataForPeriod(filterArrayByTeam(allreports, 'team'), period, {
field: 'date',
allSelectedTeamsAreNightSession,
}),
[allreports, filterArrayByTeam, period, allSelectedTeamsAreNightSession]
);
const filterPersonsBase = useRecoilValue(filterPersonsBaseSelector);
// Add enabled custom fields in filters.
const filterPersonsWithAllFields = (withMedicalFiles = false) => [
Expand Down
31 changes: 0 additions & 31 deletions dashboard/src/scenes/stats/utils.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,3 @@
import dayjs from 'dayjs';
import { filterData } from '../../components/Filters';

export const getDataForPeriod = (
data,
{ startDate, endDate },
{ filters = [], field = 'createdAt', backupField = 'createdAt', allSelectedTeamsAreNightSession } = {},
callback = null
) => {
if (!!filters?.filter((f) => Boolean(f?.value)).length) data = filterData(data, filters);
if (!startDate || !endDate) {
return data;
}

if (callback) {
return callback(data);
}

const offsetHours = allSelectedTeamsAreNightSession ? 12 : 0;

const isoStartDate = dayjs(startDate).startOf('day').add(offsetHours, 'hour').toISOString();
const isoEndDate = dayjs(endDate).startOf('day').add(1, 'day').add(offsetHours, 'hour').toISOString();

return data.filter((item) => {
const date = item[field] || item[backupField] || item.createdAt;
if (date < isoStartDate) return false;
if (date > isoEndDate) return false;
return true;
});
};

export const getDuration = (timestampFromNow) => {
const inDays = Math.round(timestampFromNow / 1000 / 60 / 60 / 24);
if (inDays < 90) return [inDays, 'jours'];
Expand Down

0 comments on commit 341d86b

Please sign in to comment.