Skip to content

Commit

Permalink
Merge feature/incident-action-plan and solve conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
anagperal committed Oct 16, 2024
2 parents 2c8584d + c120b7c commit 3f3cbb5
Show file tree
Hide file tree
Showing 19 changed files with 367 additions and 168 deletions.
13 changes: 5 additions & 8 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: 2024-10-15T12:56:35.980Z\n"
"PO-Revision-Date: 2024-10-15T12:56:35.980Z\n"
"POT-Creation-Date: 2024-10-15T13:56:24.806Z\n"
"PO-Revision-Date: 2024-10-15T13:56:24.806Z\n"

msgid "Low"
msgstr ""
Expand Down Expand Up @@ -198,12 +198,6 @@ msgstr ""
msgid "Incident Response Actions saved successfully"
msgstr ""

msgid "Incident Action Plan"
msgstr ""

msgid "Edit Response Actions"
msgstr ""

msgid "Create an incident action plan"
msgstr ""

Expand All @@ -213,6 +207,9 @@ msgstr ""
msgid "Create IAP"
msgstr ""

msgid "Incident Action Plan"
msgstr ""

msgid "Incident Management Team Builder"
msgstr ""

Expand Down
11 changes: 4 additions & 7 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: 2024-10-15T12:56:35.980Z\n"
"POT-Creation-Date: 2024-10-15T13:56:24.806Z\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 @@ -197,12 +197,6 @@ msgstr ""
msgid "Incident Response Actions saved successfully"
msgstr ""

msgid "Incident Action Plan"
msgstr ""

msgid "Edit Response Actions"
msgstr ""

msgid "Create an incident action plan"
msgstr ""

Expand All @@ -212,6 +206,9 @@ msgstr ""
msgid "Create IAP"
msgstr ""

msgid "Incident Action Plan"
msgstr ""

msgid "Incident Management Team Builder"
msgstr ""

Expand Down
2 changes: 2 additions & 0 deletions src/CompositionRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import { SystemD2Repository } from "./data/repositories/SystemD2Repository";
import { SystemTestRepository } from "./data/repositories/test/SystemTestRepository";
import { GetOverviewCardsUseCase } from "./domain/usecases/GetOverviewCardsUseCase";
import { GetIncidentActionByIdUseCase } from "./domain/usecases/GetIncidentActionByIdUseCase";
import { UpdateIncidentResponseActionUseCase } from "./domain/usecases/UpdateIncidentResponseActionUseCase";

export type CompositionRoot = ReturnType<typeof getCompositionRoot>;

