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

Feature/query management #1818

Merged
merged 13 commits into from
Dec 16, 2024
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hmcts/ccd-case-ui-toolkit",
"version": "7.1.15-fix-event-hiding",
"version": "7.1.22",
"engines": {
"node": ">=18.19.0"
},
Expand Down
2 changes: 1 addition & 1 deletion projects/ccd-case-ui-toolkit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hmcts/ccd-case-ui-toolkit",
"version": "7.1.15-fix-event-hiding",
"version": "7.1.22",
"engines": {
"node": ">=18.19.0"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ export class PageValidationService {
public getInvalidFields(page: WizardPage, editForm: FormGroup): CaseField[] {
const failingCaseFields = [];
page.case_fields
.filter(caseField => !this.caseFieldService.isReadOnly(caseField))
.filter(caseField => !this.isHidden(caseField, editForm))
.forEach(caseField => {
.filter((caseField) => !this.caseFieldService.isReadOnly(caseField))
.filter((caseField) => !this.isHidden(caseField, editForm))
.forEach((caseField) => {
const theControl = FieldsUtils.isCaseFieldOfType(caseField, ['JudicialUser'])
? editForm.controls['data'].get(`${caseField.id}_judicialUserControl`)
: editForm.controls['data'].get(caseField.id);
? editForm.controls.data.get(`${caseField.id}_judicialUserControl`)
: editForm.controls.data.get(caseField.id);
if (!(this.checkDocumentField(caseField, theControl) && this.checkOptionalField(caseField, theControl))) {
failingCaseFields.push(caseField);
};
}
});
return failingCaseFields;
}
Expand All @@ -46,9 +46,8 @@ export class PageValidationService {
private checkOptionalField(caseField: CaseField, theControl: AbstractControl): boolean {
if (!theControl) {
return this.caseFieldService.isOptional(caseField);
} else {
return theControl.valid || theControl.disabled;
}
return theControl.valid || theControl.disabled;
}

private checkMandatoryField(caseField: CaseField, theControl: AbstractControl): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,25 @@ import { Draft } from '../../domain/draft.model';
})

export class CaseHeaderComponent implements OnInit {
@Input() public caseDetails: CaseView;

@Input()
public caseDetails: CaseView;
public caseTitle: CaseField;
public caseFields: CaseField[];

public ngOnInit(): void {
this.caseTitle = new CaseField();
this.caseTitle.label = this.caseDetails.state.title_display;
this.caseFields = this.getCaseFieldsInfo();
if (!this.isDraft() && this.caseDetails.state.title_display) {
this.caseTitle.label = this.caseDetails.state.title_display;
this.caseFields = this.getCaseFields();
}
}

public isDraft(): boolean {
return Draft.isDraft(this.caseDetails.case_id);
}

private getCaseFieldsInfo(): CaseField[] {
private getCaseFields(): CaseField[] {
const caseDataFields = this.caseDetails.tabs.reduce((acc, tab) => {
return acc.concat(tab.fields);
}, []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,24 +98,6 @@ export class SelectFlagTypeComponent implements OnInit, OnDestroy {
}
);

this.formGroup.addControl(CaseFlagFormFields.FLAG_TYPE, new FormControl(''));
this.formGroup.addControl(CaseFlagFormFields.OTHER_FLAG_DESCRIPTION, new FormControl(''));
this.formGroup.addControl(CaseFlagFormFields.IS_VISIBLE_INTERNALLY_ONLY, new FormControl(''));

// Should clear descriptionControlName if flagTypeControlName is changed
this.flagTypeControlChangesSubscription = this.formGroup.get(CaseFlagFormFields.FLAG_TYPE).valueChanges
.subscribe(_ => {
this.formGroup.get(CaseFlagFormFields.OTHER_FLAG_DESCRIPTION).setValue('');
this.cachedPath = [];

// required to clear language interpreter
this.formGroup.patchValue({
[SearchLanguageInterpreterControlNames.LANGUAGE_SEARCH_TERM]: '',
[SearchLanguageInterpreterControlNames.MANUAL_LANGUAGE_ENTRY]: ''
});
}
);

// If hmctsServiceId is present, use this to retrieve the relevant list of flag types
if (this.hmctsServiceId) {
this.flagRefdata$ = this.caseFlagRefdataService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ <h2 class="govuk-heading-m govuk-!-margin-top-10">
type="radio" [formControl]="qualifyingQuestionsControl" [value]="qualifyingQuestion">
<label class="govuk-label govuk-radios__label" [for]="qualifyingQuestion.name">{{ qualifyingQuestion.name |
rpxTranslate }}</label>
<div *ngIf="isLast" class="govuk-hint govuk-radios__hint">
{{ '(To follow-up on an existing query' | rpxTranslate }}
<a class="govuk-link" href="javascript:void(0)" (click)="click()">{{ 'click here' | rpxTranslate }}</a>.)
</div>
</div>
</ng-container>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe('QualifyingQuestionOptionsComponent', () => {

it('should have the link to case details queries tab', () => {
component.click();
expect(router.navigate).toHaveBeenCalledWith(['cases', 'case-details', '12345'], { fragment: 'Query Management' });
expect(router.navigate).toHaveBeenCalledWith(['cases', 'case-details', '12345'], { fragment: 'Queries' });
});

describe('displayError', () => {
Expand Down Expand Up @@ -109,5 +109,15 @@ describe('QualifyingQuestionOptionsComponent', () => {
expect(errorMessageEl).toBeTruthy();
expect(errorMessageEl.nativeElement.textContent.trim()).toBe(`Error: ${QualifyingQuestionsErrorMessage.SELECT_AN_OPTION}`);
});

it('should initialize qualifyingQuestionsControl with saved selection if available', () => {
const savedSelection = 'saved-option';
qualifyingQuestionService.getQualifyingQuestionSelection.and.returnValue(savedSelection);

component.ngOnInit();

expect(qualifyingQuestionService.getQualifyingQuestionSelection).toHaveBeenCalled();
expect(component.qualifyingQuestionsControl.value).toBe(savedSelection);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class QualifyingQuestionOptionsComponent implements OnInit {
}

public click(): void {
this.router.navigate(['cases', 'case-details', this.caseId], { fragment: 'Query Management' });
this.router.navigate(['cases', 'case-details', this.caseId], { fragment: 'Queries' });
}

public get displayError(): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,24 @@
import { Component, Input, OnInit } from '@angular/core';
import { CaseView } from '../../../../../domain/case-view/case-view.model';
import { CaseField } from '../../../../../domain/definition/case-field.model';
import { Draft } from '../../../../../domain/draft.model';
import { ActivatedRoute } from '@angular/router';

@Component({
selector: 'ccd-query-case-details-header',
templateUrl: './query-case-details-header.component.html'
})

export class QueryCaseDetailsHeaderComponent implements OnInit {
@Input()
public caseDetails: CaseView;
@Input() public caseDetails: CaseView;
public caseTitle: CaseField;
public caseFields: CaseField[];
public caseView: CaseView;

constructor(activatedRoute: ActivatedRoute) {
this.caseView = activatedRoute.snapshot.data.case;
}

public ngOnInit(): void {
this.caseTitle = new CaseField();
if (!this.isDraft() && this.caseDetails.state.title_display) {
this.caseTitle.label = this.caseDetails.state.title_display;
this.caseFields = this.getCaseFields();
}
}

public isDraft(): boolean {
return Draft.isDraft(this.caseDetails.case_id);
this.caseTitle.label = this.caseDetails.state.title_display;
this.caseFields = this.getCaseFieldsInfo();
}

private getCaseFields(): CaseField[] {
private getCaseFieldsInfo(): CaseField[] {
const caseDataFields = this.caseDetails.tabs.reduce((acc, tab) => {
return acc.concat(tab.fields);
}, []);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum QueryItemResponseStatus {
NEW = 'New',
RESPONDED = 'Responded'
RESPONDED = 'Responded',
AWAITING = 'Awaiting Response'
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ describe('QueryListItem', () => {
hearingDate: '',
createdOn: new Date('2023-06-01'),
createdBy: 'Person D',
parentId: '444-444',
parentId: '444-444'
}
];

const childrenItems = items.map(item => {
const childrenItems = items.map((item) => {
const listItem = new QueryListItem();
Object.assign(listItem, item);
return listItem;
Expand Down Expand Up @@ -163,7 +163,37 @@ describe('QueryListItem', () => {
it('should return "No response required" when it has no children', () => {
queryListItem.children = [];
expect(queryListItem.children).toEqual([]);
expect(queryListItem.responseStatus).toEqual(QueryItemResponseStatus.NEW);
expect(queryListItem.responseStatus).toEqual(QueryItemResponseStatus.AWAITING);
});

it('should return "Awaiting Response" when it has children and is for Follow up question', () => {
// Create additional child items
const additionalChildren = [
new QueryListItem(),
new QueryListItem(),
new QueryListItem(),
new QueryListItem()
].map((child, index) => {
Object.assign(child, {
id: `child-${index + 1}`,
subject: `Subject ${index + 2}`,
name: `Name ${index + 2}`,
body: `Body ${index + 2}`,
attachments: [],
isHearingRelated: false,
hearingDate: '',
createdOn: new Date(`2021-0${index + 2}-01`),
createdBy: `Person ${String.fromCharCode(65 + index + 1)}`,
parentId: queryListItem.id,
children: []
});
return child;
});

// Assign these new children to queryListItem
queryListItem.children = additionalChildren;
expect(queryListItem.children.length).toEqual(4);
expect(queryListItem.responseStatus).toEqual(QueryItemResponseStatus.AWAITING);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export class QueryListItem implements CaseMessage {
}

public get responseStatus(): QueryItemResponseStatus {
return this.children?.length > 0 ? QueryItemResponseStatus.RESPONDED : QueryItemResponseStatus.NEW;
if (this.children?.length > 0) {
return this.children.length % 2 === 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we find a more robust way of determining if this is responded or new, for example using the associated user Id, or the status of the message or perhaps a change to the data?

? QueryItemResponseStatus.RESPONDED
: QueryItemResponseStatus.AWAITING;
}
return QueryItemResponseStatus.AWAITING;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export class JurisdictionService {
}

public announceSelectedJurisdiction(jurisdiction: Jurisdiction): void {
console.info ('Announcing selected jurisdiction = ' + jurisdiction?.id);
this.selectedJurisdictionSource.next(jurisdiction);
this.selectedJurisdictionBS.next(jurisdiction);
}
Expand Down
Loading