Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: nouveau compte-rendu: possibilité de voir les actions/consultations créées pendant la période #1862

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions dashboard/src/components/ActionModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useHistory, useLocation } from 'react-router-dom';
import { actionsState, allowedActionFieldsInHistory, CANCEL, DONE, prepareActionForEncryption, TODO } from '../recoil/actions';
import { currentTeamState, organisationState, teamsState, userState } from '../recoil/auth';
import { dayjsInstance, now, outOfBoundariesDate } from '../services/date';
import { dayjsInstance, formatDateWithNameOfDay, now, outOfBoundariesDate } from '../services/date';
import API from '../services/api';
import SelectPerson from './SelectPerson';
import SelectStatus from './SelectStatus';
Expand Down Expand Up @@ -350,7 +350,7 @@ function ActionContent({ onClose, action, personId = null, personIds = null, isM
<UserName
className="tw-block tw-text-right tw-text-base tw-font-normal tw-italic"
id={action.user}
wrapper={(name) => ` (créée par ${name})`}
wrapper={(name) => ` (créée par ${name} le ${formatDateWithNameOfDay(action.createdAt)})`}
/>
)}
</>
Expand Down
15 changes: 13 additions & 2 deletions dashboard/src/components/ActionsSortableList.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import useSearchParamState from '../services/useSearchParamState';
import DescriptionIcon from './DescriptionIcon';
import { AgendaMutedIcon } from '../assets/icons/AgendaMutedIcon';

const ActionsSortableList = ({ data, limit }) => {
const ActionsSortableList = ({ data, limit, showCreatedAt }) => {
useTitle('Agenda');
const history = useHistory();
const user = useRecoilValue(userState);
Expand Down Expand Up @@ -154,7 +154,18 @@ const ActionsSortableList = ({ data, limit }) => {
);
},
},
]}
{
title: 'Créée le',
dataKey: 'createdAt',
onSortOrder: setSortOrder,
onSortBy: setSortBy,
sortBy,
sortOrder,
render: (action) => {
return <DateBloc date={action.createdAt} />;
},
},
].filter((e) => showCreatedAt || e.dataKey !== 'createdAt')}
/>
{limit > 0 && <Page page={page} limit={limit} total={total} onChange={({ page }) => setPage(page, true)} />}
</>
Expand Down
156 changes: 138 additions & 18 deletions dashboard/src/scenes/report/components/ActionsOrConsultationsReport.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,46 @@ import { useRecoilValue } from 'recoil';
import { userState } from '../../../recoil/auth';
import { dayjsInstance } from '../../../services/date';

