From 3269b255c0411bd20747d97f320ca3b721c6ba26 Mon Sep 17 00:00:00 2001 From: Thomas Crawley Date: Fri, 5 Apr 2024 15:12:19 +0100 Subject: [PATCH] feat/CB2-10033 - Additional Examiner Note (#1448) * feat(cb2-10241): update adr notes to use custom component * feat(cb2-11250): format table * feat(cb2-11250): set up router link * feat(cb2-11250): blank page link working * feat(cb2-11250): revert unnecessary changes * feat(cb2-11250): amend routing function * feat(cb2-11250): fix linting and add unit test * feat(cb2-11250): fix linting and add unit test * feat(cb2-11250): update link design * feat(cb2-11250): fix button link styling * feat(cb2-10033): basic setup and grabbed selected note from record * feat(cb2-10033): stash for mobbing * feat(cb2-10033): hook form up to display note which is to be edited * feat(cb2-10033): set up model binding to component * feat(cb2-10033): use correct directive and basic form validation * feat(cb2-10033): amend routing title for notifiable alteration * feat(cb2-10033): remove validation as requirements confirmed not needed * feat(cb2-10033): implement state management solution * feat(cb2-10033): fix display for summary screen * feat(cb2-10033): refactor state and data handling approach * feat(cb2-10033): reducer tests * feat(cb2-10033): basic unit testing draft * feat(cb2-10033): unit testing * feat(cb2-10033): linting fix * feat(cb2-10033): fix review screen * feat(cb2-10033): git stash for mobbing * feat(cb2-10033): add logic to hide collapse function and fix missing acs * feat(cb2-10033): move title from component to templates * feat(cb2-10033): acordion issues solved --------- Co-authored-by: Brandon Thomas-Davies <87308252+BrandonT95@users.noreply.github.com> Co-authored-by: Tom Evans Co-authored-by: Thomas Evans <36958694+tomevs88@users.noreply.github.com> --- ...it-additional-examiner-note.component.html | 32 +++++- ...it-additional-examiner-note.component.scss | 8 ++ ...additional-examiner-note.component.spec.ts | 70 ++++++++++-- ...edit-additional-examiner-note.component.ts | 102 +++++++++++++++++- .../tech-record/tech-record-routing.module.ts | 14 ++- ...examiner-notes-history-edit.component.html | 2 +- ...examiner-notes-history-view.component.html | 10 +- ...miner-notes-history-view.component.spec.ts | 4 + ...r-examiner-notes-history-view.component.ts | 10 +- .../templates/general/adr-summary.template.ts | 9 +- .../forms/templates/general/adr.template.ts | 7 ++ .../collapsible-text.component.html | 28 +++++ .../collapsible-text.component.scss | 0 .../collapsible-text.component.spec.ts | 37 +++++++ .../collapsible-text.component.ts | 44 ++++++++ src/app/shared/shared.module.ts | 3 + .../technical-record-service.actions.ts | 7 +- .../technical-record-service.reducer.spec.ts | 27 ++++- .../technical-record-service.reducer.ts | 18 +++- 19 files changed, 410 insertions(+), 22 deletions(-) create mode 100644 src/app/shared/components/collapsible-text/collapsible-text.component.html create mode 100644 src/app/shared/components/collapsible-text/collapsible-text.component.scss create mode 100644 src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts create mode 100644 src/app/shared/components/collapsible-text/collapsible-text.component.ts diff --git a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.html b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.html index d2e41facc..5efaac35e 100644 --- a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.html +++ b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.html @@ -1 +1,31 @@ -
This is a blank page right now.
+
+
+
+
+

Edit Additional Examiner Note

+
+ Date + {{ examinerNoteObj.createdAtDate | date: 'dd/MM/yyyy' | defaultNullOrEmpty }} + Created by + {{ examinerNoteObj.lastUpdatedBy }} +
+
+
+ + +
+
+
+
+
+ + Save + Cancel + +
diff --git a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.scss b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.scss index e69de29bb..bd6134d76 100644 --- a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.scss +++ b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.scss @@ -0,0 +1,8 @@ +.parent-div { + display: flex; + flex-direction: row; +} +.table-value { + margin-left: 1%; + margin-right: 1%; +} diff --git a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.spec.ts b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.spec.ts index 65bf1af72..6568ebf89 100644 --- a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.spec.ts @@ -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 = { @@ -18,6 +16,11 @@ const mockTechRecordService = { describe('TechRecordEditAdditionalExaminerNoteComponent', () => { let fixture: ComponentFixture; let component: TechRecordEditAdditionalExaminerNoteComponent; + let router: Router; + let errorService: GlobalErrorService; + let route: ActivatedRoute; + let store: MockStore; + beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [TechRecordEditAdditionalExaminerNoteComponent], @@ -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(); + }); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.ts b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.ts index b8139fa97..11e117cea 100644 --- a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.ts +++ b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.ts @@ -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(1); + form!: FormGroup; + formControl!: CustomFormControl; + + constructor( + private router: Router, + private route: ActivatedRoute, + private technicalRecordService: TechnicalRecordService, + private globalErrorService: GlobalErrorService, + private store: Store, + ) { } + + 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; + } } diff --git a/src/app/features/tech-record/tech-record-routing.module.ts b/src/app/features/tech-record/tech-record-routing.module.ts index 717d3f920..e56d706ea 100644 --- a/src/app/features/tech-record/tech-record-routing.module.ts +++ b/src/app/features/tech-record/tech-record-routing.module.ts @@ -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, @@ -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], }, { @@ -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, diff --git a/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history-edit.component.html b/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history-edit.component.html index c9c4a9141..b84be43f8 100644 --- a/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history-edit.component.html +++ b/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history-edit.component.html @@ -16,7 +16,7 @@ - {{ examinerNote.note }} + {{ examinerNote.lastUpdatedBy }} diff --git a/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.html b/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.html index fd9a5720a..a8a219e9d 100644 --- a/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.html +++ b/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.html @@ -1,7 +1,6 @@
-

Additional Examiner Notes History

@@ -12,11 +11,16 @@

Additional Examiner Notes History

diff --git a/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.spec.ts b/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.spec.ts index 62814c8b3..3d10b4299 100644 --- a/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.spec.ts +++ b/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.spec.ts @@ -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; @@ -18,6 +20,7 @@ describe('AdrExaminerNotesHistoryViewComponent', () => { const mockTechRecordService = { techRecord$: of({ ...MOCK_HGV }), }; + const mockRouterService = {}; const control = new CustomFormControl({ name: 'techRecord_adrDetails_additionalExaminerNotes', @@ -30,6 +33,7 @@ describe('AdrExaminerNotesHistoryViewComponent', () => { providers: [ provideMockStore({ initialState: initialAppState }), { provide: TechnicalRecordService, useValue: mockTechRecordService }, + { provide: RouterService, useValue: mockRouterService }, { provide: NG_VALUE_ACCESSOR, useExisting: AdrExaminerNotesHistoryViewComponent, multi: true }, { provide: NgControl, diff --git a/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.ts b/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.ts index b49328728..4e12d6f63 100644 --- a/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.ts +++ b/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.ts @@ -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', @@ -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; @@ -33,6 +37,10 @@ export class AdrExaminerNotesHistoryViewComponent extends BaseControlComponent i }); } + get isEditing$(): Observable { + return this.routerService.getRouteDataProperty$('isEditing').pipe(map((isEditing) => !!isEditing)); + } + handlePaginationChange({ start, end }: { start: number; end: number }): void { this.pageStart = start; this.pageEnd = end; diff --git a/src/app/forms/templates/general/adr-summary.template.ts b/src/app/forms/templates/general/adr-summary.template.ts index d54e01d5d..f4c8450ec 100644 --- a/src/app/forms/templates/general/adr-summary.template.ts +++ b/src/app/forms/templates/general/adr-summary.template.ts @@ -757,6 +757,13 @@ export const AdrSummaryTemplate: FormNode = { groups: ['declarations_details', 'dangerous_goods'], hide: true, }, + { + name: 'ExaminerNotesSectionTitle', + label: 'Additional Examiner Notes History', + type: FormNodeTypes.TITLE, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + }, { name: 'techRecord_adrDetails_additionalExaminerNotes_note', label: 'Additional Examiner Notes', @@ -774,7 +781,7 @@ export const AdrSummaryTemplate: FormNode = { label: 'Additional examiner notes history', value: null, type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, + viewType: FormNodeViewTypes.CUSTOM, viewComponent: AdrExaminerNotesHistoryViewComponent, editType: FormNodeEditTypes.CUSTOM, editComponent: AdrExaminerNotesHistoryEditComponent, diff --git a/src/app/forms/templates/general/adr.template.ts b/src/app/forms/templates/general/adr.template.ts index b1a86e219..e87c80792 100644 --- a/src/app/forms/templates/general/adr.template.ts +++ b/src/app/forms/templates/general/adr.template.ts @@ -756,6 +756,13 @@ export const AdrTemplate: FormNode = { groups: ['declarations_details', 'dangerous_goods'], hide: true, }, + { + name: 'ExaminerNotesSectionTitle', + label: 'Additional Examiner Notes History', + type: FormNodeTypes.TITLE, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + }, { name: 'techRecord_adrDetails_additionalExaminerNotes_note', label: 'Additional Examiner Notes', diff --git a/src/app/shared/components/collapsible-text/collapsible-text.component.html b/src/app/shared/components/collapsible-text/collapsible-text.component.html new file mode 100644 index 000000000..a8f098860 --- /dev/null +++ b/src/app/shared/components/collapsible-text/collapsible-text.component.html @@ -0,0 +1,28 @@ + +
+ {{ getCollapsedString() }} +
+ + +
+ +
+ {{ text }} +
+ + +
diff --git a/src/app/shared/components/collapsible-text/collapsible-text.component.scss b/src/app/shared/components/collapsible-text/collapsible-text.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts b/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts new file mode 100644 index 000000000..a7fd6d6e4 --- /dev/null +++ b/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts @@ -0,0 +1,37 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { CollapsibleTextComponent } from './collapsible-text.component'; + +describe('CollapsibleTextComponent', () => { + let component: CollapsibleTextComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [CollapsibleTextComponent], + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CollapsibleTextComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should open when open method is called', () => { + component.isCollapsed = true; + component.open(); + expect(component.isCollapsed).toBe(false); + }); + + it('should close when close method is called', () => { + component.isCollapsed = false; + component.close(); + expect(component.isCollapsed).toBe(true); + }); +}); diff --git a/src/app/shared/components/collapsible-text/collapsible-text.component.ts b/src/app/shared/components/collapsible-text/collapsible-text.component.ts new file mode 100644 index 000000000..37cd9a941 --- /dev/null +++ b/src/app/shared/components/collapsible-text/collapsible-text.component.ts @@ -0,0 +1,44 @@ +import { + ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, +} from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; + +@Component({ + selector: 'collapsible-text', + templateUrl: './collapsible-text.component.html', + styleUrls: ['./collapsible-text.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: CollapsibleTextComponent, + multi: true, + }, + ], +}) +export class CollapsibleTextComponent { + + @Input() text: string = ''; + @Input() maxChars: number = 0; + @Input() isCollapsed = true; + + constructor(private cdr: ChangeDetectorRef) { + } + + getCollapsedString() { + if (this.text.length <= this.maxChars) { + return this.text; + } + return this.text.slice(0, this.maxChars); + } + + open() { + this.isCollapsed = false; + this.cdr.markForCheck(); + } + + close() { + this.isCollapsed = true; + this.cdr.markForCheck(); + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 94f3bf1dd..c812d5629 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -4,6 +4,7 @@ import { RouterModule } from '@angular/router'; import { DocumentRetrievalService } from '@api/document-retrieval'; import { RoleRequiredDirective } from '@directives/app-role-required.directive'; import { FeatureToggleDirective } from '@directives/feature-toggle.directive'; +import { CollapsibleTextComponent } from '@shared/components/collapsible-text/collapsible-text.component'; import { AccordionControlComponent } from './components/accordion-control/accordion-control.component'; import { AccordionComponent } from './components/accordion/accordion.component'; import { BannerComponent } from './components/banner/banner.component'; @@ -54,6 +55,7 @@ import { TyreAxleLoadPipe } from './pipes/tyre-axle-load/tyre-axle-load.pipe'; TyreAxleLoadPipe, GetControlLabelPipe, FormatVehicleTypePipe, + CollapsibleTextComponent, ], imports: [CommonModule, RouterModule], exports: [ @@ -80,6 +82,7 @@ import { TyreAxleLoadPipe } from './pipes/tyre-axle-load/tyre-axle-load.pipe'; TyreAxleLoadPipe, GetControlLabelPipe, FormatVehicleTypePipe, + CollapsibleTextComponent, ], providers: [DocumentRetrievalService], diff --git a/src/app/store/technical-records/actions/technical-record-service.actions.ts b/src/app/store/technical-records/actions/technical-record-service.actions.ts index 21ce91234..3e70e03b7 100644 --- a/src/app/store/technical-records/actions/technical-record-service.actions.ts +++ b/src/app/store/technical-records/actions/technical-record-service.actions.ts @@ -98,7 +98,12 @@ export const clearScrollPosition = createAction(`${prefix} clearScrollPosition`) export const clearADRDetailsBeforeUpdate = createAction(`${prefix} clearADRDetailsBeforeUpdate`); -export const updateADRAdditionalExaminerNotes = createAction(`${prefix} handleADRExaminerNoteChanges`, props<{ username: string }>()); +export const updateADRAdditionalExaminerNotes = createAction(`${prefix} updateADRAdditionalExaminerNotes`, props<{ username: string }>()); + +export const updateExistingADRAdditionalExaminerNote = createAction( + `${prefix} updateExistingADRAdditionalExaminerNote`, + props<{ additionalExaminerNote: string, examinerNoteIndex: number }>(), +); export const generateADRCertificate = createAction(`${prefix} generateADRCertificate`, props<{ systemNumber: string, createdTimestamp: string, certificateType: string diff --git a/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts b/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts index de24eb835..1991ea32f 100644 --- a/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts +++ b/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts @@ -33,7 +33,7 @@ import { updateBody, updateBrakeForces, updateEditingTechRecord, - updateEditingTechRecordCancel, + updateEditingTechRecordCancel, updateExistingADRAdditionalExaminerNote, updateScrollPosition, updateTechRecord, updateTechRecordFailure, @@ -586,4 +586,29 @@ describe('Vehicle Technical Record Reducer', () => { .toContainEqual(testNote); }); }); + describe('handleUpdateExistingADRExaminerNote', () => { + it('should', () => { + const state: TechnicalRecordServiceState = { + ...initialState, + editingTechRecord: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_adrDetails_additionalExaminerNotes: [ + { + note: 'foo', + createdAtDate: 'bar', + lastUpdatedBy: 'foo', + }, + ], + } as unknown as TechRecordType<'put'>, + loading: true, + }; + const newNote = 'foobar'; + const action = updateExistingADRAdditionalExaminerNote({ additionalExaminerNote: newNote, examinerNoteIndex: 0 }); + const newState = vehicleTechRecordReducer(state, action); + const editingTechRecord = newState.editingTechRecord as unknown as (NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>); + expect(editingTechRecord.techRecord_adrDetails_additionalExaminerNotes![0].note).toEqual(newNote); + }); + }); }); diff --git a/src/app/store/technical-records/reducers/technical-record-service.reducer.ts b/src/app/store/technical-records/reducers/technical-record-service.reducer.ts index 2977368d0..908c1241c 100644 --- a/src/app/store/technical-records/reducers/technical-record-service.reducer.ts +++ b/src/app/store/technical-records/reducers/technical-record-service.reducer.ts @@ -61,7 +61,7 @@ import { updateBody, updateBrakeForces, updateEditingTechRecord, - updateEditingTechRecordCancel, + updateEditingTechRecordCancel, updateExistingADRAdditionalExaminerNote, updateScrollPosition, updateTechRecord, updateTechRecordFailure, @@ -153,6 +153,8 @@ export const vehicleTechRecordReducer = createReducer( on(updateADRAdditionalExaminerNotes, (state, action) => handleADRExaminerNoteChanges(state, action.username)), + on(updateExistingADRAdditionalExaminerNote, (state, action) => handleUpdateExistingADRExaminerNote(state, action)), + on(addAxle, (state) => handleAddAxle(state)), on(removeAxle, (state, action) => handleRemoveAxle(state, action)), @@ -547,3 +549,17 @@ function handleADRExaminerNoteChanges(state: TechnicalRecordServiceState, userna } return { ...state, editingTechRecord: additionalNoteTechRecord as unknown as (TechRecordType<'put'>) }; } + +function handleUpdateExistingADRExaminerNote( + state: TechnicalRecordServiceState, + action: { additionalExaminerNote: string, examinerNoteIndex: number }, +) { + const { editingTechRecord } = state; + const editedTechRecord = editingTechRecord as unknown as + (NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>); + if (editedTechRecord) { + const examinerNotes = editedTechRecord.techRecord_adrDetails_additionalExaminerNotes; + examinerNotes![action.examinerNoteIndex].note = action.additionalExaminerNote; + } + return { ...state, editingTechRecord: editingTechRecord as unknown as (TechRecordType<'put'>) }; +}
- {{ result.note }} + + + + + {{ result.note }} + {{ result.lastUpdatedBy }} - {{ result.createdAtDate | date : 'dd/MM/yyyy HH:mm' | defaultNullOrEmpty }} + {{ result.createdAtDate | date: 'dd/MM/yyyy' | defaultNullOrEmpty }}