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

feat/CB2-10033 - Additional Examiner Note #1448

Merged
merged 33 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
059bd49
feat(cb2-10241): update adr notes to use custom component
BrandonT95 Mar 27, 2024
d078144
feat(cb2-11250): format table
tomcrawleyy Mar 27, 2024
ee711c0
feat(cb2-11250): set up router link
tomcrawleyy Mar 27, 2024
491dfa0
feat(cb2-11250): blank page link working
tomcrawleyy Mar 27, 2024
436cc7e
feat(cb2-11250): revert unnecessary changes
tomcrawleyy Mar 27, 2024
8222b11
feat(cb2-11250): amend routing function
tomcrawleyy Mar 27, 2024
71bf1c5
feat(cb2-11250): fix linting and add unit test
tomcrawleyy Mar 28, 2024
1674375
feat(cb2-11250): fix linting and add unit test
tomcrawleyy Mar 28, 2024
aaa721a
feat(cb2-11250): update link design
tomcrawleyy Mar 28, 2024
43cf905
Merge branch 'release/v1.23' into feat/cb2-11250
tomcrawleyy Mar 28, 2024
f558964
feat(cb2-11250): fix button link styling
tomcrawleyy Mar 28, 2024
12cb975
feat(cb2-10033): basic setup and grabbed selected note from record
tomcrawleyy Mar 28, 2024
eba2597
feat(cb2-10033): stash for mobbing
tomcrawleyy Mar 28, 2024
41ad7c3
feat(cb2-10033): hook form up to display note which is to be edited
tomcrawleyy Mar 28, 2024
c5f8445
feat(cb2-10033): set up model binding to component
tomcrawleyy Apr 2, 2024
b22ac5b
feat(cb2-10033): use correct directive and basic form validation
tomcrawleyy Apr 2, 2024
60cddad
feat(cb2-10033): merge holding branch in
tomcrawleyy Apr 2, 2024
39a34d1
feat(cb2-10033): amend routing title for notifiable alteration
tomcrawleyy Apr 2, 2024
887d7b3
feat(cb2-10033): remove validation as requirements confirmed not needed
tomcrawleyy Apr 2, 2024
253f116
feat(cb2-10033): implement state management solution
tomcrawleyy Apr 2, 2024
10a1325
feat(cb2-10033): fix display for summary screen
tomcrawleyy Apr 2, 2024
4769a0a
feat(cb2-10033): refactor state and data handling approach
tomcrawleyy Apr 2, 2024
f525b6d
feat(cb2-10033): reducer tests
tomcrawleyy Apr 2, 2024
17e8ec1
feat(cb2-10033): basic unit testing draft
tomcrawleyy Apr 2, 2024
c06d39e
feat(cb2-10033): unit testing
tomcrawleyy Apr 3, 2024
f44616e
feat(cb2-10033): linting fix
tomcrawleyy Apr 3, 2024
11541af
feat(cb2-10033): rebase against release branch
tomcrawleyy Apr 3, 2024
16fc329
feat(cb2-10033): fix review screen
tomcrawleyy Apr 4, 2024
049c8d3
feat(cb2-10033): git stash for mobbing
tomcrawleyy Apr 4, 2024
a0cb8c9
feat(cb2-10033): add logic to hide collapse function and fix missing acs
tomcrawleyy Apr 5, 2024
5b5a9b9
feat(cb2-10033): move title from component to templates
tomcrawleyy Apr 5, 2024
4cb1819
feat(cb2-10033): acordion issues solved
Apr 5, 2024
95fb0bb
Merge branch 'feature/RELEASE-123' into feat/cb2-10033
tomevs88 Apr 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1,31 @@
<div>This is a blank page right now.</div>
<div *ngIf="currentTechRecord">
<div class="govuk-grid-row">
<div class="govuk-grid-column-full">
<dl class="govuk-summary-list">
<h1 class="govuk-heading-l">Edit Additional Examiner Note</h1>
<div class="parent-div">
<td class="govuk-heading-s">Date</td>
<td class="table-value">{{ examinerNoteObj.createdAtDate | date: 'dd/MM/yyyy' | defaultNullOrEmpty }}</td>
<td class="govuk-heading-s">Created by</td>
<td class="table-value">{{ examinerNoteObj.lastUpdatedBy }}</td>
</div>
<div class="govuk-summary-list__row">
<form [formGroup]="form">
<app-text-area
#examinerNote
formControlName="additionalExaminerNote"
name="AdditionalExaminerNote"
[width]="width.L"
(ngModelChange)="ngOnChanges(examinerNote.value)"
>
</app-text-area>
</form>
</div>
</dl>
</div>
</div>
<app-button-group>
<app-button id="submit-examiner-note" (clicked)="handleSubmit()">Save</app-button>
<app-button id="cancel-amend-examiner-note" design="link" data-module="govuk-button" (clicked)="navigateBack()">Cancel</app-button>
</app-button-group>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.parent-div {
display: flex;
flex-direction: row;
}
.table-value {
margin-left: 1%;
margin-right: 1%;
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {
AdrExaminerNotesHistoryEditComponent,
} from '@forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit';
import { DynamicFormsModule } from '@forms/dynamic-forms.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { TechnicalRecordService } from '@services/technical-record/technical-record.service';
import { provideMockStore } from '@ngrx/store/testing';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { initialAppState } from '@store/index';
import { ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { of } from 'rxjs';
import { GlobalErrorService } from '@core/components/global-error/global-error.service';
import { TechRecordEditAdditionalExaminerNoteComponent } from './tech-record-edit-additional-examiner-note.component';

const mockTechRecordService = {
Expand All @@ -18,6 +16,11 @@ const mockTechRecordService = {
describe('TechRecordEditAdditionalExaminerNoteComponent', () => {
let fixture: ComponentFixture<TechRecordEditAdditionalExaminerNoteComponent>;
let component: TechRecordEditAdditionalExaminerNoteComponent;
let router: Router;
let errorService: GlobalErrorService;
let route: ActivatedRoute;
let store: MockStore;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [TechRecordEditAdditionalExaminerNoteComponent],
Expand All @@ -28,10 +31,65 @@ describe('TechRecordEditAdditionalExaminerNoteComponent', () => {
{ provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } },
],
}).compileComponents();
fixture = TestBed.createComponent(AdrExaminerNotesHistoryEditComponent);
fixture = TestBed.createComponent(TechRecordEditAdditionalExaminerNoteComponent);
component = fixture.componentInstance;
router = TestBed.inject(Router);
errorService = TestBed.inject(GlobalErrorService);
route = TestBed.inject(ActivatedRoute);
store = TestBed.inject(MockStore);
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('ngOnInit', () => {
it('should call all initialisation functions', () => {
const examinerNoteSpy = jest.spyOn(component, 'getExaminerNote').mockReturnValue();
const techRecordSpy = jest.spyOn(component, 'getTechRecord').mockReturnValue();
const formSpy = jest.spyOn(component, 'setupForm').mockReturnValue();
component.ngOnInit();
expect(examinerNoteSpy).toHaveBeenCalled();
expect(formSpy).toHaveBeenCalled();
expect(techRecordSpy).toHaveBeenCalled();
});
});
describe('navigateBack', () => {
it('should clear all errors', () => {
jest.spyOn(router, 'navigate').mockImplementation();

const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors');

component.navigateBack();

expect(clearErrorsSpy).toHaveBeenCalledTimes(1);
});

it('should navigate back to the previous page', () => {
const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true));

component.navigateBack();

expect(navigateSpy).toHaveBeenCalledWith(['../../'], { relativeTo: route });
});
});
describe('handleSubmit', () => {
it('should not dispatch an action if the notes are the same', () => {
const storeSpy = jest.spyOn(store, 'dispatch');
const navigateBackSpy = jest.spyOn(component, 'navigateBack').mockReturnValue();
component.originalExaminerNote = 'foobar';
component.editedExaminerNote = 'foobar';
component.handleSubmit();
expect(storeSpy).not.toHaveBeenCalled();
expect(navigateBackSpy).toHaveBeenCalled();
});

it('should dispatch an action if the notes are not the same', () => {
const storeSpy = jest.spyOn(store, 'dispatch');
const navigateBackSpy = jest.spyOn(component, 'navigateBack').mockReturnValue();
component.originalExaminerNote = 'foo';
component.editedExaminerNote = 'bar';
component.handleSubmit();
expect(storeSpy).toHaveBeenCalled();
expect(navigateBackSpy).toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,108 @@
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { TechnicalRecordService } from '@services/technical-record/technical-record.service';
import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type';
import { ReplaySubject, take, takeUntil } from 'rxjs';
import { GlobalErrorService } from '@core/components/global-error/global-error.service';
import {
CustomFormControl,
FormNodeEditTypes,
FormNodeTypes,
FormNodeWidth,
} from '@forms/services/dynamic-form.types';
import { FormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { State } from '@store/index';
import { updateExistingADRAdditionalExaminerNote } from '@store/technical-records';
import { AdditionalExaminerNotes } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete';

@Component({
selector: 'tech-record-edit-additional-examiner-note',
templateUrl: './tech-record-edit-additional-examiner-note.component.html',
styleUrls: ['./tech-record-edit-additional-examiner-note.component.scss'],
})
export class TechRecordEditAdditionalExaminerNoteComponent {
export class TechRecordEditAdditionalExaminerNoteComponent implements OnInit {
currentTechRecord!: TechRecordType<'hgv' | 'trl' | 'lgv'>;
examinerNoteIndex!: number;
editedExaminerNote: string = '';
originalExaminerNote: string = '';
examinerNoteObj!: AdditionalExaminerNotes;
destroy$ = new ReplaySubject<boolean>(1);
form!: FormGroup;
formControl!: CustomFormControl;

constructor(
private router: Router,
private route: ActivatedRoute,
private technicalRecordService: TechnicalRecordService,
private globalErrorService: GlobalErrorService,
private store: Store<State>,
) { }

ngOnInit() {
this.getTechRecord();
this.getExaminerNote();
this.setupForm();
}

getTechRecord() {
this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((currentTechRecord) => {
this.currentTechRecord = currentTechRecord as TechRecordType<'hgv' | 'lgv' | 'trl'>;
});
}

getExaminerNote() {
this.route.params.pipe(take(1)).subscribe((params) => {
this.examinerNoteIndex = params['examinerNoteIndex'];
});
const additionalExaminerNotes = this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes;
if (additionalExaminerNotes) {
const examinerNote = additionalExaminerNotes[this.examinerNoteIndex].note;
if (examinerNote) {
this.examinerNoteObj = additionalExaminerNotes[this.examinerNoteIndex];
this.originalExaminerNote = examinerNote;
this.editedExaminerNote = examinerNote;
}
}
}

setupForm() {
this.formControl = new CustomFormControl({
name: 'additionalExaminerNote', type: FormNodeTypes.CONTROL,
}, '', [Validators.required]);
this.form = new FormGroup({
additionalExaminerNote: this.formControl,
});
this.formControl.patchValue(this.editedExaminerNote);
}

navigateBack() {
this.globalErrorService.clearErrors();
void this.router.navigate(['../../'], { relativeTo: this.route });
}

handleSubmit(): void {
if (this.originalExaminerNote !== this.editedExaminerNote) {
this.store.dispatch(
updateExistingADRAdditionalExaminerNote({
examinerNoteIndex: this.examinerNoteIndex,
additionalExaminerNote: this.editedExaminerNote,
}),
);
}
this.navigateBack();
}

ngOnChanges(examinerNote: string) {
this.editedExaminerNote = examinerNote;
}

get editTypes(): typeof FormNodeEditTypes {
return FormNodeEditTypes;
}

get width(): typeof FormNodeWidth {
return FormNodeWidth;
}

}
14 changes: 10 additions & 4 deletions src/app/features/tech-record/tech-record-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,17 @@ const routes: Routes = [
{
path: TechRecordRoutes.CORRECT_ERROR_CHANGE_SUMMARY,
component: TechRecordSummaryChangesComponent,
data: { roles: Roles.TechRecordAmend },
data: {
roles: Roles.TechRecordAmend,
isEditing: true,
},
canActivate: [MsalGuard, RoleGuard],
},
{
path: TechRecordRoutes.CORRECT_ERROR_EDIT_ADDITIONAL_EXAMINER_NOTE,
component: TechRecordEditAdditionalExaminerNoteComponent,
data: {
title: 'edit-additional-examiner-note',
title: 'Edit Additional Examiner Note',
roles: Roles.TechRecordAmend,
isEditing: true,
reason: ReasonForEditing.CORRECTING_AN_ERROR,
Expand All @@ -188,7 +191,10 @@ const routes: Routes = [
{
path: TechRecordRoutes.NOTIFIABLE_ALTERATION_NEEDED_CHANGE_SUMMARY,
component: TechRecordSummaryChangesComponent,
data: { roles: Roles.TechRecordAmend },
data: {
roles: Roles.TechRecordAmend,
isEditing: true,
},
canActivate: [MsalGuard, RoleGuard],
},
{
Expand All @@ -207,7 +213,7 @@ const routes: Routes = [
path: TechRecordRoutes.NOTIFIABLE_ALTERNATION_NEEDED_EDIT_ADDITIONAL_EXAMINER_NOTE,
component: TechRecordEditAdditionalExaminerNoteComponent,
data: {
title: 'edit-additional-examiner-note',
title: 'Edit Additional Examiner Note',
roles: Roles.TechRecordAmend,
isEditing: true,
reason: ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<ng-container *ngFor="let examinerNote of currentAdrNotesPage; let i = index; let isLast = last">
<tr class="govuk-table__row" *ngIf="i < 3">
<td class="govuk-table__cell break-words" [class.border-b-0]="i === 2 || isLast">
{{ examinerNote.note }}
<collapsible-text [text]="examinerNote.note ?? ''" [maxChars]="150"></collapsible-text>
</td>
<td class="govuk-table__cell break-words" [class.border-b-0]="i === 2 || isLast">{{ examinerNote.lastUpdatedBy }}</td>
<td class="govuk-table__cell break-words" [class.border-b-0]="i === 2 || isLast">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<ng-container *ngIf="control">
<ng-container *ngIf="adrNotes">
<section class="govuk-!-margin-top-4">
<h3 class="govuk-heading-m">Additional Examiner Notes History</h3>
<table class="govuk-table" *ngIf="adrNotes && adrNotes.length > 0; else empty">
<tbody class="govuk-table__body">
<tr class="govuk-table__row">
Expand All @@ -12,11 +11,16 @@ <h3 class="govuk-heading-m">Additional Examiner Notes History</h3>
<ng-container *ngFor="let result of currentAdrNotesPage; let i = index; let isLast = last">
<tr class="govuk-table__row" *ngIf="i < 3">
<td class="govuk-table__cell break-words" [class.border-b-0]="i === 2 || isLast">
{{ result.note }}
<ng-container *ngIf="(isEditing$ | async) === false">
<collapsible-text [text]="result.note ?? ''" [maxChars]="150"></collapsible-text>
</ng-container>
<ng-container *ngIf="(isEditing$ | async) === true">
{{ result.note }}
</ng-container>
</td>
<td class="govuk-table__cell break-words" [class.border-b-0]="i === 2 || isLast">{{ result.lastUpdatedBy }}</td>
<td class="govuk-table__cell break-words" [class.border-b-0]="i === 2 || isLast">
{{ result.createdAtDate | date : 'dd/MM/yyyy HH:mm' | defaultNullOrEmpty }}
{{ result.createdAtDate | date: 'dd/MM/yyyy' | defaultNullOrEmpty }}
</td>
</tr>
</ng-container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { VehicleTypes } from '@models/vehicle-tech-record.model';
import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type';
import { of } from 'rxjs';
import { AdrExaminerNotesHistoryViewComponent } from './adr-examiner-notes-history-view.component';
import { RouterService } from '@services/router/router.service';


describe('AdrExaminerNotesHistoryViewComponent', () => {
let component: AdrExaminerNotesHistoryViewComponent;
Expand All @@ -18,6 +20,7 @@ describe('AdrExaminerNotesHistoryViewComponent', () => {
const mockTechRecordService = {
techRecord$: of({ ...MOCK_HGV }),
};
const mockRouterService = {};

const control = new CustomFormControl({
name: 'techRecord_adrDetails_additionalExaminerNotes',
Expand All @@ -30,6 +33,7 @@ describe('AdrExaminerNotesHistoryViewComponent', () => {
providers: [
provideMockStore<State>({ initialState: initialAppState }),
{ provide: TechnicalRecordService, useValue: mockTechRecordService },
{ provide: RouterService, useValue: mockRouterService },
{ provide: NG_VALUE_ACCESSOR, useExisting: AdrExaminerNotesHistoryViewComponent, multi: true },
{
provide: NgControl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import { BaseControlComponent } from '@forms/components/base-control/base-contro
import { AdditionalExaminerNotes } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete';
import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type';
import { TechnicalRecordService } from '@services/technical-record/technical-record.service';
import { Subject, takeUntil } from 'rxjs';
import {
map, Observable, Subject, takeUntil,
} from 'rxjs';
import { RouterService } from '@services/router/router.service';

@Component({
selector: 'app-adr-examiner-notes-history-view',
Expand All @@ -22,6 +25,7 @@ import { Subject, takeUntil } from 'rxjs';
})
export class AdrExaminerNotesHistoryViewComponent extends BaseControlComponent implements OnInit, OnDestroy {
technicalRecordService = inject(TechnicalRecordService);
routerService = inject(RouterService);
currentTechRecord?: TechRecordType<'hgv' | 'lgv' | 'trl'> | undefined;
pageStart?: number;
pageEnd?: number;
Expand All @@ -33,6 +37,10 @@ export class AdrExaminerNotesHistoryViewComponent extends BaseControlComponent i
});
}

get isEditing$(): Observable<boolean> {
return this.routerService.getRouteDataProperty$('isEditing').pipe(map((isEditing) => !!isEditing));
}

handlePaginationChange({ start, end }: { start: number; end: number }): void {
this.pageStart = start;
this.pageEnd = end;
Expand Down
Loading
Loading