export const ActionsOrConsultationsReport = ({ actions, consultations, period }) => {
const formatEcheanceLabelPeriod = (period) => {
if (!!period.startDate && !!period.endDate) {
const start = dayjsInstance(period.startDate);
const end = dayjsInstance(period.endDate);
const today = dayjsInstance();
const showYear = start.year() !== end.year() || start.year() !== today.year();
const startFormatted = dayjsInstance(period.startDate).format(showYear ? 'D MMM YYYY' : 'D MMM');
const endFormatted = dayjsInstance(period.endDate).format(showYear ? 'D MMM YYYY' : 'D MMM');
if (startFormatted === endFormatted) return `le ${startFormatted}`;
return `entre le ${startFormatted} et le ${endFormatted}`;
}
return '';
};

export const ActionsOrConsultationsReport = ({
actionsDueOrCompletedAt,
actionsCreatedAt,
consultationsDueOrCompletedAt,
consultationsCreatedAt,
period,
}) => {
const [activeTab, setActiveTab] = useLocalStorage('reports-actions-consultation-toggle', 'Actions');
const [fullScreen, setFullScreen] = useState(false);
const [filterStatus, setFilterStatus] = useState([]);
const filteredActions = actions.filter((item) => !filterStatus.length || filterStatus.includes(item.status));
const filteredConsultations = consultations.filter((item) => !filterStatus.length || filterStatus.includes(item.status));
const [switchCreatedAt, setSwitchCreatedAt] = useLocalStorage('reports-actions-switch-created-at', 'dueOrCompletedAt'); // 'createdAt' or 'dueOrCompletedAt'
const [filterStatus, setFilterStatus] = useLocalStorage('reports-actions-filter-status', []);

const actions = switchCreatedAt === 'createdAt' ? actionsCreatedAt : actionsDueOrCompletedAt;
const consultations = switchCreatedAt === 'createdAt' ? consultationsCreatedAt : consultationsDueOrCompletedAt;
const data = activeTab.includes('Actions') ? actions : consultations;

const filteredActionsDueOrCompletedAt = actionsDueOrCompletedAt.filter((item) => !filterStatus.length || filterStatus.includes(item.status));
const filteredActionsCreatedAt = actionsCreatedAt.filter((item) => !filterStatus.length || filterStatus.includes(item.status));
const filteredConsultationsDueOrCompletedAt = consultationsDueOrCompletedAt.filter(
(item) => !filterStatus.length || filterStatus.includes(item.status)
);
const filteredConsultationsCreatedAt = consultationsCreatedAt.filter((item) => !filterStatus.length || filterStatus.includes(item.status));
const filteredActions = switchCreatedAt === 'createdAt' ? filteredActionsCreatedAt : filteredActionsDueOrCompletedAt;
const filteredConsultations = switchCreatedAt === 'createdAt' ? filteredConsultationsCreatedAt : filteredConsultationsDueOrCompletedAt;
const filteredData = activeTab.includes('Actions') ? filteredActions : filteredConsultations;

const history = useHistory();
const user = useRecoilValue(userState);

Expand Down Expand Up @@ -67,8 +99,15 @@ export const ActionsOrConsultationsReport = ({ actions, consultations, period })
</button>
</div>
</div>
<div className="w-full tw-max-w-lg tw-bg-white tw-px-7 tw-pb-1">
<ActionsOrConsultationsFilters setFilterStatus={setFilterStatus} filterStatus={filterStatus} disabled={!data.length} />
<div className="w-full tw-max-w-3xl tw-bg-white tw-px-7 tw-pb-1">
<ActionsOrConsultationsFilters
switchCreatedAt={switchCreatedAt}
setSwitchCreatedAt={setSwitchCreatedAt}
setFilterStatus={setFilterStatus}
filterStatus={filterStatus}
disabled={!data.length}
period={period}
/>
</div>
<div className="tw-grow tw-overflow-y-auto tw-border-t tw-border-main tw-border-opacity-20">
<ActionsSortableList data={filteredData} />
Expand All @@ -78,7 +117,30 @@ export const ActionsOrConsultationsReport = ({ actions, consultations, period })
aria-hidden="true"
className="printonly tw-flex tw-h-full tw-flex-col tw-overflow-hidden tw-rounded-lg tw-border tw-border-zinc-200 tw-shadow">
<div className="tw-flex tw-flex-col tw-items-stretch tw-bg-white tw-px-3 tw-py-3">
<h3 className="tw-m-0 tw-text-base tw-font-medium">Actions ({filteredActions.length})</h3>
<h3 className="tw-m-0 tw-text-base tw-font-medium">
Actions À FAIRE/FAITE/ANNULÉE {formatEcheanceLabelPeriod(period)} ({filteredActionsDueOrCompletedAt.length})
</h3>
{filterStatus.length > 0 && (
<h4 className="tw-m-0 tw-text-base tw-font-medium">
Filtrées par status:{' '}
{mappedIdsToLabels
.filter((s) => filterStatus.includes(s._id))
.map((status) => status.name)
.join(', ')}
</h4>
)}
</div>
<div className="tw-grow tw-overflow-y-auto tw-border-t tw-border-main tw-border-opacity-20">
<ActionsSortableList data={filteredActionsDueOrCompletedAt} showCreatedAt />
</div>
</section>
<section
aria-hidden="true"
className="printonly tw-mt-12 tw-flex tw-h-full tw-flex-col tw-overflow-hidden tw-rounded-lg tw-border tw-border-zinc-200 tw-shadow">
<div className="tw-flex tw-flex-col tw-items-stretch tw-bg-white tw-px-3 tw-py-3">
<h3 className="tw-m-0 tw-text-base tw-font-medium">
Actions créées {formatEcheanceLabelPeriod(period)} ({filteredActionsCreatedAt.length})
</h3>
{filterStatus.length > 0 && (
<h4 className="tw-m-0 tw-text-base tw-font-medium">
Filtrées par status:{' '}
Expand All @@ -90,14 +152,17 @@ export const ActionsOrConsultationsReport = ({ actions, consultations, period })
)}
</div>
<div className="tw-grow tw-overflow-y-auto tw-border-t tw-border-main tw-border-opacity-20">
<ActionsSortableList data={filteredActions} />
<ActionsSortableList data={filteredActionsCreatedAt} showCreatedAt />
</div>
</section>

<section
aria-hidden="true"
className="printonly tw-mt-12 tw-flex tw-h-full tw-flex-col tw-overflow-hidden tw-rounded-lg tw-border tw-border-zinc-200 tw-shadow">
<div className="tw-flex tw-flex-col tw-items-stretch tw-bg-white tw-px-3 tw-py-3">
<h3 className="tw-m-0 tw-text-base tw-font-medium">Consultations ({filteredConsultations.length})</h3>
<h3 className="tw-m-0 tw-text-base tw-font-medium">
Consultations À FAIRE/FAITE/ANNULÉE {formatEcheanceLabelPeriod(period)} ({filteredConsultationsDueOrCompletedAt.length})
</h3>
{filterStatus.length > 0 && (
<h4 className="tw-m-0 tw-text-base tw-font-medium">
Filtrées par status:{' '}
Expand All @@ -109,17 +174,45 @@ export const ActionsOrConsultationsReport = ({ actions, consultations, period })
)}
</div>
<div className="tw-grow tw-overflow-y-auto tw-border-t tw-border-main tw-border-opacity-20">
<ActionsSortableList data={filteredConsultations} />
<ActionsSortableList data={filteredConsultationsDueOrCompletedAt} showCreatedAt />
</div>
</section>
<section
aria-hidden="true"
className="printonly tw-mt-12 tw-flex tw-h-full tw-flex-col tw-overflow-hidden tw-rounded-lg tw-border tw-border-zinc-200 tw-shadow">
<div className="tw-flex tw-flex-col tw-items-stretch tw-bg-white tw-px-3 tw-py-3">
<h3 className="tw-m-0 tw-text-base tw-font-medium">
Consultations créées {formatEcheanceLabelPeriod(period)} ({filteredConsultationsCreatedAt.length})
</h3>
{filterStatus.length > 0 && (
<h4 className="tw-m-0 tw-text-base tw-font-medium">
Filtrées par status:{' '}
{mappedIdsToLabels
.filter((s) => filterStatus.includes(s._id))
.map((status) => status.name)
.join(', ')}
</h4>
)}
</div>
<div className="tw-grow tw-overflow-y-auto tw-border-t tw-border-main tw-border-opacity-20">
<ActionsSortableList data={filteredConsultationsCreatedAt} showCreatedAt />
</div>
</section>
<ModalContainer open={!!fullScreen} className="" size="full" onClose={() => setFullScreen(false)}>
<ModalHeader title={`${activeTab} (${filteredData.length})`} onClose={() => setFullScreen(false)}>
<div className="tw-mx-auto tw-mt-2 tw-w-full tw-max-w-lg">
<ActionsOrConsultationsFilters setFilterStatus={setFilterStatus} filterStatus={filterStatus} disabled={!data.length} />
<div className="tw-mx-auto tw-mt-2 tw-w-full tw-max-w-3xl">
<ActionsOrConsultationsFilters
switchCreatedAt={switchCreatedAt}
setSwitchCreatedAt={setSwitchCreatedAt}
setFilterStatus={setFilterStatus}
filterStatus={filterStatus}
disabled={!data.length}
period={period}
/>
</div>
</ModalHeader>
<ModalBody>
<ActionsSortableList data={filteredData} />
<ActionsSortableList data={filteredData} showCreatedAt />
</ModalBody>
<ModalFooter>
<button type="button" name="cancel" className="button-cancel" onClick={() => setFullScreen(false)}>
Expand All @@ -141,17 +234,44 @@ export const ActionsOrConsultationsReport = ({ actions, consultations, period })
);
};