Expand Down Expand Up @@ -107,6 +108,7 @@ function getCompositionRoot(repositories: Repositories) {
},
incidentActionPlan: {
get: new GetIncidentActionByIdUseCase(repositories),
updateResponseAction: new UpdateIncidentResponseActionUseCase(repositories),
},
performanceOverview: {
getPerformanceOverviewMetrics: new GetAllPerformanceOverviewMetricsUseCase(
Expand Down
78 changes: 71 additions & 7 deletions src/data/repositories/IncidentActionD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import {
RTSL_ZEBRA_ORG_UNIT_ID,
RTSL_ZEBRA_PROGRAM_ID,
} from "./consts/DiseaseOutbreakConstants";
import { IncidentActionRepository } from "../../domain/repositories/IncidentActionRepository";
import {
IncidentActionRepository,
UpdateIncidentResponseActionOptions,
} from "../../domain/repositories/IncidentActionRepository";
import {
mapDataElementsToIncidentActionPlan,
mapDataElementsToIncidentResponseActions,
Expand All @@ -18,6 +21,9 @@ import { ActionPlanFormData, ResponseActionFormData } from "../../domain/entitie
import { getProgramStage } from "./utils/MetadataHelper";
import { Future } from "../../domain/entities/generic/Future";
import { Status, Verification } from "../../domain/entities/incident-action-plan/ResponseAction";
import { assertOrError } from "./utils/AssertOrError";
import { D2TrackerEvent } from "@eyeseetea/d2-api/api/trackerEvents";
import { statusCodeMap, verificationCodeMap } from "./consts/IncidentActionConstants";

export const incidentActionPlanIds = {
iapType: "wr1I51WTHhl",
Expand Down Expand Up @@ -129,9 +135,7 @@ export class IncidentActionD2Repository implements IncidentActionRepository {
const incidentDataElements = incidentResponse.objects[0]?.programStageDataElements;

if (!incidentDataElements)
return Future.error(
new Error(` ${formData.type} Program Stage metadata not found`)
);
return Future.error(new Error(`${formData.type} Program Stage metadata not found`));

//Get the enrollment Id for the disease outbreak
return apiToFuture(
Expand Down Expand Up @@ -165,9 +169,7 @@ export class IncidentActionD2Repository implements IncidentActionRepository {
)
).flatMap(saveResponse => {
if (saveResponse.status === "ERROR" || !diseaseOutbreakId) {
return Future.error(
new Error(`Error saving Incident Action Plan Risk Assessment Grading`)
);
return Future.error(new Error(`Error saving Incident Action`));
} else {
return Future.success(undefined);
}
Expand All @@ -176,6 +178,68 @@ export class IncidentActionD2Repository implements IncidentActionRepository {
});
}

updateIncidentResponseAction(options: UpdateIncidentResponseActionOptions): FutureData<void> {
const { diseaseOutbreakId, eventId, responseAction } = options;

return apiToFuture(
this.api.tracker.events.get({
program: RTSL_ZEBRA_PROGRAM_ID,
orgUnit: RTSL_ZEBRA_ORG_UNIT_ID,
trackedEntity: diseaseOutbreakId,
programStage: RTSL_ZEBRA_INCIDENT_RESPONSE_ACTION_PROGRAM_STAGE_ID,
event: eventId,
fields: {
enrollment: true,
dataValues: {
dataElement: true,
value: true,
},
},
})
)
.flatMap(response => assertOrError(response.instances[0], "Event"))
.flatMap(event => {
const enrollmentId = event.enrollment;
if (!enrollmentId) {
return Future.error(new Error(`Enrollment not found for response action`));
}

const valueCodeMaps = { ...statusCodeMap, ...verificationCodeMap };

const eventToPost: D2TrackerEvent = {
event: eventId,
program: RTSL_ZEBRA_PROGRAM_ID,
programStage: RTSL_ZEBRA_INCIDENT_RESPONSE_ACTION_PROGRAM_STAGE_ID,
orgUnit: RTSL_ZEBRA_ORG_UNIT_ID,
enrollment: enrollmentId,
occurredAt: new Date().toISOString(),
trackedEntity: diseaseOutbreakId,
status: "ACTIVE",
dataValues: [
{
dataElement:
incidentResponseActionsIds[
responseAction.type as keyof typeof incidentResponseActionsIds
],
value: valueCodeMaps[
responseAction.value as keyof typeof valueCodeMaps
],
},
],
};

return apiToFuture(
this.api.tracker.post({ importStrategy: "UPDATE" }, { events: [eventToPost] })
).flatMap(saveResponse => {
if (saveResponse.status === "ERROR") {
return Future.error(new Error(`Error saving Incident Response Action`));
} else {
return Future.success(undefined);
}
});
});
}

private getProgramStageByFormType(formType: string) {
switch (formType) {
case "incident-action-plan":
Expand Down
4 changes: 2 additions & 2 deletions src/data/repositories/consts/IncidentActionConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export function isStringInIncidentResponseActionCodes(
return (Object.values(responseActionConstants) as string[]).includes(code);
}

const statusCodeMap: Record<ResponseActionStatusType, string> = {
export const statusCodeMap: Record<ResponseActionStatusType, string> = {
"Not done": "RTSL_ZEB_OS_STATUS_NOT_DONE",
Pending: "RTSL_ZEB_OS_STATUS_PENDING",
"In Progress": "RTSL_ZEB_OS_STATUS_IN_PROGRESS",
Expand All @@ -89,7 +89,7 @@ export function getStatusTypeByCode(iapTypeCode: string): Maybe<ResponseActionSt
);
}

const verificationCodeMap: Record<ResponseActionVerificationType, string> = {
export const verificationCodeMap: Record<ResponseActionVerificationType, string> = {
Verified: "RTSL_ZEB_OS_VERIFICATION_VERIFIED",
Unverified: "RTSL_ZEB_OS_VERIFICATION_UNVERIFIED",
};
Expand Down
9 changes: 8 additions & 1 deletion src/data/repositories/test/IncidentActionTestRepository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Id } from "../../../domain/entities/Ref";
import { IncidentActionRepository } from "../../../domain/repositories/IncidentActionRepository";
import {
IncidentActionRepository,
UpdateIncidentResponseActionOptions,
} from "../../../domain/repositories/IncidentActionRepository";
import { Maybe } from "../../../utils/ts-utils";
import { FutureData } from "../../api-futures";
import {
Expand All @@ -21,4 +24,8 @@ export class IncidentActionTestRepository implements IncidentActionRepository {
saveIncidentAction(_formData: any, _diseaseOutbreakId: Id): FutureData<void> {
throw new Error("Method not implemented.");
}

updateIncidentResponseAction(_options: UpdateIncidentResponseActionOptions): FutureData<void> {
throw new Error("Method not implemented.");
}
}
2 changes: 1 addition & 1 deletion src/data/repositories/utils/IncidentActionMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ function mapIncidentActionPlanToDataElements(
);
}

function mapIncidentResponseActionToDataElements(
export function mapIncidentResponseActionToDataElements(
programStageId: Id,
teiId: Id,
enrollmentId: Id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { ActionPlan } from "./ActionPlan";
import { Ref } from "../Ref";
import { Option, Ref } from "../Ref";
import { Struct } from "../generic/Struct";
import { ResponseAction } from "./ResponseAction";
import { Maybe } from "../../../utils/ts-utils";

export type IncidentActionOptions = {
status: Option[];
verification: Option[];
};

interface IncidentActionPlanAttrs extends Ref {
lastUpdated: Date;
actionPlan: Maybe<ActionPlan>;
responseActions: ResponseAction[];
incidentActionOptions: IncidentActionOptions;
}

export class IncidentActionPlan extends Struct<IncidentActionPlanAttrs>() {}
10 changes: 10 additions & 0 deletions src/domain/repositories/IncidentActionRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,14 @@ export interface IncidentActionRepository {
formData: ActionPlanFormData | ResponseActionFormData,
diseaseOutbreakId: Id
): FutureData<void>;
updateIncidentResponseAction(options: UpdateIncidentResponseActionOptions): FutureData<void>;
}

export type UpdateIncidentResponseActionOptions = {
diseaseOutbreakId: Id;
eventId: Id;
responseAction: {
value: string;
type: string;
};
};
13 changes: 13 additions & 0 deletions src/domain/usecases/UpdateIncidentResponseActionUseCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FutureData } from "../../data/api-futures";
import {
IncidentActionRepository,
UpdateIncidentResponseActionOptions,
} from "../repositories/IncidentActionRepository";

export class UpdateIncidentResponseActionUseCase {
constructor(private options: { incidentActionRepository: IncidentActionRepository }) {}

public execute(options: UpdateIncidentResponseActionOptions): FutureData<void> {
return this.options.incidentActionRepository.updateIncidentResponseAction(options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export function getIncidentAction(
lastUpdated: new Date(),
actionPlan: actionPlan,
responseActions: responseActions,
incidentActionOptions: {
status: statusOptions,
verification: verificationOptions,
},
});

return Future.success(incidentAction);
Expand Down
6 changes: 5 additions & 1 deletion src/webapp/components/form/FormSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ export const FormSection: React.FC<FormSectionProps> = React.memo(
)}

{addNewField && handleAddNew && (
<AddNewOption id="" onAddNewOption={handleAddNew} />
<AddNewOption
id=""
label={addNewField.label}
onAddNewOption={handleAddNew}
/>
)}

{fields.length && fields.some(f => f.isVisible) ? (
Expand Down
Loading

0 comments on commit 3f3cbb5

Please sign in to comment.