Skip to content

Commit

Permalink
Merge pull request #10 from EyeSeeTea/feat/add-delete-functionality
Browse files Browse the repository at this point in the history
Feat/add delete functionality
  • Loading branch information
MiquelAdell authored Dec 20, 2023
2 parents 0eccaa6 + 48e4f43 commit 3a43f89
Show file tree
Hide file tree
Showing 17 changed files with 183 additions and 32 deletions.
12 changes: 9 additions & 3 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ 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: 2023-11-28T10:56:14.436Z\n"
"PO-Revision-Date: 2023-11-28T10:56:14.436Z\n"
"POT-Creation-Date: 2023-12-12T09:57:09.880Z\n"
"PO-Revision-Date: 2023-12-12T09:57:09.881Z\n"

msgid "WHO privacy policy"
msgstr ""
Expand Down Expand Up @@ -61,7 +61,7 @@ msgstr ""
msgid "FUTURE"
msgstr ""

msgid "NONE"
msgid "ALL"
msgstr ""

msgid "SUPRANATIONAL"
Expand Down Expand Up @@ -100,6 +100,12 @@ msgstr ""
msgid "Action"
msgstr ""

msgid "Survey deleted!"
msgstr ""

msgid "Error deleting the survery"
msgstr ""

msgid "Yes"
msgstr ""

Expand Down
10 changes: 8 additions & 2 deletions i18n/es.po
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: i18next-conv\n"
"POT-Creation-Date: 2023-11-28T10:56:14.436Z\n"
"POT-Creation-Date: 2023-12-12T09:57:09.880Z\n"
"PO-Revision-Date: 2018-10-25T09:02:35.143Z\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -61,7 +61,7 @@ msgstr ""
msgid "FUTURE"
msgstr ""

msgid "NONE"
msgid "ALL"
msgstr ""

msgid "SUPRANATIONAL"
Expand Down Expand Up @@ -100,6 +100,12 @@ msgstr ""
msgid "Action"
msgstr ""

msgid "Survey deleted!"
msgstr ""

msgid "Error deleting the survery"
msgstr ""

msgid "Yes"
msgstr ""

Expand Down
2 changes: 2 additions & 0 deletions src/CompositionRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { SaveFormDataUseCase } from "./domain/usecases/SaveFormDataUseCase";
import { GetAllSurveysUseCase } from "./domain/usecases/GetAllSurveysUseCase";
import { GetPopulatedSurveyUseCase } from "./domain/usecases/GetPopulatedSurveyUseCase";
import { NonAdminUserTestRepository } from "./data/repositories/testRepositories/NonAdminUserTestRepository";
import { DeleteSurveyUseCase } from "./domain/usecases/DeleteSurveyUseCase";

export type CompositionRoot = ReturnType<typeof getCompositionRoot>;

Expand Down Expand Up @@ -54,6 +55,7 @@ function getCompositionRoot(repositories: Repositories) {
getPopulatedForm: new GetPopulatedSurveyUseCase(repositories.surveyFormRepository),
saveFormData: new SaveFormDataUseCase(repositories.surveyFormRepository),
getSurveys: new GetAllSurveysUseCase(repositories.surveyFormRepository),
deleteSurvey: new DeleteSurveyUseCase(repositories.surveyFormRepository),
},
};
}
Expand Down
30 changes: 30 additions & 0 deletions src/data/repositories/SurveyFormD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,4 +526,34 @@ export class SurveyD2Repository implements SurveyRepository {
});
else return Future.success("");
}

deleteSurvey(eventId: Id, orgUnitId: Id, programId: Id): FutureData<void> {
const event: D2TrackerEvent = {
event: eventId,
orgUnit: orgUnitId,
program: programId,
// status doesn't play a part in deleting but is required
status: "ACTIVE",
occurredAt: "",
dataValues: [],
};
return apiToFuture(
this.api.tracker.postAsync({ importStrategy: "DELETE" }, { events: [event] })
).flatMap(response => {
return apiToFuture(
// eslint-disable-next-line testing-library/await-async-utils
this.api.system.waitFor("TRACKER_IMPORT_JOB", response.response.id)
).flatMap(result => {
if (result && result.status !== "ERROR") {
return Future.success(undefined);
} else {
return Future.error(
new Error(
`Error: ${result?.validationReport?.errorReports?.at(0)?.message} `
)
);
}
});
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,9 @@ export class SurveyTestRepository implements SurveyRepository {
return Future.error(new Error("Error in getSurveyById"));
}
}

deleteSurvey(orgUnitId: Id, eventId: Id, programId: Id): FutureData<void> {
if (orgUnitId && eventId && programId) return Future.success(undefined);
else return Future.error(new Error("An error occured while deleting the survey"));
}
}
4 changes: 4 additions & 0 deletions src/domain/entities/generic/ActionOutcome.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface ActionOutcome {
status: "success" | "error";
message: string;
}
1 change: 1 addition & 0 deletions src/domain/repositories/SurveyRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ export interface SurveyRepository {
): FutureData<Survey[]>;
getPopulatedSurveyById(eventId: Id, programId: Id): FutureData<Questionnaire>;
getSurveyNameFromId(id: Id): FutureData<string | undefined>;
deleteSurvey(eventId: Id, orgUnitId: Id, programId: Id): FutureData<void>;
}
19 changes: 19 additions & 0 deletions src/domain/usecases/DeleteSurveyUseCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { FutureData } from "../../data/api-futures";
import { SURVEY_FORM_TYPES } from "../entities/Survey";
import { Id } from "../entities/Ref";

