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

Add pagination to surveys lists #12

Merged
merged 6 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
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
32 changes: 27 additions & 5 deletions src/data/repositories/SurveyFormD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
} from "../../domain/entities/EventProgram";
import { Survey, SURVEY_FORM_TYPES, SURVEY_STATUSES } from "../../domain/entities/Survey";
import { DataValue } from "@eyeseetea/d2-api";
import { PaginatedReponse } from "../../domain/entities/TablePagination";

//PPS Program Ids
export const PPS_SURVEY_FORM_ID = "OGOw5Kt3ytv";
Expand Down Expand Up @@ -401,8 +402,11 @@ export class SurveyD2Repository implements SurveyRepository {
getSurveys(
surveyFormType: SURVEY_FORM_TYPES,
programId: Id,
orgUnitId: Id
): FutureData<Survey[]> {
orgUnitId: Id,
parentWardRegisterId: Id | undefined,
page: number,
pageSize: number
): FutureData<PaginatedReponse<Survey[]>> {
const ouMode =
orgUnitId !== "" &&
(programId === PPS_WARD_REGISTER_ID ||
Expand All @@ -416,9 +420,18 @@ export class SurveyD2Repository implements SurveyRepository {
program: programId,
orgUnit: orgUnitId,
ouMode: ouMode,
// Testing the API filter for now to see how the filtering performs
...(surveyFormType === "PPSPatientRegister" && {
page: page + 1,
pageSize,
totalPages: true,
filter: `${WARD_ID_DATAELEMENT_ID}:eq:${parentWardRegisterId}`,
}),
})
).flatMap(events => {
const surveys = events.instances.map(event => {
).flatMap(response => {
const events = response.instances;

const surveys = events.map(event => {
let startDateString,
surveyType = "",
surveyCompleted,
Expand Down Expand Up @@ -494,7 +507,16 @@ export class SurveyD2Repository implements SurveyRepository {
});
});

return Future.sequential(surveys);
return Future.sequential(surveys).map(surveys => {
return {
pager: {
page: response.page,
pageSize: response.pageSize,
total: response.total,
},
objects: surveys,
};
});
});
}

Expand Down
60 changes: 38 additions & 22 deletions src/data/repositories/testRepositories/SurveyFormTestRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Survey } from "../../../domain/entities/Survey";
import { SurveyRepository } from "../../../domain/repositories/SurveyRepository";
import { FutureData } from "../../api-futures";
import { PPS_SURVEY_FORM_ID } from "../SurveyFormD2Repository";
import { PaginatedReponse } from "../../../domain/entities/TablePagination";

export class SurveyTestRepository implements SurveyRepository {
getSurveyNameFromId(id: string): FutureData<string | undefined> {
Expand Down Expand Up @@ -50,31 +51,46 @@ export class SurveyTestRepository implements SurveyRepository {
else return Future.error(new Error("An error occured while saving the survey"));
}

getSurveys(programId: string, orgUnitId: string): FutureData<Survey[]> {
getSurveys(programId: string, orgUnitId: string): FutureData<PaginatedReponse<Survey[]>> {
if (programId === PPS_SURVEY_FORM_ID)
return Future.success([
{
name: "TestSurvey1",
id: "1",
startDate: new Date(),
status: "ACTIVE",
assignedOrgUnit: { id: orgUnitId, name: "OU1" },
surveyType: "SUPRANATIONAL",
rootSurvey: { id: "1", name: "TestSurvey1", surveyType: "" },
surveyFormType: "PPSSurveyForm",
return Future.success({
pager: {
page: 0,
pageSize: 2,
total: 2,
},
{
name: "TestSurvey2",
id: "2",
startDate: new Date(),
status: "COMPLETED",
assignedOrgUnit: { id: "OU1234", name: "OU2" },
surveyType: "NATIONAL",
rootSurvey: { id: "2", name: "TestSurvey1", surveyType: "" },
surveyFormType: "PPSSurveyForm",
objects: [
{
name: "TestSurvey1",
id: "1",
startDate: new Date(),
status: "ACTIVE",
assignedOrgUnit: { id: orgUnitId, name: "OU1" },
surveyType: "SUPRANATIONAL",
rootSurvey: { id: "1", name: "TestSurvey1", surveyType: "" },
surveyFormType: "PPSSurveyForm",
},
{
name: "TestSurvey2",
id: "2",
startDate: new Date(),
status: "COMPLETED",
assignedOrgUnit: { id: "OU1234", name: "OU2" },
surveyType: "NATIONAL",
rootSurvey: { id: "2", name: "TestSurvey1", surveyType: "" },
surveyFormType: "PPSSurveyForm",
},
],
});
else
return Future.success({
pager: {
page: 0,
pageSize: 0,
total: 0,
},
]);
else return Future.success([]);
objects: [],
});
}
getSurveyById(eventId: string): FutureData<D2TrackerEvent> {
if (eventId) {
Expand Down
11 changes: 11 additions & 0 deletions src/domain/entities/TablePagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface PaginatedReponse<T> {
pager: Pager;
objects: T;
}

export interface Pager {
page: number;
total?: number;
pageSize: number;
pageCount?: number;
}
8 changes: 6 additions & 2 deletions src/domain/repositories/SurveyRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ImportStrategy } from "../entities/EventProgram";
import { Questionnaire } from "../entities/Questionnaire";
import { Id } from "../entities/Ref";
import { Survey, SURVEY_FORM_TYPES } from "../entities/Survey";
import { PaginatedReponse } from "../entities/TablePagination";

export interface SurveyRepository {
getForm(programId: Id, eventId: Id | undefined): FutureData<Questionnaire>;
Expand All @@ -16,8 +17,11 @@ export interface SurveyRepository {
getSurveys(
surveyFormType: SURVEY_FORM_TYPES,
programId: Id,
orgUnitId: Id
): FutureData<Survey[]>;
orgUnitId: Id,
parentWardRegisterId: Id | undefined,
page: number,
pageSize: number
): FutureData<PaginatedReponse<Survey[]>>;
getPopulatedSurveyById(eventId: Id, programId: Id): FutureData<Questionnaire>;
getSurveyNameFromId(id: Id): FutureData<string | undefined>;
}
54 changes: 25 additions & 29 deletions src/domain/usecases/GetAllSurveysUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SurveyRepository } from "../repositories/SurveyRepository";
import { getProgramId } from "../utils/PPSProgramsHelper";
import { GLOBAL_OU_ID } from "./SaveFormDataUseCase";
import _ from "../entities/generic/Collection";
import { PaginatedReponse } from "../entities/TablePagination";

export class GetAllSurveysUseCase {
constructor(private surveyReporsitory: SurveyRepository) {}
Expand All @@ -14,46 +15,41 @@ export class GetAllSurveysUseCase {
surveyFormType: SURVEY_FORM_TYPES,
orgUnitId: Id,
parentPPSSurveyId: Id | undefined,
parentWardRegisterId: Id | undefined
): FutureData<Survey[]> {
parentWardRegisterId: Id | undefined,
page: number,
pageSize: number
): FutureData<PaginatedReponse<Survey[]>> {
const programId = getProgramId(surveyFormType);

//All PPS Survey Forms are Global.
if (surveyFormType === "PPSSurveyForm") orgUnitId = GLOBAL_OU_ID;

return this.surveyReporsitory
.getSurveys(surveyFormType, programId, orgUnitId)
.flatMap(surveys => {
.getSurveys(surveyFormType, programId, orgUnitId, parentWardRegisterId, page, pageSize)
.flatMap(({ pager, objects: surveys }) => {
if (
surveyFormType === "PPSSurveyForm" ||
(surveyFormType === "PPSHospitalForm" && !parentPPSSurveyId)
(surveyFormType === "PPSHospitalForm" && !parentPPSSurveyId) ||
surveyFormType === "PPSPatientRegister"
) {
return Future.success(surveys);
return Future.success({
pager: pager,
objects: surveys,
});
} else {
if (surveyFormType === "PPSPatientRegister") {
//Filter Surveys by parentWardRegisterId
const filteredSurveys = _(
surveys.map(survey => {
if (survey.parentWardRegisterId === parentWardRegisterId)
return survey;
})
)
.compact()
.value();
//Filter Surveys by parentPPSSurveyId
const filteredSurveys = _(
surveys.map(survey => {
if (survey.rootSurvey.id === parentPPSSurveyId) return survey;
})
)
.compact()
.value();

return Future.success(filteredSurveys);
} else {
//Filter Surveys by parentPPSSurveyId
const filteredSurveys = _(
surveys.map(survey => {
if (survey.rootSurvey.id === parentPPSSurveyId) return survey;
})
)
.compact()
.value();

return Future.success(filteredSurveys);
}
return Future.success({
pager: pager,
objects: filteredSurveys,
});
}
});
}
Expand Down
8 changes: 7 additions & 1 deletion src/webapp/components/survey-list/SurveyList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export const SurveyList: React.FC<SurveyListProps> = ({ surveyFormType }) => {
if (currentModule)
isAdmin = getUserAccess(currentModule, currentUser.userGroups).hasAdminAccess;

const { surveys, loading, error } = useSurveys(surveyFormType);
const { surveys, loading, error, page, setPage, pageSize, setPageSize, total } =
useSurveys(surveyFormType);

const {
statusFilter,
Expand Down Expand Up @@ -102,6 +103,11 @@ export const SurveyList: React.FC<SurveyListProps> = ({ surveyFormType }) => {
surveys={filteredSurveys}
surveyFormType={surveyFormType}
updateSelectedSurveyDetails={updateSelectedSurveyDetails}
page={page}
setPage={setPage}
pageSize={pageSize}
setPageSize={setPageSize}
total={total}
/>
</CustomCard>
</ContentLoader>
Expand Down
35 changes: 34 additions & 1 deletion src/webapp/components/survey-list/SurveyListTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import {
TableCell,
TableHead,
Typography,
TablePagination,
} from "@material-ui/core";
import i18n from "@eyeseetea/feedback-component/locales";
import { ActionMenuButton } from "../action-menu-button/ActionMenuButton";
import { palette } from "../../pages/app/themes/dhis2.theme";
import { Id } from "../../../domain/entities/Ref";
import { getChildSurveyType, getSurveyOptions } from "../../../domain/utils/PPSProgramsHelper";
import { useHistory } from "react-router-dom";
import { useEffect, useState } from "react";
import { ChangeEvent, Dispatch, MouseEvent, SetStateAction, useEffect, useState } from "react";
import { ArrowDownward, ArrowUpward } from "@material-ui/icons";
import _ from "../../../domain/entities/generic/Collection";

Expand All @@ -28,6 +29,11 @@ interface SurveyListTableProps {
orgUnitId: Id,
rootSurvey: SurveyBase
) => void;
page: number;
setPage: Dispatch<SetStateAction<number>>;
pageSize: number;
setPageSize: Dispatch<SetStateAction<number>>;
total?: number;
}

export type SortDirection = "asc" | "desc";
Expand All @@ -36,6 +42,11 @@ export const SurveyListTable: React.FC<SurveyListTableProps> = ({
surveys,
surveyFormType,
updateSelectedSurveyDetails,
page,
setPage,
pageSize,
setPageSize,
total,
}) => {
const [options, setOptions] = useState<string[]>([]);
const [sortedSurveys, setSortedSurveys] = useState<Survey[]>();
Expand Down Expand Up @@ -112,6 +123,17 @@ export const SurveyListTable: React.FC<SurveyListTableProps> = ({
});
};

const handleChangePage = (_event: MouseEvent | null, newPage: SetStateAction<number>) => {
setPage(newPage);
};

const handleChangeRowsPerPage = (
event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
setPageSize(parseInt(event.target.value, 10));
setPage(0);
};

return (
<>
{sortedSurveys && (
Expand Down Expand Up @@ -502,6 +524,17 @@ export const SurveyListTable: React.FC<SurveyListTableProps> = ({
)}
</Table>
</TableContainer>
{surveyFormType === "PPSPatientRegister" && (
<TablePagination
rowsPerPageOptions={[5, 10, 15, 20]}
component="div"
count={total || 0}
rowsPerPage={pageSize}
page={page}
onPageChange={(event, page) => handleChangePage(event, page)}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
)}
</TableContentWrapper>
)}
</>
Expand Down
19 changes: 16 additions & 3 deletions src/webapp/hooks/useSurveys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ export function useSurveys(surveyFormType: SURVEY_FORM_TYPES) {
const [surveys, setSurveys] = useState<Survey[]>();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string>();
const [page, setPage] = useState<number>(0);
const [pageSize, setPageSize] = useState<number>(5);
const [total, setTotal] = useState<number>();
const {
currentPPSSurveyForm,
currentCountryQuestionnaire,
Expand All @@ -24,10 +27,18 @@ export function useSurveys(surveyFormType: SURVEY_FORM_TYPES) {
orgUnitId = currentHospitalForm?.orgUnitId ?? "";

compositionRoot.surveys.getSurveys
.execute(surveyFormType, orgUnitId, currentPPSSurveyForm?.id, currentWardRegister?.id)
.execute(
surveyFormType,
orgUnitId,
currentPPSSurveyForm?.id,
currentWardRegister?.id,
page,
pageSize
)
.run(
surveys => {
({ pager: { total }, objects: surveys }) => {
setSurveys(surveys);
setTotal(total);
setLoading(false);
},
err => {
Expand All @@ -42,7 +53,9 @@ export function useSurveys(surveyFormType: SURVEY_FORM_TYPES) {
currentCountryQuestionnaire?.orgUnitId,
currentHospitalForm?.orgUnitId,
currentWardRegister,
page,
pageSize,
]);

return { surveys, loading, error };
return { surveys, loading, error, page, setPage, pageSize, setPageSize, total };
}
Loading