From 9b1428502a6cacd558840bacebabf389a6cc0edc Mon Sep 17 00:00:00 2001 From: davidbgomes Date: Thu, 2 May 2024 06:50:37 -0500 Subject: [PATCH] Add child count to all surveys --- i18n/en.pot | 43 ++++-- i18n/es.po | 41 ++++-- .../PaginatedSurveyD2Repository.ts | 19 +++ .../repositories/SurveyFormD2Repository.ts | 121 ++-------------- .../PaginatedSurveyTestRepository.ts | 11 ++ src/data/utils/surveyCountHelper.ts | 134 ++++++++++++++++++ src/domain/entities/Survey.ts | 8 +- .../repositories/PaginatedSurveyRepository.ts | 9 ++ src/domain/usecases/GetAllSurveysUseCase.ts | 2 + .../GetPaginatedPatientSurveysUseCase.ts | 45 +++--- src/domain/utils/getChildCount.ts | 3 +- src/domain/utils/getChildrenName.ts | 20 ++- .../survey-list/hook/useDeleteSurvey.ts | 9 +- .../survey-list/hook/useSurveyListActions.ts | 70 ++++----- .../table/PaginatedSurveyListTable.tsx | 97 ++++++++++++- .../survey-list/table/SurveyListTable.tsx | 2 +- 16 files changed, 422 insertions(+), 212 deletions(-) create mode 100644 src/data/utils/surveyCountHelper.ts diff --git a/i18n/en.pot b/i18n/en.pot index 3808711f..3533d87a 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,43 +5,58 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-04-01T18:30:50.736Z\n" -"PO-Revision-Date: 2024-04-01T18:30:50.736Z\n" +"POT-Creation-Date: 2024-04-30T16:29:46.275Z\n" +"PO-Revision-Date: 2024-04-30T16:29:46.275Z\n" -msgid "WHO privacy policy" +msgid "Facilities" msgstr "" -msgid "HOME" +msgid "Sample Shipment" msgstr "" -msgid "Log Out" +msgid "Central Ref Lab Results" msgstr "" -msgid "Stage - Profile" +msgid "Pathogen Isolates Logs" msgstr "" -msgid "Cancel" +msgid "Supranational Ref Results" msgstr "" -msgid "Save" +msgid "Countries" msgstr "" -msgid "PPS Surveys" +msgid "Hospitals" msgstr "" -msgid "New Survey" +msgid "Wards" msgstr "" -msgid "Countries" +msgid "Patients" msgstr "" -msgid "Hospitals" +msgid "WHO privacy policy" msgstr "" -msgid "Wards" +msgid "HOME" msgstr "" -msgid "Patients" +msgid "Log Out" +msgstr "" + +msgid "Stage - Profile" +msgstr "" + +msgid "Cancel" +msgstr "" + +msgid "Save" +msgstr "" + +msgid "PPS Surveys" +msgstr "" + +msgid "New Survey" msgstr "" msgid "Submission Success!" diff --git a/i18n/es.po b/i18n/es.po index 4b065356..38a5b925 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -1,47 +1,62 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2024-04-01T18:30:50.736Z\n" +"POT-Creation-Date: 2024-04-30T16:29:46.275Z\n" "PO-Revision-Date: 2018-10-25T09:02:35.143Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -msgid "WHO privacy policy" +msgid "Facilities" msgstr "" -msgid "HOME" +msgid "Sample Shipment" msgstr "" -msgid "Log Out" +msgid "Central Ref Lab Results" msgstr "" -msgid "Stage - Profile" +msgid "Pathogen Isolates Logs" msgstr "" -msgid "Cancel" +msgid "Supranational Ref Results" msgstr "" -msgid "Save" +msgid "Countries" msgstr "" -msgid "PPS Surveys" +msgid "Hospitals" msgstr "" -msgid "New Survey" +msgid "Wards" msgstr "" -msgid "Countries" +msgid "Patients" msgstr "" -msgid "Hospitals" +msgid "WHO privacy policy" msgstr "" -msgid "Wards" +msgid "HOME" msgstr "" -msgid "Patients" +msgid "Log Out" +msgstr "" + +msgid "Stage - Profile" +msgstr "" + +msgid "Cancel" +msgstr "" + +msgid "Save" +msgstr "" + +msgid "PPS Surveys" +msgstr "" + +msgid "New Survey" msgstr "" msgid "Submission Success!" diff --git a/src/data/repositories/PaginatedSurveyD2Repository.ts b/src/data/repositories/PaginatedSurveyD2Repository.ts index 3d875dd9..799b5996 100644 --- a/src/data/repositories/PaginatedSurveyD2Repository.ts +++ b/src/data/repositories/PaginatedSurveyD2Repository.ts @@ -15,6 +15,8 @@ import { } from "../entities/D2Survey"; import { TrackerEventsResponse } from "@eyeseetea/d2-api/api/trackerEvents"; import { mapEventToSurvey, mapTrackedEntityToSurvey } from "../utils/surveyListMappers"; +import { getSurveyChildCount } from "../utils/surveyCountHelper"; +import { ProgramCountMap } from "../../domain/entities/Program"; export class PaginatedSurveyD2Repository implements PaginatedSurveyRepository { constructor(private api: D2Api) {} @@ -154,4 +156,21 @@ export class PaginatedSurveyD2Repository implements PaginatedSurveyRepository { return Future.success(paginatedSurveys); }); } + + getSurveyChildCount( + parentProgram: Id, + orgUnitId: Id, + parentSurveyId: Id, + secondaryparentId: Id | undefined + ): + | { type: "value"; value: FutureData } + | { type: "map"; value: FutureData } { + return getSurveyChildCount( + parentProgram, + orgUnitId, + parentSurveyId, + secondaryparentId, + this.api + ); + } } diff --git a/src/data/repositories/SurveyFormD2Repository.ts b/src/data/repositories/SurveyFormD2Repository.ts index fa223260..2c8c68b0 100644 --- a/src/data/repositories/SurveyFormD2Repository.ts +++ b/src/data/repositories/SurveyFormD2Repository.ts @@ -13,8 +13,6 @@ import { TrackedEntitiesGetResponse, } from "@eyeseetea/d2-api/api/trackerTrackedEntities"; import { - getChildProgramId, - getParentDataElementForProgram, getSurveyType, getTrackedEntityAttributeType, isTrackerProgram, @@ -26,7 +24,6 @@ import { PPS_PATIENT_REGISTER_ID, SURVEY_NAME_DATAELEMENT_ID, PREVALENCE_SURVEY_NAME_DATAELEMENT_ID, - PPS_COUNTRY_QUESTIONNAIRE_ID, } from "../entities/D2Survey"; import { ProgramDataElement, ProgramMetadata } from "../entities/D2Program"; import { @@ -36,6 +33,7 @@ import { } from "../utils/surveyFormMappers"; import { mapEventToSurvey, mapTrackedEntityToSurvey } from "../utils/surveyListMappers"; import { Questionnaire } from "../../domain/entities/Questionnaire/Questionnaire"; +import { getSurveyChildCount } from "../utils/surveyCountHelper"; export class SurveyD2Repository implements SurveyRepository { constructor(private api: D2Api) {} @@ -316,116 +314,13 @@ export class SurveyD2Repository implements SurveyRepository { ): | { type: "value"; value: FutureData } | { type: "map"; value: FutureData } { - const childIds = getChildProgramId(parentProgram); - - //As of now, all child programs for a given program are of the same type, - //so we will check only the first child - - const childId = childIds.type === "singleChild" ? childIds.value : childIds.value[0]; - - if (childId) { - const isTracker = isTrackerProgram(childId); - - if (isTracker) { - if (childIds.type === "singleChild") { - const eventCount = this.getTrackerSurveyCount( - childId, - orgUnitId, - parentSurveyId - ); - - return { type: "value", value: eventCount }; - } else { - const eventCounts = childIds.value.map(id => { - return this.getTrackerSurveyCount(id, orgUnitId, parentSurveyId).map( - count => { - return { id: id, count: count }; - } - ); - }); - - return { type: "map", value: Future.sequential(eventCounts) }; - } - } else { - if (childIds.type === "singleChild") { - const eventCount = this.getEventSurveyCount( - childIds.value, - orgUnitId, - parentSurveyId, - secondaryparentId - ); - - return { type: "value", value: eventCount }; - } else { - return { - type: "map", - value: Future.error( - new Error( - "Event programs in AMR Surveys have single child. It should not contain multiple children" - ) - ), - }; - } - } - } else { - return { - type: "value", - value: Future.error(new Error("Unknown Child program ")), - }; - } - } - - private getEventSurveyCount( - programId: Id, - orgUnitId: Id, - parentSurveyId: Id, - secondaryParentId: Id | undefined - ): FutureData { - const ouId = programId === PPS_COUNTRY_QUESTIONNAIRE_ID ? "" : orgUnitId; - const ouMode = programId === PPS_HOSPITAL_FORM_ID ? "DESCENDANTS" : undefined; - const filterParentDEId = getParentDataElementForProgram(programId); - - const filterStr = - secondaryParentId === "" - ? `${filterParentDEId}:eq:${parentSurveyId}` - : `${filterParentDEId}:eq:${secondaryParentId} `; - - return apiToFuture( - this.api.tracker.events.get({ - fields: { event: true }, - program: programId, - orgUnit: ouId, - ouMode: ouMode, - filter: filterStr, - }) - ).flatMap(response => { - return Future.success(response.instances.length); - }); - } - - private getTrackerSurveyCount( - programId: Id, - orgUnitId: Id, - parentSurveyId: Id - ): FutureData { - const filterParentDEId = getParentDataElementForProgram(programId); - - const ouMode = - orgUnitId !== "" && programId === PREVALENCE_FACILITY_LEVEL_FORM_ID - ? "DESCENDANTS" - : undefined; - - return apiToFuture( - this.api.tracker.trackedEntities.get({ - fields: { trackedEntity: true }, - program: programId, - orgUnit: orgUnitId, - ouMode: ouMode, - filter: `${filterParentDEId}:eq:${parentSurveyId}`, - }) - ).flatMap((trackedEntities: TrackedEntitiesGetResponse) => { - return Future.success(trackedEntities.instances.length); - }); + return getSurveyChildCount( + parentProgram, + orgUnitId, + parentSurveyId, + secondaryparentId, + this.api + ); } deleteSurvey(id: Id, orgUnitId: Id, programId: Id): FutureData { diff --git a/src/data/repositories/testRepositories/PaginatedSurveyTestRepository.ts b/src/data/repositories/testRepositories/PaginatedSurveyTestRepository.ts index 05114c7e..272c7170 100644 --- a/src/data/repositories/testRepositories/PaginatedSurveyTestRepository.ts +++ b/src/data/repositories/testRepositories/PaginatedSurveyTestRepository.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ +import { ProgramCountMap } from "../../../domain/entities/Program"; import { SURVEY_FORM_TYPES, Survey } from "../../../domain/entities/Survey"; import { PaginatedReponse } from "../../../domain/entities/TablePagination"; import { PaginatedSurveyRepository } from "../../../domain/repositories/PaginatedSurveyRepository"; @@ -21,4 +22,14 @@ export class PaginatedSurveyTestRepository implements PaginatedSurveyRepository ): FutureData> { throw new Error("Method not implemented."); } + getSurveyChildCount( + parentProgram: string, + orgUnitId: string, + parentSurveyId: string, + secondaryparentId: string | undefined + ): + | { type: "value"; value: FutureData } + | { type: "map"; value: FutureData } { + throw new Error("Method not implemented."); + } } diff --git a/src/data/utils/surveyCountHelper.ts b/src/data/utils/surveyCountHelper.ts new file mode 100644 index 00000000..9d31aead --- /dev/null +++ b/src/data/utils/surveyCountHelper.ts @@ -0,0 +1,134 @@ +import { Id } from "@eyeseetea/d2-api"; +import { FutureData, apiToFuture } from "../api-futures"; +import { + getChildProgramId, + getParentDataElementForProgram, + isTrackerProgram, +} from "./surveyProgramHelper"; +import { ProgramCountMap } from "../../domain/entities/Program"; +import { Future } from "../../domain/entities/generic/Future"; +import { + PPS_COUNTRY_QUESTIONNAIRE_ID, + PPS_HOSPITAL_FORM_ID, + PREVALENCE_FACILITY_LEVEL_FORM_ID, +} from "../entities/D2Survey"; +import { D2Api } from "@eyeseetea/d2-api/2.36"; +import { TrackedEntitiesGetResponse } from "@eyeseetea/d2-api/api/trackerTrackedEntities"; + +export const getSurveyChildCount = ( + parentProgram: Id, + orgUnitId: Id, + parentSurveyId: Id, + secondaryparentId: Id | undefined, + api: D2Api +): + | { type: "value"; value: FutureData } + | { type: "map"; value: FutureData } => { + const childIds = getChildProgramId(parentProgram); + + //As of now, all child programs for a given program are of the same type, + //so we will check only the first child + + const childId = childIds.type === "singleChild" ? childIds.value : childIds.value[0]; + + if (childId) { + const isTracker = isTrackerProgram(childId); + + if (isTracker) { + if (childIds.type === "singleChild") { + const eventCount = getTrackerSurveyCount(childId, orgUnitId, parentSurveyId, api); + + return { type: "value", value: eventCount }; + } else { + const eventCounts = childIds.value.map(id => { + return getTrackerSurveyCount(id, orgUnitId, parentSurveyId, api).map(count => { + return { id: id, count: count }; + }); + }); + + return { type: "map", value: Future.sequential(eventCounts) }; + } + } else { + if (childIds.type === "singleChild") { + const eventCount = getEventSurveyCount( + childIds.value, + orgUnitId, + parentSurveyId, + secondaryparentId, + api + ); + + return { type: "value", value: eventCount }; + } else { + return { + type: "map", + value: Future.error( + new Error( + "Event programs in AMR Surveys have single child. It should not contain multiple children" + ) + ), + }; + } + } + } else { + return { + type: "value", + value: Future.error(new Error("Unknown Child program ")), + }; + } +}; + +const getEventSurveyCount = ( + programId: Id, + orgUnitId: Id, + parentSurveyId: Id, + secondaryParentId: Id | undefined, + api: D2Api +): FutureData => { + const ouId = programId === PPS_COUNTRY_QUESTIONNAIRE_ID ? "" : orgUnitId; + const ouMode = programId === PPS_HOSPITAL_FORM_ID ? "DESCENDANTS" : undefined; + const filterParentDEId = getParentDataElementForProgram(programId); + + const filterStr = + secondaryParentId === "" + ? `${filterParentDEId}:eq:${parentSurveyId}` + : `${filterParentDEId}:eq:${secondaryParentId} `; + + return apiToFuture( + api.tracker.events.get({ + fields: { event: true }, + program: programId, + orgUnit: ouId, + ouMode: ouMode, + filter: filterStr, + }) + ).flatMap(response => { + return Future.success(response.instances.length); + }); +}; + +const getTrackerSurveyCount = ( + programId: Id, + orgUnitId: Id, + parentSurveyId: Id, + api: D2Api +): FutureData => { + const filterParentDEId = getParentDataElementForProgram(programId); + + const ouMode = + orgUnitId !== "" && programId === PREVALENCE_FACILITY_LEVEL_FORM_ID + ? "DESCENDANTS" + : undefined; + + return apiToFuture( + api.tracker.trackedEntities.get({ + fields: { trackedEntity: true }, + program: programId, + orgUnit: orgUnitId, + ouMode: ouMode, + filter: `${filterParentDEId}:eq:${parentSurveyId}`, + }) + ).flatMap((trackedEntities: TrackedEntitiesGetResponse) => { + return Future.success(trackedEntities.instances.length); + }); +}; diff --git a/src/domain/entities/Survey.ts b/src/domain/entities/Survey.ts index 2343a89f..cd67fa9f 100644 --- a/src/domain/entities/Survey.ts +++ b/src/domain/entities/Survey.ts @@ -1,4 +1,5 @@ import { ASTGUIDELINE_TYPES } from "./ASTGuidelines"; +import { ProgramOptionCountMap } from "./Program"; import { NamedRef, Id } from "./Ref"; export type SURVEY_FORM_TYPES = @@ -21,6 +22,11 @@ export type SURVEY_TYPES = "SUPRANATIONAL" | "NATIONAL" | "HOSP"; export const SURVEYS_WITH_CHILD_COUNT: SURVEY_FORM_TYPES[] = [ "PrevalenceSurveyForm", "PrevalenceFacilityLevelForm", + "PrevalenceCaseReportForm", + "PPSSurveyForm", + "PPSCountryQuestionnaire", + "PPSHospitalForm", + "PPSWardRegister", ]; export interface SurveyBase extends NamedRef { @@ -43,5 +49,5 @@ export interface Survey extends SurveyBase { assignedOrgUnit: NamedRef; surveyFormType: SURVEY_FORM_TYPES; parentWardRegisterId?: Id; - childCount?: number; + childCount?: number | ProgramOptionCountMap; } diff --git a/src/domain/repositories/PaginatedSurveyRepository.ts b/src/domain/repositories/PaginatedSurveyRepository.ts index 7f8dee66..e0917c3c 100644 --- a/src/domain/repositories/PaginatedSurveyRepository.ts +++ b/src/domain/repositories/PaginatedSurveyRepository.ts @@ -1,4 +1,5 @@ import { FutureData } from "../../data/api-futures"; +import { ProgramCountMap } from "../entities/Program"; import { Id } from "../entities/Ref"; import { Survey, SURVEY_FORM_TYPES } from "../entities/Survey"; import { PaginatedReponse } from "../entities/TablePagination"; @@ -16,4 +17,12 @@ export interface PaginatedSurveyRepository { keyword: string, orgUnitId: Id ): FutureData>; + getSurveyChildCount( + parentProgram: Id, + orgUnitId: Id, + parentSurveyId: Id, + secondaryparentId: Id | undefined + ): + | { type: "value"; value: FutureData } + | { type: "map"; value: FutureData }; } diff --git a/src/domain/usecases/GetAllSurveysUseCase.ts b/src/domain/usecases/GetAllSurveysUseCase.ts index 7d6d8c01..03e1d01f 100644 --- a/src/domain/usecases/GetAllSurveysUseCase.ts +++ b/src/domain/usecases/GetAllSurveysUseCase.ts @@ -48,6 +48,8 @@ export class GetAllSurveysUseCase { orgUnitId: survey.assignedOrgUnit.id, parentSurveyId: survey.rootSurvey.id, surveyReporsitory: this.surveyReporsitory, + secondaryparentId: + surveyFormType === "PPSWardRegister" ? survey.id : "", }) ).map(([parentSurveyName, childCount]): Survey => { const count = diff --git a/src/domain/usecases/GetPaginatedPatientSurveysUseCase.ts b/src/domain/usecases/GetPaginatedPatientSurveysUseCase.ts index e300dc9f..273ae33c 100644 --- a/src/domain/usecases/GetPaginatedPatientSurveysUseCase.ts +++ b/src/domain/usecases/GetPaginatedPatientSurveysUseCase.ts @@ -7,6 +7,7 @@ import { PaginatedReponse } from "../entities/TablePagination"; import { PaginatedSurveyRepository } from "../repositories/PaginatedSurveyRepository"; import { SurveyRepository } from "../repositories/SurveyRepository"; import _ from "../entities/generic/Collection"; +import { getChildCount } from "../utils/getChildCount"; //This use case fetched only patient surveys for both Prevalence and PPS modules export class GetPaginatedPatientSurveysUseCase { @@ -32,24 +33,34 @@ export class GetPaginatedPatientSurveysUseCase { .getSurveys(surveyFormType, programId, orgUnitId, parentId, page, pageSize) .flatMap(surveys => { const surveysWithName = surveys.objects.map(survey => { - return this.surveyReporsitory - .getSurveyNameFromId(survey.rootSurvey.id, survey.surveyFormType) - .map((parentSurveyName): Survey => { - const newRootSurvey: SurveyBase = { - surveyType: survey.rootSurvey.surveyType, - id: survey.rootSurvey.id, - name: - survey.rootSurvey.name === "" - ? parentSurveyName - : survey.rootSurvey.name, - }; + return Future.join2( + this.surveyReporsitory.getSurveyNameFromId( + survey.rootSurvey.id, + survey.surveyFormType + ), + getChildCount({ + surveyFormType: surveyFormType, + orgUnitId: survey.assignedOrgUnit.id, + parentSurveyId: survey.rootSurvey.id, + surveyReporsitory: this.paginatedSurveyRepo, + }) + ).map(([parentSurveyName, childCount]): Survey => { + const newRootSurvey: SurveyBase = { + surveyType: survey.rootSurvey.surveyType, + id: survey.rootSurvey.id, + name: + survey.rootSurvey.name === "" + ? parentSurveyName + : survey.rootSurvey.name, + }; - const updatedSurvey: Survey = { - ...survey, - rootSurvey: newRootSurvey, - }; - return updatedSurvey; - }); + const updatedSurvey: Survey = { + ...survey, + rootSurvey: newRootSurvey, + childCount: childCount, + }; + return updatedSurvey; + }); }); return Future.sequential(surveysWithName).map(updatedSurveys => { diff --git a/src/domain/utils/getChildCount.ts b/src/domain/utils/getChildCount.ts index 24e26db5..3906666e 100644 --- a/src/domain/utils/getChildCount.ts +++ b/src/domain/utils/getChildCount.ts @@ -10,13 +10,14 @@ import { PREVALENCE_SAMPLE_SHIP_TRACK_FORM_ID, PREVALENCE_SUPRANATIONAL_REF_LAB_ID, } from "../../data/entities/D2Survey"; +import { PaginatedSurveyRepository } from "../repositories/PaginatedSurveyRepository"; type GetChildCountType = { surveyFormType: SURVEY_FORM_TYPES; orgUnitId: Id; parentSurveyId: Id; secondaryparentId?: Id; - surveyReporsitory: SurveyRepository; + surveyReporsitory: SurveyRepository | PaginatedSurveyRepository; }; export const getChildCount = ({ diff --git a/src/domain/utils/getChildrenName.ts b/src/domain/utils/getChildrenName.ts index 1e9977ee..24a5bf46 100644 --- a/src/domain/utils/getChildrenName.ts +++ b/src/domain/utils/getChildrenName.ts @@ -1,12 +1,26 @@ import i18n from "../../utils/i18n"; import { SURVEY_FORM_TYPES } from "../entities/Survey"; -export const getChildrenName = (surveyFormType: SURVEY_FORM_TYPES): string => { +export const getChildrenName = (surveyFormType: SURVEY_FORM_TYPES): string[] => { switch (surveyFormType) { case "PrevalenceSurveyForm": - return i18n.t("Facilities"); + return [i18n.t("Facilities")]; + case "PrevalenceCaseReportForm": + return [ + i18n.t("Sample Shipment"), + i18n.t("Central Ref Lab Results"), + i18n.t("Pathogen Isolates Logs"), + i18n.t("Supranational Ref Results"), + ]; + case "PPSSurveyForm": + return [i18n.t("Countries")]; + case "PPSCountryQuestionnaire": + return [i18n.t("Hospitals")]; + case "PPSHospitalForm": + return [i18n.t("Wards")]; case "PrevalenceFacilityLevelForm": - return i18n.t("Patients"); + case "PPSWardRegister": + return [i18n.t("Patients")]; default: throw new Error("Invalid survey form type"); } diff --git a/src/webapp/components/survey-list/hook/useDeleteSurvey.ts b/src/webapp/components/survey-list/hook/useDeleteSurvey.ts index 1606d0dd..102c101e 100644 --- a/src/webapp/components/survey-list/hook/useDeleteSurvey.ts +++ b/src/webapp/components/survey-list/hook/useDeleteSurvey.ts @@ -17,7 +17,14 @@ export function useDeleteSurvey( const { currentHospitalForm } = useCurrentSurveys(); const showDeleteErrorMsg = (survey: Survey) => { - if (survey.childCount && survey.childCount > 0) { + const count = + typeof survey.childCount === "number" + ? survey.childCount + : survey.childCount + ?.map(child => child.count) + .reduce((agg, childCount) => agg + childCount, 0) || 0; + + if (survey.childCount && count > 0) { setDeleteCompleteState({ status: "error", message: i18n.t( diff --git a/src/webapp/components/survey-list/hook/useSurveyListActions.ts b/src/webapp/components/survey-list/hook/useSurveyListActions.ts index 506e4b10..58c799af 100644 --- a/src/webapp/components/survey-list/hook/useSurveyListActions.ts +++ b/src/webapp/components/survey-list/hook/useSurveyListActions.ts @@ -111,53 +111,33 @@ export function useSurveyListActions(surveyFormType: SURVEY_FORM_TYPES) { setOptionLoading(false); return; } + const { childCount } = survey; - compositionRoot.surveys.getChildCount - .execute( - surveyFormType, - survey.assignedOrgUnit.id, - survey.rootSurvey.id, - surveyFormType === "PPSWardRegister" ? survey.id : "" - ) - .run( - childCountMap => { - if (typeof childCountMap === "number") { - const optionsWithChildCount = currentOptions.map(option => { - if (option.label.startsWith("List")) { - const updatedLabel = `${option.label} (${childCountMap})`; - return { ...option, label: updatedLabel }; - } - return option; - }); - if (survey) survey.childCount = childCountMap; - setOptions(optionsWithChildCount); - setOptionLoading(false); - } else { - const optionsWithChildCount = currentOptions.map(option => { - const updatedChilsOptionMap = childCountMap.find(childMap => - childMap.option.label.startsWith(option.label) - ); - if (updatedChilsOptionMap) { - return updatedChilsOptionMap.option; - } else { - return option; - } - }); - if (survey) - survey.childCount = childCountMap.reduce((agg, childCount) => { - return agg + childCount.count; - }, 0); - - setOptions(optionsWithChildCount); - setOptionLoading(false); - } - }, - err => { - console.debug(`Could not get child count, error : ${err}`); - setOptions(currentOptions); - setOptionLoading(false); + if (typeof childCount === "number") { + const optionsWithChildCount = currentOptions.map(option => { + if (option.label.startsWith("List")) { + const updatedLabel = `${option.label} (${childCount})`; + return { ...option, label: updatedLabel }; } - ); + return option; + }); + setOptions(optionsWithChildCount); + setOptionLoading(false); + } else { + const optionsWithChildCount = currentOptions.map(option => { + const updatedChilsOptionMap = childCount?.find(childMap => + childMap.option.label.startsWith(option.label) + ); + if (updatedChilsOptionMap) { + return updatedChilsOptionMap.option; + } else { + return option; + } + }); + + setOptions(optionsWithChildCount); + setOptionLoading(false); + } }; const sortByColumn = (columnName: keyof Survey, sortDirection: SortDirection) => { diff --git a/src/webapp/components/survey-list/table/PaginatedSurveyListTable.tsx b/src/webapp/components/survey-list/table/PaginatedSurveyListTable.tsx index c5c26247..4856c816 100644 --- a/src/webapp/components/survey-list/table/PaginatedSurveyListTable.tsx +++ b/src/webapp/components/survey-list/table/PaginatedSurveyListTable.tsx @@ -1,4 +1,8 @@ -import { Survey, SURVEY_FORM_TYPES } from "../../../../domain/entities/Survey"; +import { + Survey, + SURVEY_FORM_TYPES, + SURVEYS_WITH_CHILD_COUNT, +} from "../../../../domain/entities/Survey"; import { useSnackbar } from "@eyeseetea/d2-ui-components"; import styled from "styled-components"; import { @@ -15,12 +19,13 @@ import { import i18n from "@eyeseetea/feedback-component/locales"; import { ActionMenuButton } from "../../action-menu-button/ActionMenuButton"; import { palette } from "../../../pages/app/themes/dhis2.theme"; -import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { Dispatch, MouseEventHandler, SetStateAction, useEffect, useState } from "react"; import { ArrowDownward, ArrowUpward } from "@material-ui/icons"; import _ from "../../../../domain/entities/generic/Collection"; import { useDeleteSurvey } from "../hook/useDeleteSurvey"; import { ContentLoader } from "../../content-loader/ContentLoader"; import { useSurveyListActions } from "../hook/useSurveyListActions"; +import { getChildrenName } from "../../../../domain/utils/getChildrenName"; interface PaginatedSurveyListTableProps { surveys: Survey[] | undefined; @@ -33,7 +38,6 @@ interface PaginatedSurveyListTableProps { } export type SortDirection = "asc" | "desc"; -export type SurveyColumns = keyof Survey; export const PaginatedSurveyListTable: React.FC = ({ surveys, surveyFormType, @@ -48,6 +52,14 @@ export const PaginatedSurveyListTable: React.FC = const [surveyNameSortDirection, setSurveyNameSortDirection] = useState("asc"); const [patientIdSortDirection, setPatientIdSortDirection] = useState("asc"); const [patientNameSortDirection, setPatientNameSortDirection] = useState("asc"); + const [sampleShipmentsSortDirection, setSampleShipmentsSortDirection] = + useState("asc"); + const [centralRefLabsResultsSortDirection, setCentralRefLabsResultsSortDirection] = + useState("asc"); + const [pathogenIsolatesLogsSortDirection, setPathogenIsolatesLogsSortDirection] = + useState("asc"); + const [supranationalRefsResultsSortDirection, setSupranationalRefsResultsSortDirection] = + useState("asc"); const { deleteSurvey, loading, deleteCompleteState } = useDeleteSurvey( surveyFormType, @@ -76,6 +88,56 @@ export const PaginatedSurveyListTable: React.FC = } }, [deleteCompleteState, snackbar, surveys, setSortedSurveys]); + const getCurrentSortDirection = (childOptionName: string): SortDirection => { + switch (childOptionName) { + case "Sample Shipment": + return sampleShipmentsSortDirection; + case "Central Ref Lab Results": + return centralRefLabsResultsSortDirection; + case "Pathogen Isolates Logs": + return pathogenIsolatesLogsSortDirection; + case "Supranational Ref Results": + return supranationalRefsResultsSortDirection; + default: + throw new Error(`Invalid child option name: ${childOptionName}`); + } + }; + + const childOnClick = (childOptionName: string): MouseEventHandler | undefined => { + switch (childOptionName) { + case "Sample Shipment": + return () => { + sampleShipmentsSortDirection === "asc" + ? setSampleShipmentsSortDirection("desc") + : setSampleShipmentsSortDirection("asc"); + sortByColumn("childCount", sampleShipmentsSortDirection); + }; + case "Central Ref Lab Results": + return () => { + centralRefLabsResultsSortDirection === "asc" + ? setCentralRefLabsResultsSortDirection("desc") + : setCentralRefLabsResultsSortDirection("asc"); + sortByColumn("childCount", centralRefLabsResultsSortDirection); + }; + case "Pathogen Isolates Logs": + return () => { + pathogenIsolatesLogsSortDirection === "asc" + ? setPathogenIsolatesLogsSortDirection("desc") + : setPathogenIsolatesLogsSortDirection("asc"); + sortByColumn("childCount", pathogenIsolatesLogsSortDirection); + }; + case "Supranational Ref Results": + return () => { + supranationalRefsResultsSortDirection === "asc" + ? setSupranationalRefsResultsSortDirection("desc") + : setSupranationalRefsResultsSortDirection("asc"); + sortByColumn("childCount", supranationalRefsResultsSortDirection); + }; + default: + return undefined; + } + }; + return ( {sortedSurveys && ( @@ -145,6 +207,26 @@ export const PaginatedSurveyListTable: React.FC = + {SURVEYS_WITH_CHILD_COUNT.includes(surveyFormType) && + getChildrenName(surveyFormType).map(childName => ( + + + + {childName} + + {childName && + getCurrentSortDirection(childName) === "asc" ? ( + + ) : ( + + )} + + + ))} + {i18n.t("Action")} @@ -162,6 +244,15 @@ export const PaginatedSurveyListTable: React.FC = {survey.id} {survey.name} + {SURVEYS_WITH_CHILD_COUNT.includes(surveyFormType) && + typeof survey.childCount !== "number" && + survey.childCount?.map((option, index) => { + return ( + + {option.count} + + ); + })} = ({ )} {SURVEYS_WITH_CHILD_COUNT.includes(surveyFormType) && ( - {survey.childCount} + {survey.childCount as number} )}