import { SurveyRepository } from "../repositories/SurveyRepository";
import { getProgramId } from "../utils/PPSProgramsHelper";

export class DeleteSurveyUseCase {
constructor(private surveyReporsitory: SurveyRepository) {}

public execute(
surveyFormType: SURVEY_FORM_TYPES,
orgUnitId: Id,
eventId: Id
): FutureData<void> {
const programId = getProgramId(surveyFormType);
return this.surveyReporsitory.deleteSurvey(eventId, orgUnitId, programId);
}
}
14 changes: 7 additions & 7 deletions src/domain/utils/PPSProgramsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,23 +60,23 @@ export const getSurveyOptions = (
case "PPSSurveyForm": {
switch (ppsSurveyType) {
case "NATIONAL":
return ["Edit", "Add new Country", "List Country"];
return ["Edit", "Add new Country", "List Country", "Delete"];
case "HOSP":
return ["Edit", "Add new Hospital", "List Hospitals"];
return ["Edit", "Add new Hospital", "List Hospitals", "Delete"];
case "SUPRANATIONAL":
default:
return ["Edit", "Add new Country", "List Countries"];
return ["Edit", "Add new Country", "List Countries", "Delete"];
}
}
case "PPSCountryQuestionnaire":
return ["Edit", "Add new Hospital", "List Hospitals"];
return ["Edit", "Add new Hospital", "List Hospitals", "Delete"];
case "PPSHospitalForm":
return ["Edit", "Add new Ward", "List Wards"];
return ["Edit", "Add new Ward", "List Wards", "Delete"];
case "PPSWardRegister":
return ["Edit", "Add new Patient", "List Patients"];
return ["Edit", "Add new Patient", "List Patients", "Delete"];
case "PPSPatientRegister":
default:
return ["Edit"];
return ["Edit", "Delete"];
}
};

Expand Down
3 changes: 2 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,7 @@ 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, setRefreshSurveys } = useSurveys(surveyFormType);

