From 2f7013f5cfc30ca302093ece961980e063db3634 Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Wed, 12 Jun 2024 22:13:23 +0530 Subject: [PATCH 1/8] feat: Domain entities for zebra --- index.html | 13 +- package.json | 10 +- src/domain/entities/DiseaseOutbreak.ts | 56 +++++++++ src/domain/entities/OrgUnit.ts | 7 ++ src/domain/entities/Properties.ts | 32 +++++ src/domain/entities/Ref.ts | 6 + .../incident-action-plan/ActionPlan.ts | 8 ++ .../IncidentActionPlan.ts | 12 ++ .../incident-action-plan/ResponseAction.ts | 20 +++ .../IncidentManagementTeam.ts | 17 +++ .../incident-management-team/TeamMember.ts | 21 ++++ .../risk-assessment/RiskAssessment.ts | 12 ++ .../risk-assessment/RiskAssessmentGrading.ts | 118 ++++++++++++++++++ .../RiskAssessmentQuestionnaire.ts | 8 ++ .../risk-assessment/RiskAssessmentSummary.ts | 8 ++ .../__tests__/RiskAssessmentGrading.spec.ts | 94 ++++++++++++++ src/webapp/pages/app/__tests__/App.spec.tsx | 31 ----- 17 files changed, 434 insertions(+), 39 deletions(-) create mode 100644 src/domain/entities/DiseaseOutbreak.ts create mode 100644 src/domain/entities/OrgUnit.ts create mode 100644 src/domain/entities/Properties.ts create mode 100644 src/domain/entities/incident-action-plan/ActionPlan.ts create mode 100644 src/domain/entities/incident-action-plan/IncidentActionPlan.ts create mode 100644 src/domain/entities/incident-action-plan/ResponseAction.ts create mode 100644 src/domain/entities/incident-management-team/IncidentManagementTeam.ts create mode 100644 src/domain/entities/incident-management-team/TeamMember.ts create mode 100644 src/domain/entities/risk-assessment/RiskAssessment.ts create mode 100644 src/domain/entities/risk-assessment/RiskAssessmentGrading.ts create mode 100644 src/domain/entities/risk-assessment/RiskAssessmentQuestionnaire.ts create mode 100644 src/domain/entities/risk-assessment/RiskAssessmentSummary.ts create mode 100644 src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts delete mode 100644 src/webapp/pages/app/__tests__/App.spec.tsx diff --git a/index.html b/index.html index 492d83db..1e5a8d80 100644 --- a/index.html +++ b/index.html @@ -4,15 +4,22 @@ - + - + - Vite + React + TS + Zebra diff --git a/package.json b/package.json index 321eefa8..d5f49e60 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { - "name": "dhis2-app-skeleton", - "description": "DHIS2 Skeleton App", + "name": "zebra", + "description": "Zambia Emergency Bridge for Response Application", "version": "0.0.1", "license": "GPL-3.0", "author": "EyeSeeTea team", "homepage": ".", "repository": { "type": "git", - "url": "git+https://github.com/eyeseetea/dhis2-app-skeleton.git" + "url": "git+https://github.com/eyeseetea/zebra-dev.git" }, "dependencies": { "@dhis2/app-runtime": "2.8.0", @@ -108,8 +108,8 @@ "script-example": "npx ts-node src/scripts/example.ts" }, "manifest.webapp": { - "name": "DHIS2 Skeleton App", - "description": "DHIS2 Skeleton App", + "name": "zebra", + "description": "Zambia Emergency Bridge for Response Application", "icons": { "48": "icon.png" }, diff --git a/src/domain/entities/DiseaseOutbreak.ts b/src/domain/entities/DiseaseOutbreak.ts new file mode 100644 index 00000000..5e67512c --- /dev/null +++ b/src/domain/entities/DiseaseOutbreak.ts @@ -0,0 +1,56 @@ +//Note: DiseaseOutbreak represents Event in the Figma. +//Not using event as it is a keyword and can also be confused with dhis event +import { Struct } from "./generic/Struct"; +import { IncidentActionPlan } from "./incident-action-plan/IncidentActionPlan"; +import { IncidentManagementTeam } from "./incident-management-team/IncidentManagementTeam"; +import { TeamMember } from "./incident-management-team/TeamMember"; +import { OrgUnit } from "./OrgUnit"; +import { NamedRef, Option } from "./Ref"; +import { RiskAssessment } from "./risk-assessment/RiskAssessment"; + +type HazardType = + | "Biological:Human" + | "Biological:Animal" + | "Chemical" + | "Environmental" + | "Unknown"; + +type IncidentStatusType = "Watch" | "Alert" | "Respond" | "Closed" | "Discarded"; + +type DateWithNarrative = { + date: Date; + narrative: string; +}; + +interface DiseaseOutbreakAttrs extends NamedRef { + created: Date; + lastUpdated: Date; + createdBy: TeamMember; + hazardType: HazardType; + mainSyndrome: Option; + suspectedDisease: Option; + notificationSource: Option; + areasAffected: { + provinces: OrgUnit[]; + districts: OrgUnit[]; + }; + incidentStatus: IncidentStatusType; + dateEmerged: DateWithNarrative; + dateDetected: DateWithNarrative; + dateNotified: DateWithNarrative; + responseNarrative: string; + incidentManager: TeamMember; + notes: string; + //when should risk assessment, IAP,IMT be fetched? Only when the user clicks on the risk assessment tab? + //Can we async get only 1 property in a class? + riskAssessments: RiskAssessment[]; + //we need only response actions property from IncidentActionPlan. How can we map that? + IncidentActionPlan: IncidentActionPlan; + IncidentManagementTeam: IncidentManagementTeam; +} + +export class DiseaseOutbreak extends Struct() { + static validateEventName() { + //Ensure event name is unique on event creation. + } +} diff --git a/src/domain/entities/OrgUnit.ts b/src/domain/entities/OrgUnit.ts new file mode 100644 index 00000000..6c5c0875 --- /dev/null +++ b/src/domain/entities/OrgUnit.ts @@ -0,0 +1,7 @@ +import { CodedNamedRef } from "./Ref"; + +type OrgUnitLevelType = "Province" | "District"; + +export interface OrgUnit extends CodedNamedRef { + level: OrgUnitLevelType; +} diff --git a/src/domain/entities/Properties.ts b/src/domain/entities/Properties.ts new file mode 100644 index 00000000..492723f3 --- /dev/null +++ b/src/domain/entities/Properties.ts @@ -0,0 +1,32 @@ +//TO DO : Can there be a better name for a generic property? +import { CodedNamedRef } from "./Ref"; + +type PropertTypes = "string" | "date" | "number" | "boolean"; + +//TO DO : what other attributes of a generic domain property? +interface BaseProperty extends CodedNamedRef { + text: string; //or label or key? + type: PropertTypes; +} + +interface StringProperty extends BaseProperty { + type: "string"; + value: string; +} + +interface DateProperty extends BaseProperty { + type: "date"; + value: Date; +} + +interface NumberProperty extends BaseProperty { + type: "number"; + value: number; +} + +interface BooleanProperty extends BaseProperty { + type: "boolean"; + value: boolean; +} + +export type Property = StringProperty | DateProperty | NumberProperty | BooleanProperty; diff --git a/src/domain/entities/Ref.ts b/src/domain/entities/Ref.ts index 8b95ca2f..bdd6e18d 100644 --- a/src/domain/entities/Ref.ts +++ b/src/domain/entities/Ref.ts @@ -7,3 +7,9 @@ export interface Ref { export interface NamedRef extends Ref { name: string; } + +export interface CodedNamedRef extends NamedRef { + code: string; +} + +export type Option = CodedNamedRef; diff --git a/src/domain/entities/incident-action-plan/ActionPlan.ts b/src/domain/entities/incident-action-plan/ActionPlan.ts new file mode 100644 index 00000000..09336e77 --- /dev/null +++ b/src/domain/entities/incident-action-plan/ActionPlan.ts @@ -0,0 +1,8 @@ +import { Property } from "../Properties"; +import { Struct } from "../generic/Struct"; + +interface ActionPlanAttrs { + properties: Property[]; +} + +export class ActionPlan extends Struct() {} diff --git a/src/domain/entities/incident-action-plan/IncidentActionPlan.ts b/src/domain/entities/incident-action-plan/IncidentActionPlan.ts new file mode 100644 index 00000000..222a8df2 --- /dev/null +++ b/src/domain/entities/incident-action-plan/IncidentActionPlan.ts @@ -0,0 +1,12 @@ +import { ActionPlan } from "./ActionPlan"; +import { Ref } from "../Ref"; +import { Struct } from "../generic/Struct"; +import { ResponseAction } from "./ResponseAction"; + +interface IncidentActionPlanAttrs extends Ref { + lastUpdated: Date; + actionPlan: ActionPlan; + responseActions: ResponseAction[]; +} + +export class IncidentActionPlan extends Struct() {} diff --git a/src/domain/entities/incident-action-plan/ResponseAction.ts b/src/domain/entities/incident-action-plan/ResponseAction.ts new file mode 100644 index 00000000..efac906d --- /dev/null +++ b/src/domain/entities/incident-action-plan/ResponseAction.ts @@ -0,0 +1,20 @@ +import { Struct } from "../generic/Struct"; +import { TeamMember } from "../incident-management-team/TeamMember"; +import { Option } from "../Ref"; + +//TO DO : Should this be Option? +type ResponseActionStatusType = "Not done" | "Pending" | "In Progress" | "Complete"; +type ResponseActionVerificationType = "Verified" | "Unverified"; + +interface ResponseActionAttrs { + mainTask: Option; + subActivities: string; + subPillar: Option; + responsibleOfficer: TeamMember; + dueDate: Date; + timeLine: Option; + status: ResponseActionStatusType; + verification: ResponseActionVerificationType; +} + +export class ResponseAction extends Struct() {} diff --git a/src/domain/entities/incident-management-team/IncidentManagementTeam.ts b/src/domain/entities/incident-management-team/IncidentManagementTeam.ts new file mode 100644 index 00000000..89532595 --- /dev/null +++ b/src/domain/entities/incident-management-team/IncidentManagementTeam.ts @@ -0,0 +1,17 @@ +import { Struct } from "../generic/Struct"; +import { TeamMember } from "./TeamMember"; + +interface TeamRole { + role: string; + level: number; +} + +interface RoleTeamMemberMap { + role: TeamRole; + teamMember: TeamMember; +} +interface IncidentManagementTeamAttrs { + teamHeirarchy: RoleTeamMemberMap[]; //Is there a better way to represent heirarchy? Maybe a tree? +} + +export class IncidentManagementTeam extends Struct() {} diff --git a/src/domain/entities/incident-management-team/TeamMember.ts b/src/domain/entities/incident-management-team/TeamMember.ts new file mode 100644 index 00000000..ede7e5fd --- /dev/null +++ b/src/domain/entities/incident-management-team/TeamMember.ts @@ -0,0 +1,21 @@ +import { NamedRef } from "../Ref"; +import { Struct } from "../generic/Struct"; + +type PhoneNumber = string; +type Email = string; +type IncidentManagerStatus = "Available" | "Unavailable"; + +interface TeamMemberAttrs extends NamedRef { + position: string; + phone: PhoneNumber; + email: Email; + status: IncidentManagerStatus; + photo: string; //URL to photo +} + +export class TeamMember extends Struct() { + static validatePhAndEmail() { + //TO DO : any validations for phone number? + //TO DO : any validations for email? + } +} diff --git a/src/domain/entities/risk-assessment/RiskAssessment.ts b/src/domain/entities/risk-assessment/RiskAssessment.ts new file mode 100644 index 00000000..d2b5f63f --- /dev/null +++ b/src/domain/entities/risk-assessment/RiskAssessment.ts @@ -0,0 +1,12 @@ +import { Struct } from "../generic/Struct"; +import { RiskAssessmentGrading } from "./RiskAssessmentGrading"; +import { RiskAssessmentQuestionnaire } from "./RiskAssessmentQuestionnaire"; +import { RiskAssessmentSummary } from "./RiskAssessmentSummary"; + +interface RiskAssessmentAttrs { + riskAssessmentGrading: RiskAssessmentGrading[]; + riskAssessmentSummary: RiskAssessmentSummary; + riskAssessmentQuestionnaire: RiskAssessmentQuestionnaire[]; +} + +export class RiskAssessment extends Struct() {} diff --git a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts new file mode 100644 index 00000000..a035c19a --- /dev/null +++ b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts @@ -0,0 +1,118 @@ +import { Ref } from "../Ref"; +import { Struct } from "../generic/Struct"; + +type WeightedOptions = { + label: "Low" | "Medium" | "High"; + weight: 1 | 2 | 3; +}; + +export const LowWeightedOption: WeightedOptions = { + label: "Low", + weight: 1, +}; +export const MediumWeightedOption: WeightedOptions = { + label: "Medium", + weight: 2, +}; +export const HighWeightedOption: WeightedOptions = { + label: "High", + weight: 3, +}; + +type PopulationWeightOptions = { + label: "Less than 0.1%" | "Between 0.1% to 0.25%" | "Above 0.25%"; + weight: 1 | 2 | 3; +}; + +export const LowPopulationAtRisk: PopulationWeightOptions = { + label: "Less than 0.1%", + weight: 1, +}; +export const MediumPopulationAtRisk: PopulationWeightOptions = { + label: "Between 0.1% to 0.25%", + weight: 2, +}; +export const HighPopulationAtRisk: PopulationWeightOptions = { + label: "Above 0.25%", + weight: 3, +}; + +type GeographicalSpreadOptions = { + label: + | "Within a district" + | "Within a province with more than one district affected" + | "More than one province affected with high threat of spread locally and internationally"; + weight: 1 | 2 | 3; +}; + +export const LowGeographicalSpread: GeographicalSpreadOptions = { + label: "Within a district", + weight: 1, +}; +export const MediumGeographicalSpread: GeographicalSpreadOptions = { + label: "Within a province with more than one district affected", + weight: 2, +}; +export const HighGeographicalSpread: GeographicalSpreadOptions = { + label: "More than one province affected with high threat of spread locally and internationally", + weight: 3, +}; + +type CapacityOptions = { + label: + | "Available within the district with support from provincial and national level " + | "Available within the province with minimal support from national level" + | " Available at national with support required from international"; + weight: 1 | 2 | 3; +}; + +export const LowCapacity: CapacityOptions = { + label: "Available within the district with support from provincial and national level ", + weight: 1, +}; +export const MediumCapacity: CapacityOptions = { + label: "Available within the province with minimal support from national level", + weight: 2, +}; +export const HighCapacity: CapacityOptions = { + label: " Available at national with support required from international", + weight: 3, +}; + +export type Grade = "Grade 1" | "Grade 2" | "Grade 3"; + +interface RiskAssessmentGradingAttrs extends Ref { + lastUpdated: Date; + populationAtRisk: PopulationWeightOptions; + attackRate: WeightedOptions; + geographicalSpread: GeographicalSpreadOptions; + complexity: WeightedOptions; + capacity: CapacityOptions; + reputationalRisk: WeightedOptions; + severity: WeightedOptions; + // capability: WeightedOptions; + grade?: Grade; +} + +export class RiskAssessmentGrading extends Struct() { + calculateAndSetGrade(): void { + const totalWeight = + this.populationAtRisk.weight + + this.attackRate.weight + + this.geographicalSpread.weight + + this.complexity.weight + + this.capacity.weight + + this.reputationalRisk.weight + + this.severity.weight; + // this.capability.weight; + + if (totalWeight > 21) throw new Error("Invalid grade"); + + this.grade = + totalWeight <= 7 + ? "Grade 1" + : totalWeight > 7 && totalWeight <= 14 + ? "Grade 2" + : "Grade 3"; + } +} diff --git a/src/domain/entities/risk-assessment/RiskAssessmentQuestionnaire.ts b/src/domain/entities/risk-assessment/RiskAssessmentQuestionnaire.ts new file mode 100644 index 00000000..4a77cab4 --- /dev/null +++ b/src/domain/entities/risk-assessment/RiskAssessmentQuestionnaire.ts @@ -0,0 +1,8 @@ +import { Property } from "../Properties"; +import { Struct } from "../generic/Struct"; + +interface RiskAssessmentQuestionnaireAttrs { + questions: Property[]; +} + +export class RiskAssessmentQuestionnaire extends Struct() {} diff --git a/src/domain/entities/risk-assessment/RiskAssessmentSummary.ts b/src/domain/entities/risk-assessment/RiskAssessmentSummary.ts new file mode 100644 index 00000000..21b26ce2 --- /dev/null +++ b/src/domain/entities/risk-assessment/RiskAssessmentSummary.ts @@ -0,0 +1,8 @@ +import { Property } from "../Properties"; +import { Struct } from "../generic/Struct"; + +interface RiskAssessmentSummaryAttrs { + properties: Property[]; +} + +export class RiskAssessmentSummary extends Struct() {} diff --git a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts new file mode 100644 index 00000000..7631ff17 --- /dev/null +++ b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts @@ -0,0 +1,94 @@ +import { describe, expect, it } from "vitest"; +import { + HighCapacity, + HighGeographicalSpread, + HighPopulationAtRisk, + HighWeightedOption, + LowCapacity, + LowGeographicalSpread, + LowPopulationAtRisk, + LowWeightedOption, + MediumCapacity, + MediumGeographicalSpread, + MediumPopulationAtRisk, + MediumWeightedOption, + RiskAssessmentGrading, +} from "../RiskAssessmentGrading"; + +describe("RiskAssessmentGrading", () => { + it("should be Grade1 if total weight is less than or equal to 7", () => { + const riskAssessmentGrading = RiskAssessmentGrading.create({ + id: "1", + lastUpdated: new Date(), + populationAtRisk: LowPopulationAtRisk, + attackRate: LowWeightedOption, + geographicalSpread: LowGeographicalSpread, + complexity: LowWeightedOption, + capacity: LowCapacity, + reputationalRisk: LowWeightedOption, + severity: LowWeightedOption, + // capability: LowWeightedOption, + }); + + riskAssessmentGrading.calculateAndSetGrade(); + + expect(riskAssessmentGrading.grade).toBe("Grade 1"); + }); + + it("should be Grade2 if total weight is greater than 7 and less than equal to 14", () => { + const riskAssessmentGrading = RiskAssessmentGrading.create({ + id: "2", + lastUpdated: new Date(), + populationAtRisk: MediumPopulationAtRisk, + attackRate: MediumWeightedOption, + geographicalSpread: MediumGeographicalSpread, + complexity: MediumWeightedOption, + capacity: MediumCapacity, + reputationalRisk: MediumWeightedOption, + severity: MediumWeightedOption, + // capability: MediumWeightedOption, + }); + + riskAssessmentGrading.calculateAndSetGrade(); + + expect(riskAssessmentGrading.grade).toBe("Grade 2"); + }); + + it("should be Grade3 if score is greater than 14", () => { + const riskAssessmentGrading = RiskAssessmentGrading.create({ + id: "3", + lastUpdated: new Date(), + populationAtRisk: HighPopulationAtRisk, + attackRate: HighWeightedOption, + geographicalSpread: HighGeographicalSpread, + complexity: HighWeightedOption, + capacity: HighCapacity, + reputationalRisk: HighWeightedOption, + severity: HighWeightedOption, + // capability: MediumWeightedOption, + }); + + riskAssessmentGrading.calculateAndSetGrade(); + + expect(riskAssessmentGrading.grade).toBe("Grade 3"); + }); + + it("should be Grade3 if score is greater than 14", () => { + const riskAssessmentGrading = RiskAssessmentGrading.create({ + id: "4", + lastUpdated: new Date(), + populationAtRisk: LowPopulationAtRisk, + attackRate: MediumWeightedOption, + geographicalSpread: HighGeographicalSpread, + complexity: MediumWeightedOption, + capacity: LowCapacity, + reputationalRisk: HighWeightedOption, + severity: HighWeightedOption, + // capability: MediumWeightedOption, + }); + + riskAssessmentGrading.calculateAndSetGrade(); + + expect(riskAssessmentGrading.grade).toBe("Grade 3"); + }); +}); diff --git a/src/webapp/pages/app/__tests__/App.spec.tsx b/src/webapp/pages/app/__tests__/App.spec.tsx deleted file mode 100644 index 8a974586..00000000 --- a/src/webapp/pages/app/__tests__/App.spec.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { fireEvent, render } from "@testing-library/react"; - -import App from "../App"; -import { getTestContext } from "../../../../utils/tests"; -import { Provider } from "@dhis2/app-runtime"; - -describe("App", () => { - it("renders the feedback component", async () => { - const view = getView(); - - expect(await view.findByText("Send feedback")).toBeInTheDocument(); - }); - - it("navigates to page", async () => { - const view = getView(); - - fireEvent.click(await view.findByText("John")); - - expect(await view.findByText("Hello John")).toBeInTheDocument(); - expect(view.asFragment()).toMatchSnapshot(); - }); -}); - -function getView() { - const { compositionRoot } = getTestContext(); - return render( - - - - ); -} From 11a8739553c4023989a7696e3c4c0e22840bd3b5 Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Thu, 20 Jun 2024 22:35:28 +0530 Subject: [PATCH 2/8] refactor: ensure create used for creation of objects instead of new --- src/domain/entities/generic/Struct.ts | 2 +- .../risk-assessment/RiskAssessmentGrading.ts | 24 +++++++++++++------ .../__tests__/RiskAssessmentGrading.spec.ts | 16 ++++--------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/domain/entities/generic/Struct.ts b/src/domain/entities/generic/Struct.ts index cf4d9816..6e268007 100644 --- a/src/domain/entities/generic/Struct.ts +++ b/src/domain/entities/generic/Struct.ts @@ -15,7 +15,7 @@ export function Struct() { abstract class Base { - constructor(_attributes: Attrs) { + private constructor(_attributes: Attrs) { Object.assign(this, _attributes); } diff --git a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts index a035c19a..ee4c9ee5 100644 --- a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts +++ b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts @@ -95,7 +95,18 @@ interface RiskAssessmentGradingAttrs extends Ref { } export class RiskAssessmentGrading extends Struct() { - calculateAndSetGrade(): void { + private constructor(attrs: RiskAssessmentGradingAttrs) { + super(attrs); + } + + public static createAndCalculateGrade( + attrs: RiskAssessmentGradingAttrs + ): RiskAssessmentGrading { + const riskAssessmentGrading = new RiskAssessmentGrading(attrs); + return riskAssessmentGrading._update({ grade: riskAssessmentGrading.calculateGrade() }); + } + + calculateGrade(): Grade { const totalWeight = this.populationAtRisk.weight + this.attackRate.weight + @@ -108,11 +119,10 @@ export class RiskAssessmentGrading extends Struct() if (totalWeight > 21) throw new Error("Invalid grade"); - this.grade = - totalWeight <= 7 - ? "Grade 1" - : totalWeight > 7 && totalWeight <= 14 - ? "Grade 2" - : "Grade 3"; + return totalWeight <= 7 + ? "Grade 1" + : totalWeight > 7 && totalWeight <= 14 + ? "Grade 2" + : "Grade 3"; } } diff --git a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts index 7631ff17..2c94b7ea 100644 --- a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts +++ b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts @@ -17,7 +17,7 @@ import { describe("RiskAssessmentGrading", () => { it("should be Grade1 if total weight is less than or equal to 7", () => { - const riskAssessmentGrading = RiskAssessmentGrading.create({ + const riskAssessmentGrading = RiskAssessmentGrading.createAndCalculateGrade({ id: "1", lastUpdated: new Date(), populationAtRisk: LowPopulationAtRisk, @@ -30,13 +30,11 @@ describe("RiskAssessmentGrading", () => { // capability: LowWeightedOption, }); - riskAssessmentGrading.calculateAndSetGrade(); - expect(riskAssessmentGrading.grade).toBe("Grade 1"); }); it("should be Grade2 if total weight is greater than 7 and less than equal to 14", () => { - const riskAssessmentGrading = RiskAssessmentGrading.create({ + const riskAssessmentGrading = RiskAssessmentGrading.createAndCalculateGrade({ id: "2", lastUpdated: new Date(), populationAtRisk: MediumPopulationAtRisk, @@ -49,13 +47,11 @@ describe("RiskAssessmentGrading", () => { // capability: MediumWeightedOption, }); - riskAssessmentGrading.calculateAndSetGrade(); - expect(riskAssessmentGrading.grade).toBe("Grade 2"); }); it("should be Grade3 if score is greater than 14", () => { - const riskAssessmentGrading = RiskAssessmentGrading.create({ + const riskAssessmentGrading = RiskAssessmentGrading.createAndCalculateGrade({ id: "3", lastUpdated: new Date(), populationAtRisk: HighPopulationAtRisk, @@ -68,13 +64,11 @@ describe("RiskAssessmentGrading", () => { // capability: MediumWeightedOption, }); - riskAssessmentGrading.calculateAndSetGrade(); - expect(riskAssessmentGrading.grade).toBe("Grade 3"); }); it("should be Grade3 if score is greater than 14", () => { - const riskAssessmentGrading = RiskAssessmentGrading.create({ + const riskAssessmentGrading = RiskAssessmentGrading.createAndCalculateGrade({ id: "4", lastUpdated: new Date(), populationAtRisk: LowPopulationAtRisk, @@ -87,8 +81,6 @@ describe("RiskAssessmentGrading", () => { // capability: MediumWeightedOption, }); - riskAssessmentGrading.calculateAndSetGrade(); - expect(riskAssessmentGrading.grade).toBe("Grade 3"); }); }); From 3da15ace29d573731cc36afee9990a89be9b481d Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Wed, 26 Jun 2024 14:28:05 +0530 Subject: [PATCH 3/8] refactor: apply coding standards, define types consistently --- src/domain/entities/DiseaseOutbreak.ts | 35 ++++++++++--------- src/domain/entities/OrgUnit.ts | 4 +-- src/domain/entities/Properties.ts | 23 ++++++------ src/domain/entities/Ref.ts | 2 -- src/domain/entities/generic/Struct.ts | 7 +--- .../incident-action-plan/ResponseAction.ts | 14 ++++---- .../IncidentManagementTeam.ts | 8 ++--- .../incident-management-team/TeamMember.ts | 5 +-- .../risk-assessment/RiskAssessment.ts | 6 ++-- .../risk-assessment/RiskAssessmentGrading.ts | 20 +++++------ .../__tests__/RiskAssessmentGrading.spec.ts | 16 ++++----- 11 files changed, 67 insertions(+), 73 deletions(-) diff --git a/src/domain/entities/DiseaseOutbreak.ts b/src/domain/entities/DiseaseOutbreak.ts index 5e67512c..a6ccc6e4 100644 --- a/src/domain/entities/DiseaseOutbreak.ts +++ b/src/domain/entities/DiseaseOutbreak.ts @@ -1,11 +1,9 @@ -//Note: DiseaseOutbreak represents Event in the Figma. -//Not using event as it is a keyword and can also be confused with dhis event import { Struct } from "./generic/Struct"; import { IncidentActionPlan } from "./incident-action-plan/IncidentActionPlan"; import { IncidentManagementTeam } from "./incident-management-team/IncidentManagementTeam"; import { TeamMember } from "./incident-management-team/TeamMember"; import { OrgUnit } from "./OrgUnit"; -import { NamedRef, Option } from "./Ref"; +import { CodedNamedRef, NamedRef } from "./Ref"; import { RiskAssessment } from "./risk-assessment/RiskAssessment"; type HazardType = @@ -22,35 +20,40 @@ type DateWithNarrative = { narrative: string; }; -interface DiseaseOutbreakAttrs extends NamedRef { +type Syndrome = CodedNamedRef; +type Disease = CodedNamedRef; +type NotificationSource = CodedNamedRef; + +type DiseaseOutbreakEventAttrs = NamedRef & { created: Date; lastUpdated: Date; createdBy: TeamMember; hazardType: HazardType; - mainSyndrome: Option; - suspectedDisease: Option; - notificationSource: Option; + mainSyndrome: Syndrome; + suspectedDisease: Disease; + notificationSource: NotificationSource; areasAffected: { provinces: OrgUnit[]; districts: OrgUnit[]; }; incidentStatus: IncidentStatusType; - dateEmerged: DateWithNarrative; - dateDetected: DateWithNarrative; - dateNotified: DateWithNarrative; + emerged: DateWithNarrative; + detected: DateWithNarrative; + notified: DateWithNarrative; responseNarrative: string; incidentManager: TeamMember; notes: string; - //when should risk assessment, IAP,IMT be fetched? Only when the user clicks on the risk assessment tab? - //Can we async get only 1 property in a class? riskAssessments: RiskAssessment[]; - //we need only response actions property from IncidentActionPlan. How can we map that? IncidentActionPlan: IncidentActionPlan; IncidentManagementTeam: IncidentManagementTeam; -} +}; +/** + * Note: DiseaseOutbreak represents Event in the Figma. + * Not using event as it is a keyword and can also be confused with dhis event + **/ -export class DiseaseOutbreak extends Struct() { +export class DiseaseOutbreakEvent extends Struct() { static validateEventName() { - //Ensure event name is unique on event creation. + //TO DO : Ensure event name is unique on event creation. } } diff --git a/src/domain/entities/OrgUnit.ts b/src/domain/entities/OrgUnit.ts index 6c5c0875..554c0721 100644 --- a/src/domain/entities/OrgUnit.ts +++ b/src/domain/entities/OrgUnit.ts @@ -2,6 +2,6 @@ import { CodedNamedRef } from "./Ref"; type OrgUnitLevelType = "Province" | "District"; -export interface OrgUnit extends CodedNamedRef { +export type OrgUnit = CodedNamedRef & { level: OrgUnitLevelType; -} +}; diff --git a/src/domain/entities/Properties.ts b/src/domain/entities/Properties.ts index 492723f3..4fe8844a 100644 --- a/src/domain/entities/Properties.ts +++ b/src/domain/entities/Properties.ts @@ -1,32 +1,29 @@ -//TO DO : Can there be a better name for a generic property? import { CodedNamedRef } from "./Ref"; type PropertTypes = "string" | "date" | "number" | "boolean"; -//TO DO : what other attributes of a generic domain property? -interface BaseProperty extends CodedNamedRef { - text: string; //or label or key? +type BaseProperty = CodedNamedRef & { type: PropertTypes; -} +}; -interface StringProperty extends BaseProperty { +type StringProperty = BaseProperty & { type: "string"; value: string; -} +}; -interface DateProperty extends BaseProperty { +type DateProperty = BaseProperty & { type: "date"; value: Date; -} +}; -interface NumberProperty extends BaseProperty { +type NumberProperty = BaseProperty & { type: "number"; value: number; -} +}; -interface BooleanProperty extends BaseProperty { +type BooleanProperty = BaseProperty & { type: "boolean"; value: boolean; -} +}; export type Property = StringProperty | DateProperty | NumberProperty | BooleanProperty; diff --git a/src/domain/entities/Ref.ts b/src/domain/entities/Ref.ts index bdd6e18d..922a5d18 100644 --- a/src/domain/entities/Ref.ts +++ b/src/domain/entities/Ref.ts @@ -11,5 +11,3 @@ export interface NamedRef extends Ref { export interface CodedNamedRef extends NamedRef { code: string; } - -export type Option = CodedNamedRef; diff --git a/src/domain/entities/generic/Struct.ts b/src/domain/entities/generic/Struct.ts index 6e268007..5a01041e 100644 --- a/src/domain/entities/generic/Struct.ts +++ b/src/domain/entities/generic/Struct.ts @@ -15,7 +15,7 @@ export function Struct() { abstract class Base { - private constructor(_attributes: Attrs) { + protected constructor(_attributes: Attrs) { Object.assign(this, _attributes); } @@ -28,15 +28,10 @@ export function Struct() { const ParentClass = this.constructor as new (values: Attrs) => typeof this; return new ParentClass({ ...this._getAttributes(), ...partialAttrs }); } - - static create(this: new (attrs: Attrs) => U, attrs: Attrs): U { - return new this(attrs); - } } return Base as { new (values: Attrs): Attrs & Base; - create: (typeof Base)["create"]; }; } diff --git a/src/domain/entities/incident-action-plan/ResponseAction.ts b/src/domain/entities/incident-action-plan/ResponseAction.ts index efac906d..1d2c268c 100644 --- a/src/domain/entities/incident-action-plan/ResponseAction.ts +++ b/src/domain/entities/incident-action-plan/ResponseAction.ts @@ -1,18 +1,20 @@ +import { CodedNamedRef } from "../Ref"; import { Struct } from "../generic/Struct"; import { TeamMember } from "../incident-management-team/TeamMember"; -import { Option } from "../Ref"; -//TO DO : Should this be Option? -type ResponseActionStatusType = "Not done" | "Pending" | "In Progress" | "Complete"; +type ResponseActionStatusType = "NotDone" | "Pending" | "InProgress" | "Complete"; type ResponseActionVerificationType = "Verified" | "Unverified"; +type MainTask = CodedNamedRef; +type SubPillar = CodedNamedRef; +type TimeLine = CodedNamedRef; interface ResponseActionAttrs { - mainTask: Option; + mainTask: MainTask; subActivities: string; - subPillar: Option; + subPillar: SubPillar; responsibleOfficer: TeamMember; dueDate: Date; - timeLine: Option; + timeLine: TimeLine; status: ResponseActionStatusType; verification: ResponseActionVerificationType; } diff --git a/src/domain/entities/incident-management-team/IncidentManagementTeam.ts b/src/domain/entities/incident-management-team/IncidentManagementTeam.ts index 89532595..ba0b2832 100644 --- a/src/domain/entities/incident-management-team/IncidentManagementTeam.ts +++ b/src/domain/entities/incident-management-team/IncidentManagementTeam.ts @@ -1,17 +1,17 @@ +import { NamedRef } from "../Ref"; import { Struct } from "../generic/Struct"; import { TeamMember } from "./TeamMember"; -interface TeamRole { - role: string; +type TeamRole = NamedRef & { level: number; -} +}; interface RoleTeamMemberMap { role: TeamRole; teamMember: TeamMember; } interface IncidentManagementTeamAttrs { - teamHeirarchy: RoleTeamMemberMap[]; //Is there a better way to represent heirarchy? Maybe a tree? + teamHierarchy: RoleTeamMemberMap[]; } export class IncidentManagementTeam extends Struct() {} diff --git a/src/domain/entities/incident-management-team/TeamMember.ts b/src/domain/entities/incident-management-team/TeamMember.ts index ede7e5fd..15d3a98b 100644 --- a/src/domain/entities/incident-management-team/TeamMember.ts +++ b/src/domain/entities/incident-management-team/TeamMember.ts @@ -4,13 +4,14 @@ import { Struct } from "../generic/Struct"; type PhoneNumber = string; type Email = string; type IncidentManagerStatus = "Available" | "Unavailable"; +type Postion = string; //TO DO : make a list once available from client. interface TeamMemberAttrs extends NamedRef { - position: string; + position: Postion; phone: PhoneNumber; email: Email; status: IncidentManagerStatus; - photo: string; //URL to photo + photo: URL; } export class TeamMember extends Struct() { diff --git a/src/domain/entities/risk-assessment/RiskAssessment.ts b/src/domain/entities/risk-assessment/RiskAssessment.ts index d2b5f63f..1a3fd827 100644 --- a/src/domain/entities/risk-assessment/RiskAssessment.ts +++ b/src/domain/entities/risk-assessment/RiskAssessment.ts @@ -4,9 +4,9 @@ import { RiskAssessmentQuestionnaire } from "./RiskAssessmentQuestionnaire"; import { RiskAssessmentSummary } from "./RiskAssessmentSummary"; interface RiskAssessmentAttrs { - riskAssessmentGrading: RiskAssessmentGrading[]; - riskAssessmentSummary: RiskAssessmentSummary; - riskAssessmentQuestionnaire: RiskAssessmentQuestionnaire[]; + grading: RiskAssessmentGrading[]; + summary: RiskAssessmentSummary; + questionnaire: RiskAssessmentQuestionnaire[]; } export class RiskAssessment extends Struct() {} diff --git a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts index ee4c9ee5..92d9be49 100644 --- a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts +++ b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts @@ -1,5 +1,7 @@ +import i18n from "@eyeseetea/feedback-component/locales"; import { Ref } from "../Ref"; import { Struct } from "../generic/Struct"; +import { Maybe } from "../../../utils/ts-utils"; type WeightedOptions = { label: "Low" | "Medium" | "High"; @@ -60,14 +62,14 @@ export const HighGeographicalSpread: GeographicalSpreadOptions = { type CapacityOptions = { label: - | "Available within the district with support from provincial and national level " + | "Available within the district with support from provincial and national level" | "Available within the province with minimal support from national level" - | " Available at national with support required from international"; + | "Available at national with support required from international"; weight: 1 | 2 | 3; }; export const LowCapacity: CapacityOptions = { - label: "Available within the district with support from provincial and national level ", + label: "Available within the district with support from provincial and national level", weight: 1, }; export const MediumCapacity: CapacityOptions = { @@ -75,7 +77,7 @@ export const MediumCapacity: CapacityOptions = { weight: 2, }; export const HighCapacity: CapacityOptions = { - label: " Available at national with support required from international", + label: "Available at national with support required from international", weight: 3, }; @@ -90,8 +92,7 @@ interface RiskAssessmentGradingAttrs extends Ref { capacity: CapacityOptions; reputationalRisk: WeightedOptions; severity: WeightedOptions; - // capability: WeightedOptions; - grade?: Grade; + grade: Maybe; } export class RiskAssessmentGrading extends Struct() { @@ -99,9 +100,7 @@ export class RiskAssessmentGrading extends Struct() super(attrs); } - public static createAndCalculateGrade( - attrs: RiskAssessmentGradingAttrs - ): RiskAssessmentGrading { + public static create(attrs: RiskAssessmentGradingAttrs): RiskAssessmentGrading { const riskAssessmentGrading = new RiskAssessmentGrading(attrs); return riskAssessmentGrading._update({ grade: riskAssessmentGrading.calculateGrade() }); } @@ -115,9 +114,8 @@ export class RiskAssessmentGrading extends Struct() this.capacity.weight + this.reputationalRisk.weight + this.severity.weight; - // this.capability.weight; - if (totalWeight > 21) throw new Error("Invalid grade"); + if (totalWeight > 21) throw new Error(i18n.t("Invalid grade")); return totalWeight <= 7 ? "Grade 1" diff --git a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts index 2c94b7ea..af543c81 100644 --- a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts +++ b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts @@ -17,7 +17,7 @@ import { describe("RiskAssessmentGrading", () => { it("should be Grade1 if total weight is less than or equal to 7", () => { - const riskAssessmentGrading = RiskAssessmentGrading.createAndCalculateGrade({ + const riskAssessmentGrading = RiskAssessmentGrading.create({ id: "1", lastUpdated: new Date(), populationAtRisk: LowPopulationAtRisk, @@ -27,14 +27,14 @@ describe("RiskAssessmentGrading", () => { capacity: LowCapacity, reputationalRisk: LowWeightedOption, severity: LowWeightedOption, - // capability: LowWeightedOption, + grade: undefined, }); expect(riskAssessmentGrading.grade).toBe("Grade 1"); }); it("should be Grade2 if total weight is greater than 7 and less than equal to 14", () => { - const riskAssessmentGrading = RiskAssessmentGrading.createAndCalculateGrade({ + const riskAssessmentGrading = RiskAssessmentGrading.create({ id: "2", lastUpdated: new Date(), populationAtRisk: MediumPopulationAtRisk, @@ -44,14 +44,14 @@ describe("RiskAssessmentGrading", () => { capacity: MediumCapacity, reputationalRisk: MediumWeightedOption, severity: MediumWeightedOption, - // capability: MediumWeightedOption, + grade: undefined, }); expect(riskAssessmentGrading.grade).toBe("Grade 2"); }); it("should be Grade3 if score is greater than 14", () => { - const riskAssessmentGrading = RiskAssessmentGrading.createAndCalculateGrade({ + const riskAssessmentGrading = RiskAssessmentGrading.create({ id: "3", lastUpdated: new Date(), populationAtRisk: HighPopulationAtRisk, @@ -61,14 +61,14 @@ describe("RiskAssessmentGrading", () => { capacity: HighCapacity, reputationalRisk: HighWeightedOption, severity: HighWeightedOption, - // capability: MediumWeightedOption, + grade: undefined, }); expect(riskAssessmentGrading.grade).toBe("Grade 3"); }); it("should be Grade3 if score is greater than 14", () => { - const riskAssessmentGrading = RiskAssessmentGrading.createAndCalculateGrade({ + const riskAssessmentGrading = RiskAssessmentGrading.create({ id: "4", lastUpdated: new Date(), populationAtRisk: LowPopulationAtRisk, @@ -78,7 +78,7 @@ describe("RiskAssessmentGrading", () => { capacity: LowCapacity, reputationalRisk: HighWeightedOption, severity: HighWeightedOption, - // capability: MediumWeightedOption, + grade: undefined, }); expect(riskAssessmentGrading.grade).toBe("Grade 3"); From bf6384733004d96e168465b93bbddd4d57375715 Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Fri, 28 Jun 2024 13:57:11 +0530 Subject: [PATCH 4/8] refactor: file name change, getGrade as readonly, use Either for error, add role to team member --- ...aseOutbreak.ts => DiseaseOutbreakEvent.ts} | 3 +- .../IncidentManagementTeam.ts | 11 +------- .../incident-management-team/TeamMember.ts | 7 +++-- .../risk-assessment/RiskAssessmentGrading.ts | 28 +++++++++++-------- .../__tests__/RiskAssessmentGrading.spec.ts | 18 ++++++------ 5 files changed, 32 insertions(+), 35 deletions(-) rename src/domain/entities/{DiseaseOutbreak.ts => DiseaseOutbreakEvent.ts} (96%) diff --git a/src/domain/entities/DiseaseOutbreak.ts b/src/domain/entities/DiseaseOutbreakEvent.ts similarity index 96% rename from src/domain/entities/DiseaseOutbreak.ts rename to src/domain/entities/DiseaseOutbreakEvent.ts index a6ccc6e4..62bd4e29 100644 --- a/src/domain/entities/DiseaseOutbreak.ts +++ b/src/domain/entities/DiseaseOutbreakEvent.ts @@ -5,6 +5,7 @@ import { TeamMember } from "./incident-management-team/TeamMember"; import { OrgUnit } from "./OrgUnit"; import { CodedNamedRef, NamedRef } from "./Ref"; import { RiskAssessment } from "./risk-assessment/RiskAssessment"; +import { Maybe } from "../../utils/ts-utils"; type HazardType = | "Biological:Human" @@ -42,7 +43,7 @@ type DiseaseOutbreakEventAttrs = NamedRef & { notified: DateWithNarrative; responseNarrative: string; incidentManager: TeamMember; - notes: string; + notes: Maybe; riskAssessments: RiskAssessment[]; IncidentActionPlan: IncidentActionPlan; IncidentManagementTeam: IncidentManagementTeam; diff --git a/src/domain/entities/incident-management-team/IncidentManagementTeam.ts b/src/domain/entities/incident-management-team/IncidentManagementTeam.ts index ba0b2832..cb9298bf 100644 --- a/src/domain/entities/incident-management-team/IncidentManagementTeam.ts +++ b/src/domain/entities/incident-management-team/IncidentManagementTeam.ts @@ -1,17 +1,8 @@ -import { NamedRef } from "../Ref"; import { Struct } from "../generic/Struct"; import { TeamMember } from "./TeamMember"; -type TeamRole = NamedRef & { - level: number; -}; - -interface RoleTeamMemberMap { - role: TeamRole; - teamMember: TeamMember; -} interface IncidentManagementTeamAttrs { - teamHierarchy: RoleTeamMemberMap[]; + teamHierarchy: TeamMember[]; } export class IncidentManagementTeam extends Struct() {} diff --git a/src/domain/entities/incident-management-team/TeamMember.ts b/src/domain/entities/incident-management-team/TeamMember.ts index 15d3a98b..4e77678e 100644 --- a/src/domain/entities/incident-management-team/TeamMember.ts +++ b/src/domain/entities/incident-management-team/TeamMember.ts @@ -4,14 +4,17 @@ import { Struct } from "../generic/Struct"; type PhoneNumber = string; type Email = string; type IncidentManagerStatus = "Available" | "Unavailable"; -type Postion = string; //TO DO : make a list once available from client. + +export type TeamRole = NamedRef & { + level: number; +}; interface TeamMemberAttrs extends NamedRef { - position: Postion; phone: PhoneNumber; email: Email; status: IncidentManagerStatus; photo: URL; + role: TeamRole; } export class TeamMember extends Struct() { diff --git a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts index 92d9be49..b81ba2eb 100644 --- a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts +++ b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts @@ -1,13 +1,12 @@ import i18n from "@eyeseetea/feedback-component/locales"; import { Ref } from "../Ref"; import { Struct } from "../generic/Struct"; -import { Maybe } from "../../../utils/ts-utils"; +import { Either } from "../generic/Either"; type WeightedOptions = { label: "Low" | "Medium" | "High"; weight: 1 | 2 | 3; }; - export const LowWeightedOption: WeightedOptions = { label: "Low", weight: 1, @@ -92,7 +91,6 @@ interface RiskAssessmentGradingAttrs extends Ref { capacity: CapacityOptions; reputationalRisk: WeightedOptions; severity: WeightedOptions; - grade: Maybe; } export class RiskAssessmentGrading extends Struct() { @@ -101,11 +99,14 @@ export class RiskAssessmentGrading extends Struct() } public static create(attrs: RiskAssessmentGradingAttrs): RiskAssessmentGrading { - const riskAssessmentGrading = new RiskAssessmentGrading(attrs); - return riskAssessmentGrading._update({ grade: riskAssessmentGrading.calculateGrade() }); + return new RiskAssessmentGrading(attrs); } - calculateGrade(): Grade { + getGrade = (): Either => { + return this.calculateGrade(); + }; + + calculateGrade(): Either { const totalWeight = this.populationAtRisk.weight + this.attackRate.weight + @@ -115,12 +116,15 @@ export class RiskAssessmentGrading extends Struct() this.reputationalRisk.weight + this.severity.weight; - if (totalWeight > 21) throw new Error(i18n.t("Invalid grade")); + if (totalWeight > 21) return Either.error(new Error(i18n.t("Invalid grade"))); + + const grade: Grade = + totalWeight <= 7 + ? "Grade 1" + : totalWeight > 7 && totalWeight <= 14 + ? "Grade 2" + : "Grade 3"; - return totalWeight <= 7 - ? "Grade 1" - : totalWeight > 7 && totalWeight <= 14 - ? "Grade 2" - : "Grade 3"; + return Either.success(grade); } } diff --git a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts index af543c81..d1564b7a 100644 --- a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts +++ b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts @@ -27,10 +27,9 @@ describe("RiskAssessmentGrading", () => { capacity: LowCapacity, reputationalRisk: LowWeightedOption, severity: LowWeightedOption, - grade: undefined, }); - - expect(riskAssessmentGrading.grade).toBe("Grade 1"); + const grade = riskAssessmentGrading.getGrade().value.data; + expect(grade).toBe("Grade 1"); }); it("should be Grade2 if total weight is greater than 7 and less than equal to 14", () => { @@ -44,10 +43,9 @@ describe("RiskAssessmentGrading", () => { capacity: MediumCapacity, reputationalRisk: MediumWeightedOption, severity: MediumWeightedOption, - grade: undefined, }); - - expect(riskAssessmentGrading.grade).toBe("Grade 2"); + const grade = riskAssessmentGrading.getGrade().value.data; + expect(grade).toBe("Grade 2"); }); it("should be Grade3 if score is greater than 14", () => { @@ -61,10 +59,10 @@ describe("RiskAssessmentGrading", () => { capacity: HighCapacity, reputationalRisk: HighWeightedOption, severity: HighWeightedOption, - grade: undefined, }); - expect(riskAssessmentGrading.grade).toBe("Grade 3"); + const grade = riskAssessmentGrading.getGrade().value.data; + expect(grade).toBe("Grade 3"); }); it("should be Grade3 if score is greater than 14", () => { @@ -78,9 +76,9 @@ describe("RiskAssessmentGrading", () => { capacity: LowCapacity, reputationalRisk: HighWeightedOption, severity: HighWeightedOption, - grade: undefined, }); - expect(riskAssessmentGrading.grade).toBe("Grade 3"); + const grade = riskAssessmentGrading.getGrade().value.data; + expect(grade).toBe("Grade 3"); }); }); From 6cb5ff53f0a3cc4f5553940a73f183c1b01dca80 Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Mon, 1 Jul 2024 07:36:11 +0530 Subject: [PATCH 5/8] fix: translate labels in risk grading --- i18n/en.pot | 56 ++++++++++- i18n/es.po | 53 +++++++++- .../risk-assessment/RiskAssessmentGrading.ts | 97 +++++++++++++------ .../__tests__/RiskAssessmentGrading.spec.ts | 23 +---- 4 files changed, 177 insertions(+), 52 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index 1ad98c3d..cab25e00 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,60 @@ 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-09-18T13:40:05.079Z\n" -"PO-Revision-Date: 2023-09-18T13:40:05.079Z\n" +"POT-Creation-Date: 2024-07-01T02:04:44.570Z\n" +"PO-Revision-Date: 2024-07-01T02:04:44.570Z\n" + +msgid "Low" +msgstr "" + +msgid "Medium" +msgstr "" + +msgid "High" +msgstr "" + +msgid "Less than 0.1%" +msgstr "" + +msgid "Between 0.1% to 0.25%" +msgstr "" + +msgid "Above 0.25%" +msgstr "" + +msgid "Within a district" +msgstr "" + +msgid "Within a province with more than one district affected" +msgstr "" + +msgid "" +"More than one province affected with high threat of spread locally and " +"internationally" +msgstr "" + +msgid "" +"Available within the district with support from provincial and national " +"level" +msgstr "" + +msgid "Available within the province with minimal support from national level" +msgstr "" + +msgid "Available at national with support required from international" +msgstr "" + +msgid "Grade 1" +msgstr "" + +msgid "Grade 2" +msgstr "" + +msgid "Grade 3" +msgstr "" + +msgid "Invalid grade" +msgstr "" msgid "Add" msgstr "" diff --git a/i18n/es.po b/i18n/es.po index 0250fb5a..2de05644 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -1,13 +1,64 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-09-18T10:19:02.458Z\n" +"POT-Creation-Date: 2024-07-01T02:04:44.570Z\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 "Low" +msgstr "" + +msgid "Medium" +msgstr "" + +msgid "High" +msgstr "" + +msgid "Less than 0.1%" +msgstr "" + +msgid "Between 0.1% to 0.25%" +msgstr "" + +msgid "Above 0.25%" +msgstr "" + +msgid "Within a district" +msgstr "" + +msgid "Within a province with more than one district affected" +msgstr "" + +msgid "" +"More than one province affected with high threat of spread locally and " +"internationally" +msgstr "" + +msgid "" +"Available within the district with support from provincial and national level" +msgstr "" + +msgid "Available within the province with minimal support from national level" +msgstr "" + +msgid "Available at national with support required from international" +msgstr "" + +msgid "Grade 1" +msgstr "" + +msgid "Grade 2" +msgstr "" + +msgid "Grade 3" +msgstr "" + +msgid "Invalid grade" +msgstr "" + msgid "Add" msgstr "AƱadir" diff --git a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts index b81ba2eb..8acc5b96 100644 --- a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts +++ b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts @@ -3,84 +3,119 @@ import { Ref } from "../Ref"; import { Struct } from "../generic/Struct"; import { Either } from "../generic/Either"; +type WeightedOptionTypes = "Low" | "Medium" | "High"; +type PopulationWeightOptionsTypes = "LessPercentage" | "MediumPercentage" | "HighPercentage"; +type GeographicalSpreadOptionsTypes = + | "WithinDistrict" + | "MoretThanOneDistrict" + | "MoreThanOneProvince"; +type CapacityOptionsTypes = + | "ProvincialNationalLevel" + | "ProvincialLevel" + | "NationalInternationalLevel"; + type WeightedOptions = { - label: "Low" | "Medium" | "High"; + type: WeightedOptionTypes; weight: 1 | 2 | 3; }; export const LowWeightedOption: WeightedOptions = { - label: "Low", + type: "Low", weight: 1, }; export const MediumWeightedOption: WeightedOptions = { - label: "Medium", + type: "Medium", weight: 2, }; export const HighWeightedOption: WeightedOptions = { - label: "High", + type: "High", weight: 3, }; type PopulationWeightOptions = { - label: "Less than 0.1%" | "Between 0.1% to 0.25%" | "Above 0.25%"; + type: PopulationWeightOptionsTypes; weight: 1 | 2 | 3; }; - export const LowPopulationAtRisk: PopulationWeightOptions = { - label: "Less than 0.1%", + type: "LessPercentage", weight: 1, }; export const MediumPopulationAtRisk: PopulationWeightOptions = { - label: "Between 0.1% to 0.25%", + type: "MediumPercentage", weight: 2, }; export const HighPopulationAtRisk: PopulationWeightOptions = { - label: "Above 0.25%", + type: "HighPercentage", weight: 3, }; type GeographicalSpreadOptions = { - label: - | "Within a district" - | "Within a province with more than one district affected" - | "More than one province affected with high threat of spread locally and internationally"; + type: GeographicalSpreadOptionsTypes; weight: 1 | 2 | 3; }; - export const LowGeographicalSpread: GeographicalSpreadOptions = { - label: "Within a district", + type: "WithinDistrict", weight: 1, }; export const MediumGeographicalSpread: GeographicalSpreadOptions = { - label: "Within a province with more than one district affected", + type: "MoretThanOneDistrict", weight: 2, }; export const HighGeographicalSpread: GeographicalSpreadOptions = { - label: "More than one province affected with high threat of spread locally and internationally", + type: "MoreThanOneProvince", weight: 3, }; type CapacityOptions = { - label: - | "Available within the district with support from provincial and national level" - | "Available within the province with minimal support from national level" - | "Available at national with support required from international"; + type: CapacityOptionsTypes; weight: 1 | 2 | 3; }; - export const LowCapacity: CapacityOptions = { - label: "Available within the district with support from provincial and national level", + type: "ProvincialNationalLevel", weight: 1, }; export const MediumCapacity: CapacityOptions = { - label: "Available within the province with minimal support from national level", + type: "ProvincialLevel", weight: 2, }; export const HighCapacity: CapacityOptions = { - label: "Available at national with support required from international", + type: "NationalInternationalLevel", weight: 3, }; -export type Grade = "Grade 1" | "Grade 2" | "Grade 3"; +export type Grade = "Grade1" | "Grade2" | "Grade3"; + +type AllOptionTypes = + | WeightedOptionTypes + | PopulationWeightOptionsTypes + | GeographicalSpreadOptionsTypes + | CapacityOptionsTypes + | Grade; + +const translations: Record = { + Low: i18n.t("Low"), + Medium: i18n.t("Medium"), + High: i18n.t("High"), + LessPercentage: i18n.t("Less than 0.1%"), + MediumPercentage: i18n.t("Between 0.1% to 0.25%"), + HighPercentage: i18n.t("Above 0.25%"), + WithinDistrict: i18n.t("Within a district"), + MoretThanOneDistrict: i18n.t("Within a province with more than one district affected"), + MoreThanOneProvince: i18n.t( + "More than one province affected with high threat of spread locally and internationally" + ), + ProvincialNationalLevel: i18n.t( + "Available within the district with support from provincial and national level" + ), + ProvincialLevel: i18n.t( + "Available within the province with minimal support from national level" + ), + NationalInternationalLevel: i18n.t( + "Available at national with support required from international" + ), + Grade1: i18n.t("Grade 1"), + Grade2: i18n.t("Grade 2"), + Grade3: i18n.t("Grade 3"), +}; interface RiskAssessmentGradingAttrs extends Ref { lastUpdated: Date; @@ -102,6 +137,10 @@ export class RiskAssessmentGrading extends Struct() return new RiskAssessmentGrading(attrs); } + public static getTranslatedLabel(key: AllOptionTypes): string { + return translations[key]; + } + getGrade = (): Either => { return this.calculateGrade(); }; @@ -120,10 +159,10 @@ export class RiskAssessmentGrading extends Struct() const grade: Grade = totalWeight <= 7 - ? "Grade 1" + ? "Grade1" : totalWeight > 7 && totalWeight <= 14 - ? "Grade 2" - : "Grade 3"; + ? "Grade2" + : "Grade3"; return Either.success(grade); } diff --git a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts index d1564b7a..3296b142 100644 --- a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts +++ b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts @@ -29,7 +29,7 @@ describe("RiskAssessmentGrading", () => { severity: LowWeightedOption, }); const grade = riskAssessmentGrading.getGrade().value.data; - expect(grade).toBe("Grade 1"); + if (grade) expect(RiskAssessmentGrading.getTranslatedLabel(grade)).toBe("Grade 1"); }); it("should be Grade2 if total weight is greater than 7 and less than equal to 14", () => { @@ -45,7 +45,7 @@ describe("RiskAssessmentGrading", () => { severity: MediumWeightedOption, }); const grade = riskAssessmentGrading.getGrade().value.data; - expect(grade).toBe("Grade 2"); + if (grade) expect(RiskAssessmentGrading.getTranslatedLabel(grade)).toBe("Grade 2"); }); it("should be Grade3 if score is greater than 14", () => { @@ -62,23 +62,6 @@ describe("RiskAssessmentGrading", () => { }); const grade = riskAssessmentGrading.getGrade().value.data; - expect(grade).toBe("Grade 3"); - }); - - it("should be Grade3 if score is greater than 14", () => { - const riskAssessmentGrading = RiskAssessmentGrading.create({ - id: "4", - lastUpdated: new Date(), - populationAtRisk: LowPopulationAtRisk, - attackRate: MediumWeightedOption, - geographicalSpread: HighGeographicalSpread, - complexity: MediumWeightedOption, - capacity: LowCapacity, - reputationalRisk: HighWeightedOption, - severity: HighWeightedOption, - }); - - const grade = riskAssessmentGrading.getGrade().value.data; - expect(grade).toBe("Grade 3"); + if (grade) expect(RiskAssessmentGrading.getTranslatedLabel(grade)).toBe("Grade 3"); }); }); From 40a3647ba464d1fef96cb69d8d22b02ffebcd000 Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Mon, 1 Jul 2024 17:45:25 +0530 Subject: [PATCH 6/8] refactor: couple type and weight for options --- src/domain/entities/DiseaseOutbreakEvent.ts | 2 +- src/domain/entities/generic/Either.ts | 7 ++ .../risk-assessment/RiskAssessmentGrading.ts | 106 ++++++++---------- .../__tests__/RiskAssessmentGrading.spec.ts | 35 +++--- 4 files changed, 70 insertions(+), 80 deletions(-) diff --git a/src/domain/entities/DiseaseOutbreakEvent.ts b/src/domain/entities/DiseaseOutbreakEvent.ts index 62bd4e29..ad19ab9f 100644 --- a/src/domain/entities/DiseaseOutbreakEvent.ts +++ b/src/domain/entities/DiseaseOutbreakEvent.ts @@ -49,7 +49,7 @@ type DiseaseOutbreakEventAttrs = NamedRef & { IncidentManagementTeam: IncidentManagementTeam; }; /** - * Note: DiseaseOutbreak represents Event in the Figma. + * Note: DiseaseOutbreakEvent represents Event in the Figma. * Not using event as it is a keyword and can also be confused with dhis event **/ diff --git a/src/domain/entities/generic/Either.ts b/src/domain/entities/generic/Either.ts index 33234090..ecca6888 100644 --- a/src/domain/entities/generic/Either.ts +++ b/src/domain/entities/generic/Either.ts @@ -17,6 +17,13 @@ export class Either { constructor(public value: EitherValue) {} + getOrThrow(): Data | undefined { + if (this.isError()) { + throw this.value.error; + } + return this.value.data; + } + match(matchObj: MatchObject): Res { switch (this.value.type) { case "success": diff --git a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts index 8acc5b96..3b053d60 100644 --- a/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts +++ b/src/domain/entities/risk-assessment/RiskAssessmentGrading.ts @@ -14,72 +14,56 @@ type CapacityOptionsTypes = | "ProvincialLevel" | "NationalInternationalLevel"; -type WeightedOptions = { - type: WeightedOptionTypes; - weight: 1 | 2 | 3; +export type LowWeightedOption = { + type: "Low"; + weight: 1; }; -export const LowWeightedOption: WeightedOptions = { - type: "Low", - weight: 1, +export type MediumWeightedOption = { + type: "Medium"; + weight: 2; }; -export const MediumWeightedOption: WeightedOptions = { - type: "Medium", - weight: 2, -}; -export const HighWeightedOption: WeightedOptions = { - type: "High", - weight: 3, +export type HighWeightedOption = { + type: "High"; + weight: 3; }; -type PopulationWeightOptions = { - type: PopulationWeightOptionsTypes; - weight: 1 | 2 | 3; -}; -export const LowPopulationAtRisk: PopulationWeightOptions = { - type: "LessPercentage", - weight: 1, +export type LowPopulationAtRisk = { + type: "LessPercentage"; + weight: 1; }; -export const MediumPopulationAtRisk: PopulationWeightOptions = { - type: "MediumPercentage", - weight: 2, +export type MediumPopulationAtRisk = { + type: "MediumPercentage"; + weight: 2; }; -export const HighPopulationAtRisk: PopulationWeightOptions = { - type: "HighPercentage", - weight: 3, +export type HighPopulationAtRisk = { + type: "HighPercentage"; + weight: 3; }; -type GeographicalSpreadOptions = { - type: GeographicalSpreadOptionsTypes; - weight: 1 | 2 | 3; -}; -export const LowGeographicalSpread: GeographicalSpreadOptions = { - type: "WithinDistrict", - weight: 1, +export type LowGeographicalSpread = { + type: "WithinDistrict"; + weight: 1; }; -export const MediumGeographicalSpread: GeographicalSpreadOptions = { - type: "MoretThanOneDistrict", - weight: 2, +export type MediumGeographicalSpread = { + type: "MoretThanOneDistrict"; + weight: 2; }; -export const HighGeographicalSpread: GeographicalSpreadOptions = { - type: "MoreThanOneProvince", - weight: 3, +export type HighGeographicalSpread = { + type: "MoreThanOneProvince"; + weight: 3; }; -type CapacityOptions = { - type: CapacityOptionsTypes; - weight: 1 | 2 | 3; +export type LowCapacity = { + type: "ProvincialNationalLevel"; + weight: 1; }; -export const LowCapacity: CapacityOptions = { - type: "ProvincialNationalLevel", - weight: 1, +export type MediumCapacity = { + type: "ProvincialLevel"; + weight: 2; }; -export const MediumCapacity: CapacityOptions = { - type: "ProvincialLevel", - weight: 2, -}; -export const HighCapacity: CapacityOptions = { - type: "NationalInternationalLevel", - weight: 3, +export type HighCapacity = { + type: "NationalInternationalLevel"; + weight: 3; }; export type Grade = "Grade1" | "Grade2" | "Grade3"; @@ -119,13 +103,13 @@ const translations: Record = { interface RiskAssessmentGradingAttrs extends Ref { lastUpdated: Date; - populationAtRisk: PopulationWeightOptions; - attackRate: WeightedOptions; - geographicalSpread: GeographicalSpreadOptions; - complexity: WeightedOptions; - capacity: CapacityOptions; - reputationalRisk: WeightedOptions; - severity: WeightedOptions; + populationAtRisk: LowPopulationAtRisk | MediumPopulationAtRisk | HighPopulationAtRisk; + attackRate: LowWeightedOption | MediumWeightedOption | HighWeightedOption; + geographicalSpread: LowGeographicalSpread | MediumGeographicalSpread | HighGeographicalSpread; + complexity: LowWeightedOption | MediumWeightedOption | HighWeightedOption; + capacity: LowCapacity | MediumCapacity | HighCapacity; + reputationalRisk: LowWeightedOption | MediumWeightedOption | HighWeightedOption; + severity: LowWeightedOption | MediumWeightedOption | HighWeightedOption; } export class RiskAssessmentGrading extends Struct() { @@ -141,9 +125,9 @@ export class RiskAssessmentGrading extends Struct() return translations[key]; } - getGrade = (): Either => { + getGrade(): Either { return this.calculateGrade(); - }; + } calculateGrade(): Either { const totalWeight = diff --git a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts index 3296b142..0e27d4b3 100644 --- a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts +++ b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts @@ -1,19 +1,18 @@ import { describe, expect, it } from "vitest"; -import { - HighCapacity, - HighGeographicalSpread, - HighPopulationAtRisk, - HighWeightedOption, - LowCapacity, - LowGeographicalSpread, - LowPopulationAtRisk, - LowWeightedOption, - MediumCapacity, - MediumGeographicalSpread, - MediumPopulationAtRisk, - MediumWeightedOption, - RiskAssessmentGrading, -} from "../RiskAssessmentGrading"; +import { RiskAssessmentGrading } from "../RiskAssessmentGrading"; + +const LowPopulationAtRisk = { type: "LessPercentage" as const, weight: 1 as const }; +const MediumPopulationAtRisk = { type: "MediumPercentage" as const, weight: 2 as const }; +const HighPopulationAtRisk = { type: "HighPercentage" as const, weight: 3 as const }; +const LowWeightedOption = { type: "Low" as const, weight: 1 as const }; +const MediumWeightedOption = { type: "Medium" as const, weight: 2 as const }; +const HighWeightedOption = { type: "High" as const, weight: 3 as const }; +const LowGeographicalSpread = { type: "WithinDistrict" as const, weight: 1 as const }; +const MediumGeographicalSpread = { type: "MoretThanOneDistrict" as const, weight: 2 as const }; +const HighGeographicalSpread = { type: "MoreThanOneProvince" as const, weight: 3 as const }; +const LowCapacity = { type: "ProvincialNationalLevel" as const, weight: 1 as const }; +const MediumCapacity = { type: "ProvincialLevel" as const, weight: 2 as const }; +const HighCapacity = { type: "NationalInternationalLevel" as const, weight: 3 as const }; describe("RiskAssessmentGrading", () => { it("should be Grade1 if total weight is less than or equal to 7", () => { @@ -28,7 +27,7 @@ describe("RiskAssessmentGrading", () => { reputationalRisk: LowWeightedOption, severity: LowWeightedOption, }); - const grade = riskAssessmentGrading.getGrade().value.data; + const grade = riskAssessmentGrading.getGrade().getOrThrow(); if (grade) expect(RiskAssessmentGrading.getTranslatedLabel(grade)).toBe("Grade 1"); }); @@ -44,7 +43,7 @@ describe("RiskAssessmentGrading", () => { reputationalRisk: MediumWeightedOption, severity: MediumWeightedOption, }); - const grade = riskAssessmentGrading.getGrade().value.data; + const grade = riskAssessmentGrading.getGrade().getOrThrow(); if (grade) expect(RiskAssessmentGrading.getTranslatedLabel(grade)).toBe("Grade 2"); }); @@ -61,7 +60,7 @@ describe("RiskAssessmentGrading", () => { severity: HighWeightedOption, }); - const grade = riskAssessmentGrading.getGrade().value.data; + const grade = riskAssessmentGrading.getGrade().getOrThrow(); if (grade) expect(RiskAssessmentGrading.getTranslatedLabel(grade)).toBe("Grade 3"); }); }); From 09e05e690326183473679cc605c8b0e752ffe27b Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Mon, 1 Jul 2024 17:54:05 +0530 Subject: [PATCH 7/8] fix: narrow Either.getOrThrow implementation --- src/domain/entities/generic/Either.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/domain/entities/generic/Either.ts b/src/domain/entities/generic/Either.ts index ecca6888..adff2c62 100644 --- a/src/domain/entities/generic/Either.ts +++ b/src/domain/entities/generic/Either.ts @@ -17,11 +17,9 @@ export class Either { constructor(public value: EitherValue) {} - getOrThrow(): Data | undefined { - if (this.isError()) { - throw this.value.error; - } - return this.value.data; + getOrThrow(): Data { + if (this.value.data) return this.value.data; + else throw this.value.error; } match(matchObj: MatchObject): Res { From 3ea234d5c9df727089a709648b32b9a774787ed5 Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Mon, 1 Jul 2024 17:56:28 +0530 Subject: [PATCH 8/8] fix: naming convention for variables --- .../__tests__/RiskAssessmentGrading.spec.ts | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts index 0e27d4b3..1f1b9e3c 100644 --- a/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts +++ b/src/domain/entities/risk-assessment/__tests__/RiskAssessmentGrading.spec.ts @@ -1,31 +1,31 @@ import { describe, expect, it } from "vitest"; import { RiskAssessmentGrading } from "../RiskAssessmentGrading"; -const LowPopulationAtRisk = { type: "LessPercentage" as const, weight: 1 as const }; -const MediumPopulationAtRisk = { type: "MediumPercentage" as const, weight: 2 as const }; -const HighPopulationAtRisk = { type: "HighPercentage" as const, weight: 3 as const }; -const LowWeightedOption = { type: "Low" as const, weight: 1 as const }; -const MediumWeightedOption = { type: "Medium" as const, weight: 2 as const }; -const HighWeightedOption = { type: "High" as const, weight: 3 as const }; -const LowGeographicalSpread = { type: "WithinDistrict" as const, weight: 1 as const }; -const MediumGeographicalSpread = { type: "MoretThanOneDistrict" as const, weight: 2 as const }; -const HighGeographicalSpread = { type: "MoreThanOneProvince" as const, weight: 3 as const }; -const LowCapacity = { type: "ProvincialNationalLevel" as const, weight: 1 as const }; -const MediumCapacity = { type: "ProvincialLevel" as const, weight: 2 as const }; -const HighCapacity = { type: "NationalInternationalLevel" as const, weight: 3 as const }; +const lowPopulationAtRisk = { type: "LessPercentage" as const, weight: 1 as const }; +const mediumPopulationAtRisk = { type: "MediumPercentage" as const, weight: 2 as const }; +const highPopulationAtRisk = { type: "HighPercentage" as const, weight: 3 as const }; +const lowWeightedOption = { type: "Low" as const, weight: 1 as const }; +const mediumWeightedOption = { type: "Medium" as const, weight: 2 as const }; +const highWeightedOption = { type: "High" as const, weight: 3 as const }; +const lowGeographicalSpread = { type: "WithinDistrict" as const, weight: 1 as const }; +const mediumGeographicalSpread = { type: "MoretThanOneDistrict" as const, weight: 2 as const }; +const highGeographicalSpread = { type: "MoreThanOneProvince" as const, weight: 3 as const }; +const lowCapacity = { type: "ProvincialNationalLevel" as const, weight: 1 as const }; +const mediumCapacity = { type: "ProvincialLevel" as const, weight: 2 as const }; +const highCapacity = { type: "NationalInternationalLevel" as const, weight: 3 as const }; describe("RiskAssessmentGrading", () => { it("should be Grade1 if total weight is less than or equal to 7", () => { const riskAssessmentGrading = RiskAssessmentGrading.create({ id: "1", lastUpdated: new Date(), - populationAtRisk: LowPopulationAtRisk, - attackRate: LowWeightedOption, - geographicalSpread: LowGeographicalSpread, - complexity: LowWeightedOption, - capacity: LowCapacity, - reputationalRisk: LowWeightedOption, - severity: LowWeightedOption, + populationAtRisk: lowPopulationAtRisk, + attackRate: lowWeightedOption, + geographicalSpread: lowGeographicalSpread, + complexity: lowWeightedOption, + capacity: lowCapacity, + reputationalRisk: lowWeightedOption, + severity: lowWeightedOption, }); const grade = riskAssessmentGrading.getGrade().getOrThrow(); if (grade) expect(RiskAssessmentGrading.getTranslatedLabel(grade)).toBe("Grade 1"); @@ -35,13 +35,13 @@ describe("RiskAssessmentGrading", () => { const riskAssessmentGrading = RiskAssessmentGrading.create({ id: "2", lastUpdated: new Date(), - populationAtRisk: MediumPopulationAtRisk, - attackRate: MediumWeightedOption, - geographicalSpread: MediumGeographicalSpread, - complexity: MediumWeightedOption, - capacity: MediumCapacity, - reputationalRisk: MediumWeightedOption, - severity: MediumWeightedOption, + populationAtRisk: mediumPopulationAtRisk, + attackRate: mediumWeightedOption, + geographicalSpread: mediumGeographicalSpread, + complexity: mediumWeightedOption, + capacity: mediumCapacity, + reputationalRisk: mediumWeightedOption, + severity: mediumWeightedOption, }); const grade = riskAssessmentGrading.getGrade().getOrThrow(); if (grade) expect(RiskAssessmentGrading.getTranslatedLabel(grade)).toBe("Grade 2"); @@ -51,13 +51,13 @@ describe("RiskAssessmentGrading", () => { const riskAssessmentGrading = RiskAssessmentGrading.create({ id: "3", lastUpdated: new Date(), - populationAtRisk: HighPopulationAtRisk, - attackRate: HighWeightedOption, - geographicalSpread: HighGeographicalSpread, - complexity: HighWeightedOption, - capacity: HighCapacity, - reputationalRisk: HighWeightedOption, - severity: HighWeightedOption, + populationAtRisk: highPopulationAtRisk, + attackRate: highWeightedOption, + geographicalSpread: highGeographicalSpread, + complexity: highWeightedOption, + capacity: highCapacity, + reputationalRisk: highWeightedOption, + severity: highWeightedOption, }); const grade = riskAssessmentGrading.getGrade().getOrThrow();