From 81c9dcfb150303d1082107e9a363579adf16ad91 Mon Sep 17 00:00:00 2001 From: DavidTMann Date: Wed, 8 Jan 2025 13:15:17 +0000 Subject: [PATCH] DMP-4506 Courthouse fields updated across admin, portal (#1757) --- .../search-transcripts-form.component.ts | 5 +- .../transcripts/transcripts.component.spec.ts | 1 + .../transcripts/transcripts.component.ts | 5 +- ...search-transformed-media-form.component.ts | 5 +- .../search-transformed-media.component.ts | 4 +- .../user-transcripts.component.ts | 8 ++- .../transcription-admin.service.spec.ts | 8 +-- .../transcription-admin.service.ts | 12 ++--- .../courthouse/courthouse.component.spec.ts | 19 +++---- .../common/courthouse/courthouse.component.ts | 50 ++++++++++++------- .../case-search-form.component.ts | 5 +- .../search/search.component.spec.ts | 12 ++++- .../components/search/search.component.ts | 8 ++- 13 files changed, 91 insertions(+), 51 deletions(-) diff --git a/src/app/admin/components/transcripts/search-transcripts-form/search-transcripts-form.component.ts b/src/app/admin/components/transcripts/search-transcripts-form/search-transcripts-form.component.ts index a541839a8..31f90529d 100644 --- a/src/app/admin/components/transcripts/search-transcripts-form/search-transcripts-form.component.ts +++ b/src/app/admin/components/transcripts/search-transcripts-form/search-transcripts-form.component.ts @@ -1,3 +1,4 @@ +import { Courthouse } from '@admin-types/courthouses/courthouse.type'; import { TranscriptionSearchFormValues } from '@admin-types/index'; import { CommonModule, NgIf } from '@angular/common'; import { Component, DestroyRef, effect, inject, input, model, output } from '@angular/core'; @@ -6,7 +7,7 @@ import { CourthouseComponent } from '@common/courthouse/courthouse.component'; import { DatepickerComponent } from '@common/datepicker/datepicker.component'; import { SpecificOrRangeDatePickerComponent } from '@common/specific-or-range-date-picker/specific-or-range-date-picker.component'; import { TranscriptSearchFormErrorMessages } from '@constants/transcript-search-form-error-messages'; -import { CourthouseData, ErrorSummaryEntry } from '@core-types/index'; +import { ErrorSummaryEntry } from '@core-types/index'; import { FormService } from '@services/form/form.service'; import { defaultFormValues } from '@services/transcription-admin/transcription-admin.service'; import { dateRangeValidator } from '@validators/date-range.validator'; @@ -40,7 +41,7 @@ export class SearchTranscriptsFormComponent { formService = inject(FormService); isCompletedTranscriptSearch = input(false); - courthouses = input([]); + courthouses = input([]); formValues = model(defaultFormValues); form = this.fb.group({ diff --git a/src/app/admin/components/transcripts/transcripts.component.spec.ts b/src/app/admin/components/transcripts/transcripts.component.spec.ts index 213fd2b10..28fd3ec12 100644 --- a/src/app/admin/components/transcripts/transcripts.component.spec.ts +++ b/src/app/admin/components/transcripts/transcripts.component.spec.ts @@ -93,6 +93,7 @@ describe('TranscriptsComponent', () => { const fakeCourthouseService = { getCourthouses: jest.fn().mockReturnValue(of([])), + mapCourthouseDataToCourthouses: jest.fn().mockReturnValue([]), } as unknown as CourthouseService; beforeEach(async () => { diff --git a/src/app/admin/components/transcripts/transcripts.component.ts b/src/app/admin/components/transcripts/transcripts.component.ts index 9c093f392..ac8f9e658 100644 --- a/src/app/admin/components/transcripts/transcripts.component.ts +++ b/src/app/admin/components/transcripts/transcripts.component.ts @@ -46,7 +46,10 @@ export class TranscriptsComponent { router = inject(Router); errors: { fieldId: string; message: string }[] = []; - courthouses$ = this.courthouseService.getCourthouses().pipe(shareReplay(1)); + courthouses$ = this.courthouseService.getCourthouses().pipe( + map((data) => this.courthouseService.mapCourthouseDataToCourthouses(data)), + shareReplay(1) + ); transcriptionStatuses$ = this.transcriptService.getTranscriptionStatuses().pipe(shareReplay(1)); search$ = new Subject(); diff --git a/src/app/admin/components/transformed-media/search-transformed-media-form/search-transformed-media-form.component.ts b/src/app/admin/components/transformed-media/search-transformed-media-form/search-transformed-media-form.component.ts index 8e0322c6d..f0bc3452b 100644 --- a/src/app/admin/components/transformed-media/search-transformed-media-form/search-transformed-media-form.component.ts +++ b/src/app/admin/components/transformed-media/search-transformed-media-form/search-transformed-media-form.component.ts @@ -1,3 +1,4 @@ +import { Courthouse } from '@admin-types/courthouses/courthouse.type'; import { TransformedMediaSearchFormValues } from '@admin-types/transformed-media/transformed-media-search-form.values'; import { CommonModule, NgIf } from '@angular/common'; import { @@ -17,7 +18,7 @@ import { CourthouseComponent } from '@common/courthouse/courthouse.component'; import { DatepickerComponent } from '@common/datepicker/datepicker.component'; import { SpecificOrRangeDatePickerComponent } from '@common/specific-or-range-date-picker/specific-or-range-date-picker.component'; import { TransformedMediaSearchFormErrorMessages } from '@constants/transformed-media-search-form-error-messages'; -import { CourthouseData, ErrorSummaryEntry } from '@core-types/index'; +import { ErrorSummaryEntry } from '@core-types/index'; import { FormService } from '@services/form/form.service'; import { defaultFormValues } from '@services/transformed-media/transformed-media.service'; import { dateRangeValidator } from '@validators/date-range.validator'; @@ -51,7 +52,7 @@ export class SearchTransformedMediaFormComponent { formService = inject(FormService); formValues = input({ ...defaultFormValues }); - @Input() courthouses: CourthouseData[] = []; + @Input() courthouses: Courthouse[] = []; form = this.fb.group({ requestId: ['', [Validators.pattern(/^-?[0-9]*$/), Validators.min(1), Validators.max(2147483647)]], diff --git a/src/app/admin/components/transformed-media/search-transformed-media/search-transformed-media.component.ts b/src/app/admin/components/transformed-media/search-transformed-media/search-transformed-media.component.ts index 4f67818d3..e05055a74 100644 --- a/src/app/admin/components/transformed-media/search-transformed-media/search-transformed-media.component.ts +++ b/src/app/admin/components/transformed-media/search-transformed-media/search-transformed-media.component.ts @@ -37,7 +37,9 @@ export class SearchTransformedMediaComponent { scrollService = inject(ScrollService); errors = signal([]); - courthouses$ = this.courthouseService.getCourthouses(); + courthouses$ = this.courthouseService + .getCourthouses() + .pipe(map((data) => this.courthouseService.mapCourthouseDataToCourthouses(data))); isLoading = signal(false); onErrors(errors: ErrorSummaryEntry[]) { diff --git a/src/app/admin/components/users/user-transcripts/user-transcripts.component.ts b/src/app/admin/components/users/user-transcripts/user-transcripts.component.ts index 99bf96d19..a4e9d940d 100644 --- a/src/app/admin/components/users/user-transcripts/user-transcripts.component.ts +++ b/src/app/admin/components/users/user-transcripts/user-transcripts.component.ts @@ -1,3 +1,4 @@ +import { Courthouse } from '@admin-types/courthouses/courthouse.type'; import { Transcription, TranscriptionStatus } from '@admin-types/transcription'; import { CommonModule, NgClass } from '@angular/common'; import { Component, EventEmitter, OnInit, Output, inject } from '@angular/core'; @@ -8,7 +9,7 @@ import { GovukHeadingComponent } from '@common/govuk-heading/govuk-heading.compo import { GovukTagComponent } from '@common/govuk-tag/govuk-tag.component'; import { LoadingComponent } from '@common/loading/loading.component'; import { transcriptStatusTagColours } from '@constants/transcript-status-tag-colours'; -import { CourthouseData, DatatableColumn } from '@core-types/index'; +import { DatatableColumn } from '@core-types/index'; import { TableRowTemplateDirective } from '@directives/table-row-template.directive'; import { LuxonDatePipe } from '@pipes/luxon-date.pipe'; import { TranscriptStatus } from '@portal-types/index'; @@ -48,7 +49,10 @@ export class UserTranscriptsComponent implements OnInit { statusColours = transcriptStatusTagColours; showAll$!: Observable; - courthouses$: Observable = this.courthouseService.getCourthouses().pipe(shareReplay(1)); + courthouses$: Observable = this.courthouseService.getCourthouses().pipe( + map((data) => this.courthouseService.mapCourthouseDataToCourthouses(data)), + shareReplay(1) + ); transcriptionStatuses$: Observable = this.transcriptionAdminService .getTranscriptionStatuses() .pipe(shareReplay(1)); diff --git a/src/app/admin/services/transcription-admin/transcription-admin.service.spec.ts b/src/app/admin/services/transcription-admin/transcription-admin.service.spec.ts index 3644dc455..d0fb9078c 100644 --- a/src/app/admin/services/transcription-admin/transcription-admin.service.spec.ts +++ b/src/app/admin/services/transcription-admin/transcription-admin.service.spec.ts @@ -1,3 +1,4 @@ +import { Courthouse } from '@admin-types/courthouses/courthouse.type'; import { FileHideOrDeleteFormValues } from '@admin-types/hidden-reasons/file-hide-or-delete-form-values'; import { HiddenReason } from '@admin-types/hidden-reasons/hidden-reason'; import { HiddenReasonData } from '@admin-types/hidden-reasons/hidden-reason-data.interface'; @@ -16,7 +17,6 @@ import { DatePipe } from '@angular/common'; import { provideHttpClient } from '@angular/common/http'; import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; import { TestBed, fakeAsync, tick } from '@angular/core/testing'; -import { CourthouseData } from '@core-types/index'; import { LuxonDatePipe } from '@pipes/luxon-date.pipe'; import { TranscriptStatus } from '@portal-types/index'; import { DateTime } from 'luxon'; @@ -710,9 +710,9 @@ describe('TranscriptionAdminService', () => { ] as unknown as Transcription[]; const courthouses = [ - { id: 1, display_name: 'Courthouse 1', courthouse_name: 'Main Courthouse' }, - { id: 2, display_name: 'Courthouse 2', courthouse_name: 'Secondary Courthouse' }, - ] as CourthouseData[]; + { id: 1, displayName: 'Courthouse 1', courthouseName: 'Main Courthouse' }, + { id: 2, displayName: 'Courthouse 2', courthouseName: 'Secondary Courthouse' }, + ] as Courthouse[]; const statuses = [ { id: 1, type: 'Requested', displayName: 'Status 1' }, diff --git a/src/app/admin/services/transcription-admin/transcription-admin.service.ts b/src/app/admin/services/transcription-admin/transcription-admin.service.ts index aaee7e244..066661b33 100644 --- a/src/app/admin/services/transcription-admin/transcription-admin.service.ts +++ b/src/app/admin/services/transcription-admin/transcription-admin.service.ts @@ -1,3 +1,4 @@ +import { Courthouse } from '@admin-types/courthouses/courthouse.type'; import { FileHide } from '@admin-types/hidden-reasons/file-hide'; import { FileHideData } from '@admin-types/hidden-reasons/file-hide-data.interface'; import { FileHideOrDeleteFormValues } from '@admin-types/hidden-reasons/file-hide-or-delete-form-values'; @@ -28,7 +29,6 @@ import { TranscriptionWorkflow } from '@admin-types/transcription/transcription- import { TranscriptionWorkflowData } from '@admin-types/transcription/transcription-workflow-data.interface'; import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http'; import { Injectable, inject, signal } from '@angular/core'; -import { CourthouseData } from '@core-types/index'; import { LuxonDatePipe } from '@pipes/luxon-date.pipe'; import { TranscriptStatus } from '@portal-types/transcriptions/transcript-status.type'; import { GET_SECURITY_GROUPS_PATH } from '@services/courthouses/courthouses.service'; @@ -301,11 +301,7 @@ export class TranscriptionAdminService { }; } - mapResults( - results: Transcription[], - courthouses: CourthouseData[], - statuses: TranscriptionStatus[] - ): Transcription[] { + mapResults(results: Transcription[], courthouses: Courthouse[], statuses: TranscriptionStatus[]): Transcription[] { return results.map((result) => { const courthouse = courthouses.find((c) => c.id === result.courthouse.id); const status = statuses.find((s) => s.id === result.status.id); @@ -313,8 +309,8 @@ export class TranscriptionAdminService { ...result, courthouse: { id: courthouse?.id, - displayName: courthouse?.display_name, - courthouseName: courthouse?.courthouse_name, + displayName: courthouse?.displayName, + courthouseName: courthouse?.courthouseName, }, status: { id: status?.id, diff --git a/src/app/core/components/common/courthouse/courthouse.component.spec.ts b/src/app/core/components/common/courthouse/courthouse.component.spec.ts index c4c6e7a21..c538c147b 100644 --- a/src/app/core/components/common/courthouse/courthouse.component.spec.ts +++ b/src/app/core/components/common/courthouse/courthouse.component.spec.ts @@ -1,6 +1,7 @@ +import { Courthouse } from '@admin-types/courthouses/courthouse.type'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { CourthouseData } from '@core-types/index'; +import { DateTime } from 'luxon'; import { CourthouseComponent } from './courthouse.component'; describe('CourthouseComponent', () => { @@ -8,10 +9,10 @@ describe('CourthouseComponent', () => { let fixture: ComponentFixture; const courts = [ - { courthouse_name: 'Reading', id: 0, created_date_time: 'mock' }, - { courthouse_name: 'Slough', id: 1, created_date_time: 'mock' }, - { courthouse_name: 'Ascot', id: 2, created_date_time: 'mock' }, - ] as CourthouseData[]; + { courthouseName: 'Reading', id: 0, createdDateTime: DateTime.now() }, + { courthouseName: 'Slough', id: 1, createdDateTime: DateTime.now() }, + { courthouseName: 'Ascot', id: 2, createdDateTime: DateTime.now() }, + ] as Courthouse[]; beforeEach(() => { TestBed.configureTestingModule({ @@ -30,15 +31,15 @@ describe('CourthouseComponent', () => { describe('AccessibleAutocomplete props', () => { it('should have correct default properties', () => { fixture.detectChanges(); - expect(component.props.id).toBe('courthouse'); - expect(component.props.name).toBe('courthouse'); - expect(component.props.minLength).toBe(1); + expect(component.props?.id).toBe('courthouse'); + expect(component.props?.name).toBe('courthouse'); + expect(component.props?.minLength).toBe(1); }); it('has correct default value if courthouse is pre-populated', () => { component.courthouse = 'Swansea'; fixture.detectChanges(); - expect(component.props.defaultValue).toBe('Swansea'); + expect(component.props?.defaultValue).toBe('Swansea'); }); }); diff --git a/src/app/core/components/common/courthouse/courthouse.component.ts b/src/app/core/components/common/courthouse/courthouse.component.ts index 9e8285562..a5605ea79 100644 --- a/src/app/core/components/common/courthouse/courthouse.component.ts +++ b/src/app/core/components/common/courthouse/courthouse.component.ts @@ -1,6 +1,16 @@ +import { Courthouse } from '@admin-types/courthouses/courthouse.type'; import { NgFor, NgIf } from '@angular/common'; -import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnChanges, Output, ViewChild } from '@angular/core'; -import { CourthouseData } from '@core-types/index'; +import { + AfterViewInit, + Component, + ElementRef, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + ViewChild, +} from '@angular/core'; import accessibleAutocomplete, { AccessibleAutocompleteProps } from 'accessible-autocomplete'; @Component({ @@ -10,27 +20,33 @@ import accessibleAutocomplete, { AccessibleAutocompleteProps } from 'accessible- templateUrl: './courthouse.component.html', styleUrls: ['./courthouse.component.scss'], }) -export class CourthouseComponent implements AfterViewInit, OnChanges { +export class CourthouseComponent implements AfterViewInit, OnChanges, OnInit { @ViewChild('courthouseAutocomplete') autocompleteContainer!: ElementRef; - @Input() courthouses: CourthouseData[] = []; + @Input() courthouses: Courthouse[] = []; @Input() courthouse = ''; @Input() label = 'Courthouse'; @Input() isInvalid = false; + @Input() showAllValues = true; @Input() errors: string[] = []; @Output() courthouseSelect = new EventEmitter(); - props: AccessibleAutocompleteProps = { - id: 'courthouse', - source: [], - minLength: 1, - name: 'courthouse', - onConfirm: () => { - // have to grab input value like this due to onConfirm(courthouse) emitting undefined onBlur - const inputValue = (document.querySelector('input[name=courthouse]') as HTMLInputElement).value; - this.courthouseSelect.emit(inputValue); - }, - }; + props: AccessibleAutocompleteProps | null = null; + + ngOnInit(): void { + this.props = { + id: 'courthouse', + source: [], + minLength: 1, + name: 'courthouse', + showAllValues: this.showAllValues, + onConfirm: () => { + // have to grab input value like this due to onConfirm(courthouse) emitting undefined onBlur + const inputValue = (document.querySelector('input[name=courthouse]') as HTMLInputElement).value; + this.courthouseSelect.emit(inputValue); + }, + }; + } ngOnChanges(): void { if (document.querySelector('input[name=courthouse]')) { @@ -47,9 +63,9 @@ export class CourthouseComponent implements AfterViewInit, OnChanges { } ngAfterViewInit(): void { - if (this.courthouses.length) { + if (this.courthouses.length && this.props) { this.props.element = this.autocompleteContainer.nativeElement; - this.props.source = this.courthouses.map((courthouse) => courthouse.display_name); + this.props.source = this.courthouses.map((courthouse) => courthouse.displayName); this.props.defaultValue = this.courthouse; accessibleAutocomplete(this.props); } diff --git a/src/app/portal/components/search/case-search-form/case-search-form.component.ts b/src/app/portal/components/search/case-search-form/case-search-form.component.ts index bdc391810..d5ee7df9a 100644 --- a/src/app/portal/components/search/case-search-form/case-search-form.component.ts +++ b/src/app/portal/components/search/case-search-form/case-search-form.component.ts @@ -1,3 +1,4 @@ +import { Courthouse } from '@admin-types/courthouses/courthouse.type'; import { NgClass, NgFor, NgIf } from '@angular/common'; import { Component, DestroyRef, inject, input, model, OnInit, output, signal, ViewChild } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @@ -5,7 +6,7 @@ import { NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angula import { CourthouseComponent } from '@common/courthouse/courthouse.component'; import { SpecificOrRangeDatePickerComponent } from '@common/specific-or-range-date-picker/specific-or-range-date-picker.component'; import { CaseSearchFormErrorMessages } from '@constants/case-search-form-error-messages'; -import { CourthouseData, ErrorSummaryEntry } from '@core-types/index'; +import { ErrorSummaryEntry } from '@core-types/index'; import { NestedKeys } from '@core-types/utils/nested-keys.type'; import { CaseSearchForm, CaseSearchFormValues } from '@portal-types/index'; import { ErrorMessageService } from '@services/error/error-message.service'; @@ -32,7 +33,7 @@ export class CaseSearchFormComponent implements OnInit { errorMsgService = inject(ErrorMessageService); formValues = input(null); - courthouses = input([]); + courthouses = input([]); isSubmitted = model(false); isAdvancedSearch = model(false); diff --git a/src/app/portal/components/search/search.component.spec.ts b/src/app/portal/components/search/search.component.spec.ts index 7b9d99d0a..19a93465f 100644 --- a/src/app/portal/components/search/search.component.spec.ts +++ b/src/app/portal/components/search/search.component.spec.ts @@ -1,3 +1,4 @@ +import { Courthouse } from '@admin-types/courthouses/courthouse.type'; import { provideHttpClient } from '@angular/common/http'; import { signal } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; @@ -11,12 +12,18 @@ import { CaseSearchService } from '../../services/case-search/case-search.servic import { CaseSearchResultsComponent } from './case-search-results/case-search-results.component'; import { SearchComponent } from './search.component'; -const mockCourthouses = [ +const mockCourthousesData = [ { courthouse_name: 'Reading', id: 0 }, { courthouse_name: 'Slough', id: 1 }, { courthouse_name: 'Ascot', id: 2 }, ] as CourthouseData[]; +const mockCourthouses = [ + { courthouseName: 'Reading', id: 0 }, + { courthouseName: 'Slough', id: 1 }, + { courthouseName: 'Ascot', id: 2 }, +] as Courthouse[]; + const mockFormValues: CaseSearchFormValues = { caseNumber: '1', courthouse: 'Reading', @@ -48,7 +55,8 @@ describe('SearchComponent', () => { } as unknown as CaseSearchService; const fakeCourtHouseService = { - getCourthouses: jest.fn().mockReturnValue(of(mockCourthouses)), + getCourthouses: jest.fn().mockReturnValue(of(mockCourthousesData)), + mapCourthouseDataToCourthouses: jest.fn().mockReturnValue(mockCourthouses), } as unknown as CourthouseService; const fakeErrorMsgService = { diff --git a/src/app/portal/components/search/search.component.ts b/src/app/portal/components/search/search.component.ts index 9dd7ce5cc..b7de256ad 100644 --- a/src/app/portal/components/search/search.component.ts +++ b/src/app/portal/components/search/search.component.ts @@ -10,6 +10,7 @@ import { CaseSearchService } from '@services/case-search/case-search.service'; import { CourthouseService } from '@services/courthouses/courthouses.service'; import { ErrorMessageService } from '@services/error/error-message.service'; import { ScrollService } from '@services/scroll/scroll.service'; +import { map } from 'rxjs'; import { CaseSearchFormComponent } from './case-search-form/case-search-form.component'; import { CaseSearchResultsComponent } from './case-search-results/case-search-results.component'; import { SearchErrorComponent } from './search-error/search-error.component'; @@ -35,7 +36,12 @@ export class SearchComponent { errorMsgService = inject(ErrorMessageService); scrollService = inject(ScrollService); - courthouses = toSignal(this.courthouseService.getCourthouses(), { initialValue: [] }); + courthouses = toSignal( + this.courthouseService + .getCourthouses() + .pipe(map((data) => this.courthouseService.mapCourthouseDataToCourthouses(data))), + { initialValue: [] } + ); errorSummary = signal([]); results = toSignal(this.caseSearchService.results$, { initialValue: null });