const {
statusFilter,
Expand Down Expand Up @@ -102,6 +102,7 @@ export const SurveyList: React.FC<SurveyListProps> = ({ surveyFormType }) => {
surveys={filteredSurveys}
surveyFormType={surveyFormType}
updateSelectedSurveyDetails={updateSelectedSurveyDetails}
refreshSurveys={setRefreshSurveys}
/>
</CustomCard>
</ContentLoader>
Expand Down
12 changes: 6 additions & 6 deletions src/webapp/components/survey-list/SurveyListFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const SurveyListFilters: React.FC<SurveyListFilterProps> = ({
labelId="status-label"
value={status}
onChange={e => {
if (e.target.value === "NONE") setStatus(undefined);
if (e.target.value === "ALL") setStatus(undefined);
else setStatus(e.target.value as SURVEY_STATUSES);
}}
label="STATUS"
Expand All @@ -38,8 +38,8 @@ export const SurveyListFilters: React.FC<SurveyListFilterProps> = ({
<MenuItem key="FUTURE" value="FUTURE">
{i18n.t("FUTURE")}
</MenuItem>
<MenuItem key="NONE-Status" value="NONE">
{i18n.t("NONE")}
<MenuItem key="ALL-Status" value="ALL">
{i18n.t("ALL")}
</MenuItem>
</Select>
</FormControl>
Expand All @@ -49,7 +49,7 @@ export const SurveyListFilters: React.FC<SurveyListFilterProps> = ({
<Select
value={surveyType}
onChange={e => {
if (e.target.value === "NONE") setSurveyType(undefined);
if (e.target.value === "ALL") setSurveyType(undefined);
else setSurveyType(e.target.value as SURVEY_TYPES);
}}
>
Expand All @@ -62,8 +62,8 @@ export const SurveyListFilters: React.FC<SurveyListFilterProps> = ({
<MenuItem key="HOSP" value="HOSP">
{i18n.t("HOSP")}
</MenuItem>
<MenuItem key="NONE-SurveyType" value="NONE">
{i18n.t("NONE")}
<MenuItem key="ALL-SurveyType" value="ALL">
{i18n.t("ALL")}
</MenuItem>
</Select>
</FormControl>
Expand Down
40 changes: 37 additions & 3 deletions src/webapp/components/survey-list/SurveyListTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Survey, SurveyBase, SURVEY_FORM_TYPES } from "../../../domain/entities/Survey";
import { useSnackbar } from "@eyeseetea/d2-ui-components";
import styled from "styled-components";
import {
TableBody,
Expand All @@ -16,13 +17,16 @@ 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 { Dispatch, 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";

interface SurveyListTableProps {
surveys: Survey[] | undefined;
surveyFormType: SURVEY_FORM_TYPES;
refreshSurveys: Dispatch<SetStateAction<{}>>;
updateSelectedSurveyDetails: (
survey: SurveyBase,
orgUnitId: Id,
Expand All @@ -36,6 +40,7 @@ export const SurveyListTable: React.FC<SurveyListTableProps> = ({
surveys,
surveyFormType,
updateSelectedSurveyDetails,
refreshSurveys,
}) => {
const [options, setOptions] = useState<string[]>([]);
const [sortedSurveys, setSortedSurveys] = useState<Survey[]>();
Expand Down Expand Up @@ -63,6 +68,27 @@ export const SurveyListTable: React.FC<SurveyListTableProps> = ({
});
};

const { deleteSurvey, loading, setLoading, error, deleteCompleteState } = useDeleteSurvey(
surveyFormType,
refreshSurveys
);

const deleteSelectedSurvey = (surveyId: Id, orgUnitId: Id) => {
setLoading(true);
deleteSurvey(surveyId, orgUnitId);
};

const snackbar = useSnackbar();

useEffect(() => {
if (deleteCompleteState?.status === "success") {
snackbar.success(deleteCompleteState.message);
}
if (deleteCompleteState?.status === "error") {
snackbar.error(deleteCompleteState.message);
}
}, [deleteCompleteState, snackbar]);

const assignChild = (
survey: SurveyBase,
orgUnitId: Id,
Expand Down Expand Up @@ -113,7 +139,7 @@ export const SurveyListTable: React.FC<SurveyListTableProps> = ({
};

return (
<>
<ContentLoader loading={loading} error={error} showErrorAsSnackbar={true}>
{sortedSurveys && (
<TableContentWrapper>
<TableContainer component={Paper}>
Expand Down Expand Up @@ -349,6 +375,14 @@ export const SurveyListTable: React.FC<SurveyListTableProps> = ({
survey.rootSurvey
),
},
{
option: "Delete",
handler: () =>
deleteSelectedSurvey(
survey.id,
survey.assignedOrgUnit.id
),
},
{
option: "Add new Country",
handler: () =>
Expand Down Expand Up @@ -504,7 +538,7 @@ export const SurveyListTable: React.FC<SurveyListTableProps> = ({
</TableContainer>
</TableContentWrapper>
)}
</>
</ContentLoader>
);
};

Expand Down
44 changes: 44 additions & 0 deletions src/webapp/components/survey-list/hook/useDeleteSurvey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Dispatch, SetStateAction, useState } from "react";
import { SURVEY_FORM_TYPES } from "../../../../domain/entities/Survey";
import { useCurrentSurveys } from "../../../contexts/current-surveys-context";

import { useAppContext } from "../../../contexts/app-context";
import i18n from "@eyeseetea/feedback-component/locales";
import { Id } from "../../../../domain/entities/Ref";
import { ActionOutcome } from "../../../../domain/entities/generic/ActionOutcome";

export function useDeleteSurvey(
formType: SURVEY_FORM_TYPES,
refreshSurveys: Dispatch<SetStateAction<{}>>
) {
const { compositionRoot } = useAppContext();
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string>();
const [deleteCompleteState, setDeleteCompleteState] = useState<ActionOutcome>();
const { currentHospitalForm } = useCurrentSurveys();

const deleteSurvey = (surveyId: Id, orgUnitId: Id) => {
if (formType === "PPSWardRegister" || formType === "PPSPatientRegister")
orgUnitId = currentHospitalForm?.orgUnitId ?? "";
compositionRoot.surveys.deleteSurvey.execute(formType, orgUnitId, surveyId).run(
() => {
setDeleteCompleteState({
status: "success",
message: i18n.t("Survey deleted!"),
});
refreshSurveys({});
setLoading(false);
},
err => {
setDeleteCompleteState({
status: "error",
message: err ? err.message : i18n.t("Error deleting the survery"),
});
setError(err.message);
setLoading(false);
}
);
};

return { deleteCompleteState, deleteSurvey, loading, setLoading, error };
}
7 changes: 2 additions & 5 deletions src/webapp/components/survey/hook/useSaveSurvey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ import { Id } from "../../../../domain/entities/Ref";
import { useState } from "react";
import i18n from "@eyeseetea/feedback-component/locales";
import { useCurrentSurveys } from "../../../contexts/current-surveys-context";
import { ActionOutcome } from "../../../../domain/entities/generic/ActionOutcome";

export interface SaveState {
status: "success" | "error";
message: string;
}
export function useSaveSurvey(formType: SURVEY_FORM_TYPES, orgUnitId: Id, surveyId?: Id) {
const { compositionRoot } = useAppContext();
const [saveCompleteState, setSaveCompleteState] = useState<SaveState>();
const [saveCompleteState, setSaveCompleteState] = useState<ActionOutcome>();
const { currentHospitalForm } = useCurrentSurveys();

const saveSurvey = (questionnaire: Questionnaire) => {
Expand Down
Loading

0 comments on commit 3a43f89

Please sign in to comment.