Skip to content

Commit

Permalink
adding an option to disable blue patients (#405)
Browse files Browse the repository at this point in the history
* adding an option to disable blue patients

* fixing merge problems
  • Loading branch information
hpistudent72 committed May 29, 2022
1 parent b921aff commit 9f743a3
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ <h5 class="popover-header">
[ngModel]="patientStatus$ | async"
(ngModelChange)="setPretriageCategory($event)"
>
<option [value]="'black'">EX</option>
<option [value]="'blue'">SK IV</option>
<option [value]="'red'">SK I</option>
<option [value]="'yellow'">SK II</option>
<option [value]="'green'">SK III</option>
<option
*ngFor="let option of pretriageOptions$ | async"
[value]="option"
>
{{ statusNames[option] }}
</option>
</select>
</td>
</tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import {
statusNames,
Patient,
} from 'digital-fuesim-manv-shared';
import { map } from 'rxjs';
import type { Observable } from 'rxjs';
import { ApiService } from 'src/app/core/api.service';
import type { AppState } from 'src/app/state/app.state';
import {
selectPretriageEnabledConfiguration,
getSelectClient,
getSelectPatient,
selectBluePatientsEnabledConfiguration,
} from 'src/app/state/exercise/exercise.selectors';
import type { PopupComponent } from '../../utility/popup-manager';

Expand All @@ -40,8 +42,17 @@ export class PatientPopupComponent implements PopupComponent, OnInit {
public pretriageEnabled$ = this.store.select(
selectPretriageEnabledConfiguration
);

private readonly secondsUntilRealStatus = 5;
public bluePatientsEnabled$ = this.store.select(
selectBluePatientsEnabledConfiguration
);
public readonly pretriageOptions$: Observable<PatientStatus[]> =
this.bluePatientsEnabled$.pipe(
map((bluePatientFlag) =>
bluePatientFlag
? ['black', 'blue', 'red', 'yellow', 'green']
: ['black', 'red', 'yellow', 'green']
)
);

// To use it in the template
public readonly healthPointsDefaults = healthPointsDefaults;
Expand All @@ -57,8 +68,13 @@ export class PatientPopupComponent implements PopupComponent, OnInit {
createSelector(
getSelectPatient(this.patientId),
selectPretriageEnabledConfiguration,
(patient, pretriageEnabled) =>
Patient.getVisibleStatus(patient, pretriageEnabled)
selectBluePatientsEnabledConfiguration,
(patient, pretriageEnabled, bluePatientsEnabled) =>
Patient.getVisibleStatus(
patient,
pretriageEnabled,
bluePatientsEnabled
)
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ <h4 class="modal-title">Einstellungen</h4>
type="checkbox"
/>
</div>
Mit SK IV Patienten üben?
<div class="form-switch">
<input
[ngModel]="bluePatientsFlag$ | async"
(ngModelChange)="setBluePatientsFlag($event)"
class="form-check-input"
type="checkbox"
/>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ApiService } from 'src/app/core/api.service';
import type { AppState } from 'src/app/state/app.state';
import {
selectPretriageEnabledConfiguration,
selectBluePatientsEnabledConfiguration,
selectTileMapProperties,
} from 'src/app/state/exercise/exercise.selectors';
import { getStateSnapshot } from 'src/app/state/get-state-snapshot';
Expand All @@ -25,6 +26,9 @@ export class ExerciseSettingsModalComponent {
public pretriageFlag$ = this.store.select(
selectPretriageEnabledConfiguration
);
public bluePatientsFlag$ = this.store.select(
selectBluePatientsEnabledConfiguration
);

constructor(
private readonly store: Store<AppState>,
Expand All @@ -50,6 +54,13 @@ export class ExerciseSettingsModalComponent {
});
}

public setBluePatientsFlag(flag: boolean) {
this.apiService.proposeAction({
type: '[ExerciseSettings] Set Blue Patients Flag',
bluePatientsEnabled: flag,
});
}

public close() {
this.activeModal.close();
}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/app/state/exercise/exercise.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export const selectTileMapProperties = (state: AppState) =>
state.exercise.tileMapProperties;
export const selectPretriageEnabledConfiguration = (state: AppState) =>
state.exercise.configuration.pretriageEnabled;
export const selectBluePatientsEnabledConfiguration = (state: AppState) =>
state.exercise.configuration.bluePatientsEnabled;
/**
* @returns a selector that returns a dictionary of all elements that have a position and are in the viewport restriction
*/
Expand Down
15 changes: 10 additions & 5 deletions shared/src/models/patient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,16 @@ export class Patient {

static readonly msUntilRealStatus: number = 120_000;

static getVisibleStatus(patient: Patient, pretriageEnabled: boolean) {
return !pretriageEnabled ||
patient.treatmentTime >= this.msUntilRealStatus
? patient.realStatus
: patient.pretriageStatus;
static getVisibleStatus(
patient: Patient,
pretriageEnabled: boolean,
bluePatientsEnabled: boolean
) {
const status =
!pretriageEnabled || patient.treatmentTime >= this.msUntilRealStatus
? patient.realStatus
: patient.pretriageStatus;
return status === 'blue' && !bluePatientsEnabled ? 'red' : status;
}

static isInVehicle(patient: Patient): boolean {
Expand Down
19 changes: 19 additions & 0 deletions shared/src/store/action-reducers/exercise-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ export class SetPretriageFlagAction implements Action {
public readonly pretriageEnabled!: boolean;
}

export class SetBluePatientsFlagAction implements Action {
@IsString()
public readonly type = '[ExerciseSettings] Set Blue Patients Flag';

@IsBoolean()
public readonly bluePatientsEnabled!: boolean;
}

export namespace ExerciseSettingsActionReducers {
export const setTileMapProperties: ActionReducer<SetTileMapPropertiesAction> =
{
Expand All @@ -39,4 +47,15 @@ export namespace ExerciseSettingsActionReducers {
},
rights: 'trainer',
};

export const setBluePatientsFlag: ActionReducer<SetBluePatientsFlagAction> =
{
action: SetBluePatientsFlagAction,
reducer: (draftState, { bluePatientsEnabled }) => {
draftState.configuration.bluePatientsEnabled =
bluePatientsEnabled;
return draftState;
},
rights: 'trainer',
};
}
95 changes: 81 additions & 14 deletions shared/src/store/action-reducers/utils/calculate-treatments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,22 @@ function caterFor(
catering: Mutable<Material> | Mutable<Personnel>,
catersFor: Mutable<CatersFor>,
patient: Mutable<Patient>,
pretriageEnabled: boolean
pretriageEnabled: boolean,
bluePatientsEnabled: boolean
) {
// Treat not pretriaged patients as yellow.
const status =
Patient.getVisibleStatus(patient, pretriageEnabled) === 'white'
Patient.getVisibleStatus(
patient,
pretriageEnabled,
bluePatientsEnabled
) === 'white'
? 'yellow'
: Patient.getVisibleStatus(patient, pretriageEnabled);
: Patient.getVisibleStatus(
patient,
pretriageEnabled,
bluePatientsEnabled
);
if (
(status === 'red' && catering.canCaterFor.red <= catersFor.red) ||
(status === 'yellow' &&
Expand Down Expand Up @@ -77,6 +86,7 @@ function caterFor(

export function calculateTreatments(state: Mutable<ExerciseState>) {
const pretriageEnabled = state.configuration.pretriageEnabled;
const bluePatientsEnabled = state.configuration.bluePatientsEnabled;
const personnels = Object.values(state.personnel).filter(
(personnel) => personnel.position !== undefined
);
Expand All @@ -93,8 +103,16 @@ export function calculateTreatments(state: Mutable<ExerciseState>) {
const patients = Object.values(state.patients).filter(
(patient) =>
patient.position !== undefined &&
Patient.getVisibleStatus(patient, pretriageEnabled) !== 'black' &&
Patient.getVisibleStatus(patient, pretriageEnabled) !== 'blue'
Patient.getVisibleStatus(
patient,
pretriageEnabled,
bluePatientsEnabled
) !== 'black' &&
Patient.getVisibleStatus(
patient,
pretriageEnabled,
bluePatientsEnabled
) !== 'blue'
);
patients.forEach((patient) => {
patient.isBeingTreated = false;
Expand All @@ -106,17 +124,28 @@ export function calculateTreatments(state: Mutable<ExerciseState>) {
// We ignore whether a patient is already treated
// and the patient is just added to the list of treated patients.
personnels.forEach((personnel) => {
calculateCatering(personnel, patients, pretriageEnabled);
calculateCatering(
personnel,
patients,
pretriageEnabled,
bluePatientsEnabled
);
});
materials.forEach((material) => {
calculateCatering(material, patients, pretriageEnabled);
calculateCatering(
material,
patients,
pretriageEnabled,
bluePatientsEnabled
);
});
}

function calculateCatering(
catering: Material | Personnel,
patients: Mutable<Patient>[],
pretriageEnabled: boolean
pretriageEnabled: boolean,
bluePatientsEnabled: boolean
) {
const catersFor: CatersFor = {
red: 0,
Expand All @@ -138,7 +167,13 @@ function calculateCatering(
return;
}
if (distances[0].distance <= specificThreshold) {
caterFor(catering, catersFor, distances[0].patient, pretriageEnabled);
caterFor(
catering,
catersFor,
distances[0].patient,
pretriageEnabled,
bluePatientsEnabled
);
}
// The typings of groupBy are not correct (group keys could be missing if there are no such elements in the array)
const distancesByStatus: Partial<
Expand All @@ -153,9 +188,17 @@ function calculateCatering(
> = groupBy(
distances,
({ patient }) =>
Patient.getVisibleStatus(patient, pretriageEnabled) === 'white'
Patient.getVisibleStatus(
patient,
pretriageEnabled,
bluePatientsEnabled
) === 'white'
? 'yellow'
: Patient.getVisibleStatus(patient, pretriageEnabled) // Treat untriaged patients as yellow
: Patient.getVisibleStatus(
patient,
pretriageEnabled,
bluePatientsEnabled
) // Treat untriaged patients as yellow
);

const redPatients =
Expand Down Expand Up @@ -183,19 +226,43 @@ function calculateCatering(
.map(({ patient }) => patient) ?? [];

for (const patient of redPatients) {
if (!caterFor(catering, catersFor, patient, pretriageEnabled)) {
if (
!caterFor(
catering,
catersFor,
patient,
pretriageEnabled,
bluePatientsEnabled
)
) {
break;
}
}

for (const patient of yellowPatients) {
if (!caterFor(catering, catersFor, patient, pretriageEnabled)) {
if (
!caterFor(
catering,
catersFor,
patient,
pretriageEnabled,
bluePatientsEnabled
)
) {
break;
}
}

for (const patient of greenPatients) {
if (!caterFor(catering, catersFor, patient, pretriageEnabled)) {
if (
!caterFor(
catering,
catersFor,
patient,
pretriageEnabled,
bluePatientsEnabled
)
) {
break;
}
}
Expand Down
1 change: 1 addition & 0 deletions shared/src/utils/exercise-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getCreate } from '../models/utils';

export class ExerciseConfiguration {
public readonly pretriageEnabled: boolean = true;
public readonly bluePatientsEnabled: boolean = false;

static readonly create = getCreate(this);
}

0 comments on commit 9f743a3

Please sign in to comment.