Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VIH-11046 Added restrictions to screening participants and endpoints #1433

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,15 @@
</div>
</div>
</ng-container>

<div *ngIf="newParticipantRemovedFromOptions">
<div class="govuk-warning-text">
<span aria-hidden="true" class="govuk-warning-text__icon">!</span>
<strong class="govuk-warning-text__text">
<span class="govuk-warning-text__assistive">Warning</span>
New participants and endpoints cannot be included in screening options, without being saved first.
</strong>
</div>
</div>
<button
*ngIf="form.value.displayName"
type="submit"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@ describe('ScreeningFormComponent', () => {
const endpoint1 = new EndpointModel();
endpoint1.id = '3';
endpoint1.displayName = 'Endpoint 1';
endpoint1.sip = 'sip1';

const endpoint2 = new EndpointModel();
endpoint2.id = '4';
endpoint2.displayName = 'Endpoint 2';
endpoint2.sip = 'sip2';

hearing.participants = [participant1, participant2];
hearing.endpoints = [endpoint1, endpoint2];
hearing.hearing_id = null; //new hearing

loggerSpy = jasmine.createSpyObj('Logger', ['debug']);
await TestBed.configureTestingModule({
Expand All @@ -47,6 +50,8 @@ describe('ScreeningFormComponent', () => {
component = fixture.componentInstance;
component.hearing = hearing;
fixture.detectChanges();
component.newParticipantRemovedFromOptions = false;
component.isEditMode = false;
});

it('init component from input on create', () => {
Expand Down Expand Up @@ -113,4 +118,34 @@ describe('ScreeningFormComponent', () => {
expect(component.displayProtectFromList).toBeFalse();
});
});

describe('filtering selectable participants for screening', () => {
it('should exclude newly added participants from screening options', () => {
// Arrange
hearing.hearing_id = '1'; // isEditMode = true
const newlyAddedParticipant = hearing.participants[0];
const newlyAddedEndpoint = hearing.endpoints[0];
newlyAddedParticipant.id = undefined;
newlyAddedEndpoint.sip = undefined;

// Act
component.hearing = hearing;

// Assert
expect(component.allParticipants.filter(p => p.displayName === newlyAddedParticipant.display_name)).toEqual([]);
expect(component.allParticipants.filter(p => p.displayName === newlyAddedEndpoint.displayName)).toEqual([]);
expect(component.allParticipants.length).toBe(2);
expect(component.newParticipantRemovedFromOptions).toBeTrue();
});

it('should include existing participant in screening options', () => {
// Arrange
hearing.hearing_id = '1'; // isEditMode = true
// Act
component.hearing = hearing;
// Assert
expect(component.allParticipants.length).toBe(4);
expect(component.newParticipantRemovedFromOptions).toBeFalse();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,57 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angu
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { Subject, takeUntil } from 'rxjs';
import { HearingModel } from 'src/app/common/model/hearing.model';
import { Logger } from 'src/app/services/logger';
import { ProtectFrom, SelectedScreeningDto, ScreeningType } from './screening.model';
import { ProtectFrom, ScreeningType, SelectedScreeningDto } from './screening.model';

@Component({
selector: 'app-screening-form',
templateUrl: './screening-form.component.html'
})
export class ScreeningFormComponent {
isEditMode = false;
newParticipantRemovedFromOptions = false;

constructor(private formBuilder: FormBuilder, private cdRef: ChangeDetectorRef) {}

@Output() screeningSaved = new EventEmitter<SelectedScreeningDto>();

displayMeasureType = false;
displayProtectFromList = false;
allParticipants: GenericParticipantsModel[];
availableProtectParticipantFromList: GenericParticipantsModel[] = [];
selectedProtectParticipantFromList: GenericParticipantsModel[] = [];

destroyed$ = new Subject<void>();
form: FormGroup<ScreeningSelectParticipantForm>;

@Input() set hearing(hearing: HearingModel) {
const mappedParticipants = hearing.participants
.filter(x => x.email)
.map(
participant =>
({
displayName: participant.display_name,
externalReferenceId: participant.externalReferenceId
externalReferenceId: participant.externalReferenceId,
isNewlyAdded: participant.id === null || participant.id === undefined
} as GenericParticipantsModel)
);

const mappedEndpoints = hearing.endpoints.map(
endpoint =>
({
displayName: endpoint.displayName,
externalReferenceId: endpoint.externalReferenceId
externalReferenceId: endpoint.externalReferenceId,
isNewlyAdded: endpoint.sip === null || endpoint.sip === undefined
} as GenericParticipantsModel)
);

this.allParticipants = [...mappedParticipants, ...mappedEndpoints];
this.isEditMode = hearing.hearing_id !== null && hearing.hearing_id !== undefined;
this.allParticipants = [...mappedParticipants, ...mappedEndpoints].filter(participant =>
this.includeParticipantInScreeningOptions(participant)
);
this.createForm();
this.cdRef.detectChanges();
}

@Output() screeningSaved = new EventEmitter<SelectedScreeningDto>();

displayMeasureType = false;
displayProtectFromList = false;
allParticipants: GenericParticipantsModel[];
availableProtectParticipantFromList: GenericParticipantsModel[] = [];
selectedProtectParticipantFromList: GenericParticipantsModel[] = [];

destroyed$ = new Subject<void>();
form: FormGroup<ScreeningSelectParticipantForm>;

constructor(private formBuilder: FormBuilder, private cdRef: ChangeDetectorRef, private logger: Logger) {}

createForm() {
this.form = this.formBuilder.group<ScreeningSelectParticipantForm>({
displayName: new FormControl(null),
Expand All @@ -69,19 +75,19 @@ export class ScreeningFormComponent {
onMeasureTypeSelected(measureType: ScreeningType, participantDisplayName: string) {
this.displayProtectFromList = measureType === 'Specific';
if (measureType === 'Specific') {
const particpant = this.allParticipants.find(participant => participant.displayName === participantDisplayName);
this.initaliseScreening(particpant.displayName);
const participantsModel = this.allParticipants.find(participant => participant.displayName === participantDisplayName);
this.initialiseScreening(participantsModel.displayName);
this.selectedProtectParticipantFromList = [];
}
}

onParticipantSelected(displayName: string): void {
this.displayMeasureType = false;
this.initaliseScreening(displayName);
this.initialiseScreening(displayName);
this.selectedProtectParticipantFromList = [];
}

initaliseScreening(displayName: string) {
initialiseScreening(displayName: string) {
this.availableProtectParticipantFromList = this.allParticipants.filter(participant => participant.displayName !== displayName);
}

Expand All @@ -99,6 +105,18 @@ export class ScreeningFormComponent {
this.displayMeasureType = false;
this.displayProtectFromList = false;
}

/// VIH-11046: due to the way updating a hearing orchestrates updating participants and endpoints in two separate requests to the booking-api,
// we need to restrict the ability to add a screening link between a newly added participant and newly added endpoints else the id won't be available to link the two.
// The user needs to save booking first then add a screening option.
// this can be removed in future if the way we change how updating hearing participants works.
private includeParticipantInScreeningOptions(participant: GenericParticipantsModel): boolean {
if (this.isEditMode && participant.isNewlyAdded) {
this.newParticipantRemovedFromOptions = true;
return false;
}
return true;
}
}

interface ScreeningSelectParticipantForm {
Expand All @@ -109,4 +127,5 @@ interface ScreeningSelectParticipantForm {
interface GenericParticipantsModel {
displayName: string;
externalReferenceId: string;
isNewlyAdded: boolean;
}
Loading