Skip to content

Commit

Permalink
Merge pull request #33 from EyeSeeTea/feat/prevalence-non-admin
Browse files Browse the repository at this point in the history
Feat/prevalence non admin
  • Loading branch information
MiquelAdell authored Apr 25, 2024
2 parents 200ff35 + 37f2d72 commit 059a187
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 63 deletions.
46 changes: 44 additions & 2 deletions src/data/repositories/SurveyFormD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
import { mapEventToSurvey, mapTrackedEntityToSurvey } from "../utils/surveyListMappers";
import { Questionnaire } from "../../domain/entities/Questionnaire/Questionnaire";

const OU_CHUNK_SIZE = 500;
export class SurveyD2Repository implements SurveyRepository {
constructor(private api: D2Api) {}

Expand Down Expand Up @@ -193,15 +194,27 @@ export class SurveyD2Repository implements SurveyRepository {
getSurveys(
surveyFormType: SURVEY_FORM_TYPES,
programId: Id,
orgUnitId: Id
orgUnitId: Id,
chunked = false
): FutureData<Survey[]> {
return isTrackerProgram(programId)
? this.getTrackerProgramSurveys(surveyFormType, programId, orgUnitId)
? this.getTrackerProgramSurveys(surveyFormType, programId, orgUnitId, chunked)
: this.getEventProgramSurveys(surveyFormType, programId, orgUnitId);
}

//Currently tracker programs are only in Prevalence module
private getTrackerProgramSurveys(
surveyFormType: SURVEY_FORM_TYPES,
programId: Id,
orgUnitId: Id,
chunked = false
): FutureData<Survey[]> {
return chunked
? this.getTrackerProgramSurveysChunked(surveyFormType, programId, orgUnitId)
: this.getTrackerProgramSurveysUnchunked(surveyFormType, programId, orgUnitId);
}

private getTrackerProgramSurveysUnchunked(
surveyFormType: SURVEY_FORM_TYPES,
programId: Id,
orgUnitId: Id
Expand All @@ -224,6 +237,35 @@ export class SurveyD2Repository implements SurveyRepository {
});
}

private getTrackerProgramSurveysChunked(
surveyFormType: SURVEY_FORM_TYPES,
programId: Id,
orgUnits: string
): FutureData<Survey[]> {
const orgUnitIds = orgUnits.split(";");
const chunkedOUs = _(orgUnitIds).chunk(OU_CHUNK_SIZE).value();

return Future.sequential(
chunkedOUs.flatMap(ouChunk => {
return apiToFuture(
this.api.tracker.trackedEntities.get({
fields: {
attributes: true,
enrollments: true,
trackedEntity: true,
orgUnit: true,
},
program: programId,
orgUnit: ouChunk.join(";"),
})
).flatMap((trackedEntities: TrackedEntitiesGetResponse) => {
const surveys = mapTrackedEntityToSurvey(trackedEntities, surveyFormType);
return Future.success(surveys);
});
})
).flatMap(listOfSurveys => Future.success(_(listOfSurveys).flatten().value()));
}

private getEventProgramSurveys(
surveyFormType: SURVEY_FORM_TYPES,
programId: Id,
Expand Down
3 changes: 2 additions & 1 deletion src/domain/repositories/SurveyRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export interface SurveyRepository {
getSurveys(
surveyFormType: SURVEY_FORM_TYPES,
programId: Id,
orgUnitId: Id
orgUnitId: Id,
chunked: boolean
): FutureData<Survey[]>;
getPopulatedSurveyById(
eventId: Id,
Expand Down
9 changes: 6 additions & 3 deletions src/domain/usecases/GetAllSurveysUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,22 @@ export class GetAllSurveysUseCase {
public execute(
surveyFormType: SURVEY_FORM_TYPES,
orgUnitId: Id,
parentSurveyId: Id | undefined
parentSurveyId: Id | undefined,
chunked = false
): FutureData<Survey[]> {
const programId = getProgramId(surveyFormType);

//All PPS Survey Forms are Global.
const ouId = surveyFormType === "PPSSurveyForm" ? GLOBAL_OU_ID : orgUnitId;

return this.surveyReporsitory
.getSurveys(surveyFormType, programId, ouId)
.getSurveys(surveyFormType, programId, ouId, chunked)
.flatMap(surveys => {
const filteredSurveys =
surveyFormType === "PPSSurveyForm" ||
(surveyFormType === "PPSHospitalForm" && !parentSurveyId) ||
surveyFormType === "PrevalenceSurveyForm"
surveyFormType === "PrevalenceSurveyForm" ||
(surveyFormType === "PrevalenceFacilityLevelForm" && !parentSurveyId)
? surveys
: _(
surveys.map(survey => {
Expand All @@ -47,6 +49,7 @@ export class GetAllSurveysUseCase {
survey.rootSurvey.name === ""
? parentSurveyName
: survey.rootSurvey.name,
astGuideline: survey.rootSurvey.astGuideline,
};

const updatedSurvey: Survey = {
Expand Down
3 changes: 2 additions & 1 deletion src/domain/utils/PPSProgramsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ export const hideCreateNewButton = (
(surveyFormType === "PPSCountryQuestionnaire" &&
currentPPSFormType === "NATIONAL" &&
surveys !== undefined &&
surveys.length >= 1)
surveys.length >= 1) ||
(surveyFormType === "PrevalenceFacilityLevelForm" && !isAdmin)
);
};

Expand Down
11 changes: 10 additions & 1 deletion src/domain/utils/menuHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,16 @@ export const getBaseSurveyFormType = (
);
}
case "Prevalence": {
return "PrevalenceSurveyForm";
const { hasReadAccess, hasCaptureAccess, hasAdminAccess } = getUserAccess(
module,
currentUserGroups
);
if (hasAdminAccess) return "PrevalenceSurveyForm";
else if (hasReadAccess || hasCaptureAccess) return "PrevalenceFacilityLevelForm";
else
throw new Error(
"You dont have the neccessary permissions. Please contact your system administrator."
);
}
default:
throw new Error("Unknown Module type");
Expand Down
13 changes: 11 additions & 2 deletions src/webapp/components/survey-list/hook/useSurveyListActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useAppContext } from "../../../contexts/app-context";
import { OptionType } from "../../../../domain/utils/optionsHelper";
import useReadOnlyAccess from "../../survey/hook/useReadOnlyAccess";
import useCaptureAccess from "../../survey/hook/useCaptureAccess";
import { GLOBAL_OU_ID } from "../../../../domain/usecases/SaveFormDataUseCase";
import { useCurrentASTGuidelinesContext } from "../../../contexts/current-ast-guidelines-context";

export type SortDirection = "asc" | "desc";
Expand Down Expand Up @@ -205,9 +206,17 @@ export function useSurveyListActions(surveyFormType: SURVEY_FORM_TYPES) {
console.debug(` No AST guidelines data could be fetched : ${err}`);
}
);
} else if (surveyFormType === "PrevalenceFacilityLevelForm")
} else if (surveyFormType === "PrevalenceFacilityLevelForm") {
if (!isAdmin) {
changeCurrentPrevalenceSurveyForm(
rootSurvey.id,
rootSurvey.name,
GLOBAL_OU_ID,
rootSurvey.astGuideline
);
}
changeCurrentFacilityLevelForm(survey.id, survey.name, orgUnitId);
else if (surveyFormType === "PrevalenceCaseReportForm")
} else if (surveyFormType === "PrevalenceCaseReportForm")
changeCurrentCaseReportForm({ id: survey.id, name: survey.name });
};

Expand Down
1 change: 1 addition & 0 deletions src/webapp/contexts/hospital-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useContext } from "react";
import { OrgUnitAccess } from "../../domain/entities/User";

export interface HospitalContextState {
hospitalState: "loading" | "error" | "loaded";
userHospitalsAccess: OrgUnitAccess[];
}

Expand Down
52 changes: 44 additions & 8 deletions src/webapp/hooks/useSurveys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { Survey, SURVEY_FORM_TYPES } from "../../domain/entities/Survey";
import { useAppContext } from "../contexts/app-context";
import { useCurrentSurveys } from "../contexts/current-surveys-context";
import { isPaginatedSurveyList } from "../../domain/utils/PPSProgramsHelper";
import { getUserAccess } from "../../domain/utils/menuHelper";
import { useCurrentModule } from "../contexts/current-module-context";
import { useHospitalContext } from "../contexts/hospital-context";

const PAGE_SIZE = 10;
export function useSurveys(surveyFormType: SURVEY_FORM_TYPES) {
Expand All @@ -23,7 +26,19 @@ export function useSurveys(surveyFormType: SURVEY_FORM_TYPES) {
currentFacilityLevelForm,
} = useCurrentSurveys();

const { currentModule } = useCurrentModule();
const {
currentUser: { userGroups },
} = useAppContext();
const { hospitalState, userHospitalsAccess } = useHospitalContext();
const isAdmin = currentModule ? getUserAccess(currentModule, userGroups).hasAdminAccess : false;

const getOrgUnitByFormType = useCallback(() => {
const currentUserHospitals = userHospitalsAccess
.filter(hospitals => hospitals.readAccess && hospitals.captureAccess)
.map(hospital => hospital.orgUnitId)
.join(";");

switch (surveyFormType) {
case "PPSHospitalForm":
return currentCountryQuestionnaire?.orgUnitId ?? "";
Expand All @@ -32,7 +47,9 @@ export function useSurveys(surveyFormType: SURVEY_FORM_TYPES) {
return currentHospitalForm?.orgUnitId ?? "";

case "PrevalenceFacilityLevelForm":
return currentPrevalenceSurveyForm?.orgUnitId ?? "";
return isAdmin
? currentPrevalenceSurveyForm?.orgUnitId ?? ""
: currentUserHospitals;
case "PrevalenceCaseReportForm":
case "PrevalenceCentralRefLabForm":
case "PrevalencePathogenIsolatesLog":
Expand All @@ -47,19 +64,34 @@ export function useSurveys(surveyFormType: SURVEY_FORM_TYPES) {
currentFacilityLevelForm?.orgUnitId,
currentHospitalForm?.orgUnitId,
currentPrevalenceSurveyForm?.orgUnitId,
isAdmin,
surveyFormType,
userHospitalsAccess,
]);

useEffect(() => {
setLoadingSurveys(true);

if (
!isAdmin &&
surveyFormType === "PrevalenceFacilityLevelForm" &&
hospitalState === "loading"
) {
console.debug("Ensure hospital context is loaded before fetching surveys.");
return;
}

const parentSurveyId =
surveyFormType === "PrevalenceFacilityLevelForm" ||
surveyFormType === "PrevalenceCaseReportForm" ||
surveyFormType === "PrevalenceCentralRefLabForm" ||
surveyFormType === "PrevalencePathogenIsolatesLog" ||
surveyFormType === "PrevalenceSampleShipTrackForm" ||
surveyFormType === "PrevalenceSupranationalRefLabForm"
!isAdmin &&
(surveyFormType === "PrevalenceFacilityLevelForm" ||
surveyFormType === "PPSHospitalForm") //Non admin users , do not have parent survey form.
? undefined
: surveyFormType === "PrevalenceFacilityLevelForm" ||
surveyFormType === "PrevalenceCaseReportForm" ||
surveyFormType === "PrevalenceCentralRefLabForm" ||
surveyFormType === "PrevalencePathogenIsolatesLog" ||
surveyFormType === "PrevalenceSampleShipTrackForm" ||
surveyFormType === "PrevalenceSupranationalRefLabForm"
? currentPrevalenceSurveyForm?.id
: currentPPSSurveyForm?.id;

Expand Down Expand Up @@ -89,9 +121,11 @@ export function useSurveys(surveyFormType: SURVEY_FORM_TYPES) {
}
);
} else {
const makeChunkedCall: boolean =
surveyFormType === "PrevalenceFacilityLevelForm" && !isAdmin;
//Other forms are not paginated.
compositionRoot.surveys.getSurveys
.execute(surveyFormType, orgUnitId, parentSurveyId)
.execute(surveyFormType, orgUnitId, parentSurveyId, makeChunkedCall)
.run(
surveys => {
setSurveys(surveys);
Expand All @@ -113,6 +147,8 @@ export function useSurveys(surveyFormType: SURVEY_FORM_TYPES) {
shouldRefreshSurveys,
page,
getOrgUnitByFormType,
isAdmin,
hospitalState,
]);

return {
Expand Down
11 changes: 7 additions & 4 deletions src/webapp/pages/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,23 @@ function App(props: AppProps) {
if (!currentUser) throw new Error("User not logged in");

setAppContext({ currentUser, compositionRoot, api });
//set some default value for hospital,astguidelines context until its loaded.
setHospitalContext({ userHospitalsAccess: [] });

//set some default value for hospital context until its loaded.
setHospitalContext({ hospitalState: "loading", userHospitalsAccess: [] });
setShowShareButton(isShareButtonVisible);

compositionRoot.users.getAccessibleOUByLevel
.execute(currentUser.organisationUnits, currentUser.dataViewOrganisationUnits)
.run(
hospitalData => {
setHospitalContext({ userHospitalsAccess: hospitalData });
setHospitalContext({
hospitalState: "loaded",
userHospitalsAccess: hospitalData,
});
console.debug("Hospital data fetched successfully, hospital data set");
},
err => {
console.debug(` No hospital data could be fetched : ${err}`);
setHospitalContext({ hospitalState: "error", userHospitalsAccess: [] });
}
);

Expand Down
58 changes: 17 additions & 41 deletions src/webapp/pages/survey-list/SurveyListPage.tsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,36 @@
import React, { useCallback, useEffect } from "react";
import React, { useEffect } from "react";
import { useHistory, useParams } from "react-router-dom";
import styled from "styled-components";
import { SURVEY_FORM_TYPES } from "../../../domain/entities/Survey";
import { SurveyList } from "../../components/survey-list/SurveyList";
import { useCurrentSurveys } from "../../contexts/current-surveys-context";
import { SurveyListBreadCrumb } from "../../components/survey-list/SurveyListBreadCrumb";
import { useCurrentModule } from "../../contexts/current-module-context";
import { useRedirectHome } from "./useRedirectHome";
import { getUserAccess } from "../../../domain/utils/menuHelper";
import { useAppContext } from "../../contexts/app-context";

export const SurveyListPage: React.FC = React.memo(() => {
const { formType } = useParams<{ formType: SURVEY_FORM_TYPES }>();
const {
currentPPSSurveyForm,
currentPrevalenceSurveyForm,
currentCountryQuestionnaire,
currentHospitalForm,
currentWardRegister,
currentFacilityLevelForm,
currentCaseReportForm,
resetCurrentPPSSurveyForm,
resetCurrentPrevalenceSurveyForm,
} = useCurrentSurveys();
const { resetCurrentPPSSurveyForm, resetCurrentPrevalenceSurveyForm } = useCurrentSurveys();

const { currentModule } = useCurrentModule();
const {
currentUser: { userGroups },
} = useAppContext();
const { shouldRedirectToHome } = useRedirectHome();
const history = useHistory();

const shouldRedirectToHome = useCallback(
(formType: SURVEY_FORM_TYPES): boolean => {
if (
(formType === "PPSCountryQuestionnaire" && !currentPPSSurveyForm) ||
(formType === "PPSHospitalForm" && !currentCountryQuestionnaire) ||
(formType === "PPSWardRegister" && !currentHospitalForm) ||
(formType === "PPSPatientRegister" && !currentWardRegister) ||
(formType === "PrevalenceFacilityLevelForm" && !currentPrevalenceSurveyForm) ||
(formType === "PrevalenceCaseReportForm" && !currentFacilityLevelForm) ||
((formType === "PrevalenceCentralRefLabForm" ||
formType === "PrevalencePathogenIsolatesLog" ||
formType === "PrevalenceSampleShipTrackForm" ||
formType === "PrevalenceSupranationalRefLabForm") &&
!currentCaseReportForm)
)
return true;
else return false;
},
[
currentPPSSurveyForm,
currentPrevalenceSurveyForm,
currentCountryQuestionnaire,
currentHospitalForm,
currentWardRegister,
currentFacilityLevelForm,
currentCaseReportForm,
]
);
const isAdmin = currentModule ? getUserAccess(currentModule, userGroups).hasAdminAccess : false;

//reset all current survey context when root form of either module is listed.
useEffect(() => {
if (formType === "PPSSurveyForm" || formType === "PrevalenceSurveyForm") {
if (
formType === "PPSSurveyForm" ||
formType === "PrevalenceSurveyForm" ||
(!isAdmin &&
(formType === "PrevalenceFacilityLevelForm" || formType === "PPSHospitalForm"))
) {
resetCurrentPPSSurveyForm();
resetCurrentPrevalenceSurveyForm();
} else if (shouldRedirectToHome(formType)) {
Expand All @@ -68,6 +43,7 @@ export const SurveyListPage: React.FC = React.memo(() => {
resetCurrentPPSSurveyForm,
resetCurrentPrevalenceSurveyForm,
shouldRedirectToHome,
isAdmin,
]);

return (
Expand Down
Loading

0 comments on commit 059a187

Please sign in to comment.