const ActionsOrConsultationsFilters = ({ setFilterStatus, filterStatus, disabled }) => {
const ActionsOrConsultationsFilters = ({ switchCreatedAt, setSwitchCreatedAt, setFilterStatus, filterStatus, disabled, period }) => {
const echeanceOptions = [
{
value: 'createdAt',
label: `Créées ${formatEcheanceLabelPeriod(period)}`,
},
{
value: 'dueOrCompletedAt',
label: `Échéance ${formatEcheanceLabelPeriod(period)} (À FAIRE/FAITE/ANNULÉE ${formatEcheanceLabelPeriod(period)})`,
},
];

return (
<>
<div className="tw-flex tw-justify-between">
<div className="tw-flex tw-w-full tw-shrink-0 tw-grow tw-items-center tw-pl-1 tw-pr-2">
<label htmlFor="action-select-status-filter" className="tw-text-xs">
<div className="tw-flex tw-w-full tw-justify-between tw-gap-x-4">
<div className="tw-flex tw-shrink-0 tw-grow tw-basis-1/2 tw-items-center tw-pl-1 tw-pr-2">
<div className="tw-w-full">
<SelectCustom
inputId="action-switch-created-at"
options={echeanceOptions}
isMulti={false}
name="switchCreatedAt"
value={echeanceOptions.find((o) => o.value === switchCreatedAt)}
onChange={(e) => {
console.log(e, e.value);
setSwitchCreatedAt(e.value);
}}
/>
</div>
</div>
<div className="tw-flex tw-shrink-0 tw-grow tw-basis-1/2 tw-items-center tw-pl-1 tw-pr-2">
{/* <label htmlFor="action-select-status-filter" className="tw-text-xs">
Filtrer par statut
</label>
</label> */}
<div className="tw-w-full">
<SelectCustom
inputId="action-select-status-filter"
placeholder="Filtrer par statut"
options={mappedIdsToLabels}
getOptionValue={(s) => s._id}
getOptionLabel={(s) => s.name}
Expand Down
61 changes: 45 additions & 16 deletions dashboard/src/scenes/report/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ const itemsForReportsSelector = selectorFamily({

const personsCreated = {};
const personsUpdated = {};
const actions = {};
const consultations = {};
const actionsDueOrCompletedAt = {};
const actionsCreatedAt = {};
const consultationsDueOrCompletedAt = {};
const consultationsCreatedAt = {};
const comments = {};
const commentsMedical = {};
const passages = {};
Expand Down Expand Up @@ -97,39 +99,45 @@ const itemsForReportsSelector = selectorFamily({
for (const action of person.actions || []) {
if (!filterItemByTeam(action, 'teams')) continue;
if (Array.isArray(action.teams)) {
let isIncluded = false;
let isDueOrCompletedAt = false;
for (const team of action.teams) {
const { isoStartDate, isoEndDate } = selectedTeamsObjectWithOwnPeriod[team] ?? defaultIsoDates;
if (action.createdAt >= isoStartDate && action.createdAt < isoEndDate) {
actionsCreatedAt[action._id] = action;
}
if (action.completedAt >= isoStartDate && action.completedAt < isoEndDate) {
isIncluded = true;
isDueOrCompletedAt = true;
continue;
}
if (action.status !== TODO) continue;
if (action.dueAt >= isoStartDate && action.dueAt < isoEndDate) {
isIncluded = true;
isDueOrCompletedAt = true;
}
}
if (!isIncluded) continue;
actions[action._id] = action;
if (!isDueOrCompletedAt) continue;
actionsDueOrCompletedAt[action._id] = action;
}
}
for (const consultation of person.consultations || []) {
if (!filterItemByTeam(consultation, 'teams')) continue;
if (Array.isArray(consultation.teams)) {
let isIncluded = false;
let isDueOrCompletedAt = false;
for (const team of consultation.teams) {
const { isoStartDate, isoEndDate } = selectedTeamsObjectWithOwnPeriod[team] ?? defaultIsoDates;
if (consultation.createdAt >= isoStartDate && consultation.createdAt < isoEndDate) {
consultationsCreatedAt[consultation._id] = consultation;
}
if (consultation.completedAt >= isoStartDate && consultation.completedAt < isoEndDate) {
isIncluded = true;
isDueOrCompletedAt = true;
continue;
}
if (consultation.status !== TODO) continue;
if (consultation.dueAt >= isoStartDate && consultation.dueAt < isoEndDate) {
isIncluded = true;
isDueOrCompletedAt = true;
}
}
if (!isIncluded) continue;
consultations[consultation._id] = consultation;
if (!isDueOrCompletedAt) continue;
consultationsDueOrCompletedAt[consultation._id] = consultation;
}
}
for (const rencontre of person.rencontres || []) {
Expand Down Expand Up @@ -189,8 +197,10 @@ const itemsForReportsSelector = selectorFamily({
return {
personsCreated: Object.values(personsCreated),
personsUpdated: Object.values(personsUpdated),
actions: Object.values(actions),
consultations: Object.values(consultations),
actionsDueOrCompletedAt: Object.values(actionsDueOrCompletedAt),
actionsCreatedAt: Object.values(actionsCreatedAt),
consultationsDueOrCompletedAt: Object.values(consultationsDueOrCompletedAt),
consultationsCreatedAt: Object.values(consultationsCreatedAt),
comments: Object.values(comments),
commentsMedical: Object.values(commentsMedical),
passages: Object.values(passages).sort((a, b) => (a.date >= b.date ? -1 : 1)),
Expand Down Expand Up @@ -244,7 +254,19 @@ const View = () => {
return teamsIdsObject;
}, [selectedTeams, period]);

const { personsCreated, actions, consultations, comments, commentsMedical, passages, rencontres, observations, reports } = useRecoilValue(
const {
personsCreated,
actionsDueOrCompletedAt,
actionsCreatedAt,
consultationsDueOrCompletedAt,
consultationsCreatedAt,
comments,
commentsMedical,
passages,
rencontres,
observations,
reports,
} = useRecoilValue(
itemsForReportsSelector({
period,
viewAllOrganisationData,
Expand Down Expand Up @@ -358,7 +380,14 @@ const View = () => {
].join(' ')}>
<div className="tw-mb-12 tw-min-h-1/2 tw-basis-6/12 tw-overflow-auto print:tw-min-h-0 print:tw-basis-full">
<div className="tw-mb-4 tw-h-[60vh] tw-overflow-hidden tw-rounded-lg tw-border tw-border-zinc-200 tw-shadow print:tw-h-auto print:tw-border-none print:tw-shadow-none">
<ActionsOrConsultationsReport actions={actions} consultations={consultations} period={period} />
<ActionsOrConsultationsReport
actionsDueOrCompletedAt={actionsDueOrCompletedAt}
actionsCreatedAt={actionsCreatedAt}
consultationsDueOrCompletedAt={consultationsDueOrCompletedAt}
consultationsCreatedAt={consultationsCreatedAt}
period={period}
preset={preset}
/>
</div>
{canSeeComments && (
<div className="tw-mb-4 tw-h-[60vh] tw-overflow-hidden tw-rounded-lg tw-border tw-border-zinc-200 tw-shadow print:tw-h-auto print:tw-border-none print:tw-shadow-none">
Expand Down
Loading