Skip to content

Commit

Permalink
feat: Domain entities for zebra
Browse files Browse the repository at this point in the history
  • Loading branch information
9sneha-n committed Jun 12, 2024
1 parent 9d292d1 commit 2f7013f
Show file tree
Hide file tree
Showing 17 changed files with 434 additions and 39 deletions.
13 changes: 10 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />

<link type="text/css" rel="stylesheet" href="/includes/material-design-icons/material-icons.css" />
<link
type="text/css"
rel="stylesheet"
href="/includes/material-design-icons/material-icons.css"
/>
<link type="text/css" rel="stylesheet" href="/includes/roboto-font.css" />
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet" />
<link
href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css"
rel="stylesheet"
/>

<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="theme-color" content="#000000" />

<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<title>Zebra</title>
</head>

<body>
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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"
},
Expand Down
56 changes: 56 additions & 0 deletions src/domain/entities/DiseaseOutbreak.ts
Original file line number Diff line number Diff line change
@@ -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<DiseaseOutbreakAttrs>() {
static validateEventName() {
//Ensure event name is unique on event creation.
}
}
7 changes: 7 additions & 0 deletions src/domain/entities/OrgUnit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { CodedNamedRef } from "./Ref";

type OrgUnitLevelType = "Province" | "District";

export interface OrgUnit extends CodedNamedRef {
level: OrgUnitLevelType;
}
32 changes: 32 additions & 0 deletions src/domain/entities/Properties.ts
Original file line number Diff line number Diff line change
@@ -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;
6 changes: 6 additions & 0 deletions src/domain/entities/Ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
8 changes: 8 additions & 0 deletions src/domain/entities/incident-action-plan/ActionPlan.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Property } from "../Properties";
import { Struct } from "../generic/Struct";

interface ActionPlanAttrs {
properties: Property[];
}

export class ActionPlan extends Struct<ActionPlanAttrs>() {}
12 changes: 12 additions & 0 deletions src/domain/entities/incident-action-plan/IncidentActionPlan.ts
Original file line number Diff line number Diff line change
@@ -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<IncidentActionPlanAttrs>() {}
20 changes: 20 additions & 0 deletions src/domain/entities/incident-action-plan/ResponseAction.ts
Original file line number Diff line number Diff line change
@@ -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<ResponseActionAttrs>() {}
Original file line number Diff line number Diff line change
@@ -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<IncidentManagementTeamAttrs>() {}
21 changes: 21 additions & 0 deletions src/domain/entities/incident-management-team/TeamMember.ts
Original file line number Diff line number Diff line change
@@ -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<TeamMemberAttrs>() {
static validatePhAndEmail() {
//TO DO : any validations for phone number?
//TO DO : any validations for email?
}
}
12 changes: 12 additions & 0 deletions src/domain/entities/risk-assessment/RiskAssessment.ts
Original file line number Diff line number Diff line change
@@ -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<RiskAssessmentAttrs>() {}
118 changes: 118 additions & 0 deletions src/domain/entities/risk-assessment/RiskAssessmentGrading.ts
Original file line number Diff line number Diff line change
@@ -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<RiskAssessmentGradingAttrs>() {
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";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Property } from "../Properties";
import { Struct } from "../generic/Struct";

interface RiskAssessmentQuestionnaireAttrs {
questions: Property[];
}

export class RiskAssessmentQuestionnaire extends Struct<RiskAssessmentQuestionnaireAttrs>() {}
8 changes: 8 additions & 0 deletions src/domain/entities/risk-assessment/RiskAssessmentSummary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Property } from "../Properties";
import { Struct } from "../generic/Struct";

interface RiskAssessmentSummaryAttrs {
properties: Property[];
}

export class RiskAssessmentSummary extends Struct<RiskAssessmentSummaryAttrs>() {}
Loading

0 comments on commit 2f7013f

Please sign in to comment.