diff --git a/package-lock.json b/package-lock.json index 669a18e..a8aaadd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cpp.ui.core", - "version": "19.0.5", + "version": "19.0.4-PRE-RELEASE-3RD-LINE-V4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cpp.ui.core", - "version": "19.0.5", + "version": "19.0.4-PRE-RELEASE-3RD-LINE-V4.1", "license": "UNLICENSED", "dependencies": { "@ngrx/operators": "^19.2.1", diff --git a/package.json b/package.json index fcbbabb..27cc795 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cpp.ui.core", - "version": "19.0.5", + "version": "19.0.4-PRE-RELEASE-3RD-LINE-V4.1", "repository": { "type": "git", "url": "https://github.com/hmcts/cpp-ui-core" diff --git a/projects/reference-data/src/actions/reference-data.actions.ts b/projects/reference-data/src/actions/reference-data.actions.ts index 0f87dff..6e69fc1 100644 --- a/projects/reference-data/src/actions/reference-data.actions.ts +++ b/projects/reference-data/src/actions/reference-data.actions.ts @@ -123,6 +123,18 @@ export const loadOrganisationUnitsError = createAction( props<{ error: HttpErrorResponse }>() ); +export const loadAllOrganisationUnits = createAction('LOAD_ALL_COURT_CENTRES'); + +export const loadAllOrganisationUnitsSuccess = createAction( + 'LOAD_ALL_COURT_CENTRES_SUCCESS', + props<{ allOrganisationUnits: OrganisationUnit[] }>() +); + +export const loadAllOrganisationUnitsError = createAction( + 'LOAD_ALL_COURT_CENTRES_ERROR', + props<{ error: HttpErrorResponse }>() +); + export const loadFixedLists = createAction('LOAD_FIXED_LISTS'); export const loadFixedListsSuccess = createAction( diff --git a/projects/reference-data/src/guards/__tests__/court-centre-units.gard.spec.ts b/projects/reference-data/src/guards/__tests__/get-all-court-centre-units.guard.spec.ts similarity index 67% rename from projects/reference-data/src/guards/__tests__/court-centre-units.gard.spec.ts rename to projects/reference-data/src/guards/__tests__/get-all-court-centre-units.guard.spec.ts index 62ab25d..4a03016 100644 --- a/projects/reference-data/src/guards/__tests__/court-centre-units.gard.spec.ts +++ b/projects/reference-data/src/guards/__tests__/get-all-court-centre-units.guard.spec.ts @@ -6,9 +6,9 @@ import { of, throwError } from 'rxjs'; import { ReferenceDataActions } from '../../actions/index'; import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; import { ReferenceDataService } from '../../services/reference-data.service'; -import { createCourtCentreUnitsGuard } from '../court-centre-units.gard'; +import { getAllCourtCentreUnitsGuard } from '../get-all-court-centre-units.guard'; -describe('createCourtCentreUnitsGuard', () => { +describe('getAllCourtCentreUnitsGuard', () => { let store: Store; let fetchOrganisationUnits: jest.Mock; @@ -62,45 +62,30 @@ describe('createCourtCentreUnitsGuard', () => { expect.assertions(1); const snapshot = createSnapshot(); - store.dispatch(ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits: [] })); + store.dispatch( + ReferenceDataActions.loadAllOrganisationUnitsSuccess({ allOrganisationUnits: [] }) + ); TestBed.runInInjectionContext(() => - createCourtCentreUnitsGuard()(snapshot, {} as RouterStateSnapshot) + getAllCourtCentreUnitsGuard(snapshot, {} as RouterStateSnapshot) ).subscribe((didResolve) => { expect(didResolve).toBe(true); }); }); - it('should resolve to true after fetching with includeExpired=false when not found in the store', () => { + it('should resolve to true after fetching the organisation units when not found in the store', () => { expect.assertions(3); const snapshot = createSnapshot(); fetchOrganisationUnits.mockReturnValue(of([])); TestBed.runInInjectionContext(() => - createCourtCentreUnitsGuard()(snapshot, {} as RouterStateSnapshot) - ).subscribe((didResolve) => { - expect(didResolve).toBe(true); - expect(fetchOrganisationUnits).toHaveBeenCalledWith(false); - expect(store.dispatch).toHaveBeenCalledWith( - ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits: [] }) - ); - }); - }); - - it('should resolve to true after fetching with includeExpired=true when not found in the store', () => { - expect.assertions(3); - const snapshot = createSnapshot(); - - fetchOrganisationUnits.mockReturnValue(of([])); - - TestBed.runInInjectionContext(() => - createCourtCentreUnitsGuard(true)(snapshot, {} as RouterStateSnapshot) + getAllCourtCentreUnitsGuard(snapshot, {} as RouterStateSnapshot) ).subscribe((didResolve) => { expect(didResolve).toBe(true); expect(fetchOrganisationUnits).toHaveBeenCalledWith(true); expect(store.dispatch).toHaveBeenCalledWith( - ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits: [] }) + ReferenceDataActions.loadAllOrganisationUnitsSuccess({ allOrganisationUnits: [] }) ); }); }); @@ -113,7 +98,7 @@ describe('createCourtCentreUnitsGuard', () => { fetchOrganisationUnits.mockReturnValue(throwError(error)); TestBed.runInInjectionContext(() => - createCourtCentreUnitsGuard()(snapshot, {} as RouterStateSnapshot) + getAllCourtCentreUnitsGuard(snapshot, {} as RouterStateSnapshot) ).subscribe((didResolve) => { expect(didResolve).toBe(false); expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); diff --git a/projects/reference-data/src/guards/court-centre-units.gard.ts b/projects/reference-data/src/guards/court-centre-units.gard.ts deleted file mode 100644 index 5a34072..0000000 --- a/projects/reference-data/src/guards/court-centre-units.gard.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { inject } from '@angular/core'; -import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { Observable, of } from 'rxjs'; -import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; -import { ReferenceDataActions } from '../actions/index'; -import { getOrganisationUnits, ReferenceDataState } from '../reducers/index'; -import { ReferenceDataService } from '../services/reference-data.service'; - -export function createCourtCentreUnitsGuard(includeExpired = false) { - return (route: ActivatedRouteSnapshot, _state: RouterStateSnapshot): Observable => { - const referenceDataService = inject(ReferenceDataService); - const store = inject(Store); - const router = inject(Router); - const { referenceDataErrorRedirectTo } = route.data as { - referenceDataErrorRedirectTo?: string; - }; - - return hasOrganisationUnitsInStore(store).pipe( - switchMap((inStore) => - inStore ? of(true) : hasOrganisationUnitsInApi(store, referenceDataService, includeExpired) - ), - tap({ - error: () => { - if (referenceDataErrorRedirectTo) { - router.navigateByUrl(referenceDataErrorRedirectTo); - } - } - }), - catchError(() => of(false)) - ); - }; -} - -const hasOrganisationUnitsInStore = (store: Store): Observable => - store.pipe( - map(getOrganisationUnits), - map((organisationUnits) => !!organisationUnits), - take(1) - ); - -const hasOrganisationUnitsInApi = ( - store: Store, - service: ReferenceDataService, - includeExpired: boolean -) => - service.fetchOrganisationUnits(includeExpired).pipe( - tap((organisationUnits) => - store.dispatch(ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits })) - ), - mapTo(true) - ); diff --git a/projects/reference-data/src/guards/court-centres.guard.ts b/projects/reference-data/src/guards/court-centres.guard.ts index 5f913eb..f20c41f 100644 --- a/projects/reference-data/src/guards/court-centres.guard.ts +++ b/projects/reference-data/src/guards/court-centres.guard.ts @@ -8,7 +8,7 @@ import { getOrganisationUnits, ReferenceDataState } from '../reducers/index'; import { ReferenceDataService } from '../services/reference-data.service'; /** - * @deprecated Use {@link createCourtCentreUnitsGuard} from `court-centre-units.gard` instead. + * @deprecated Use {@link getAllCourtCentreUnitsGuard} from `get-all-court-centre-units.guard` instead. */ @Injectable() export class OrganisationUnitsGuard { diff --git a/projects/reference-data/src/guards/get-all-court-centre-units.guard.ts b/projects/reference-data/src/guards/get-all-court-centre-units.guard.ts new file mode 100644 index 0000000..60c31f2 --- /dev/null +++ b/projects/reference-data/src/guards/get-all-court-centre-units.guard.ts @@ -0,0 +1,52 @@ +import { inject } from '@angular/core'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getAllOrganisationUnits, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +export function getAllCourtCentreUnitsGuard( + route: ActivatedRouteSnapshot, + _state: RouterStateSnapshot +): Observable { + const referenceDataService = inject(ReferenceDataService); + const store = inject(Store); + const router = inject(Router); + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + + return hasOrganisationUnitsInStore(store).pipe( + switchMap((inStore) => + inStore ? of(true) : hasOrganisationUnitsInApi(store, referenceDataService) + ), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); +} + +const hasOrganisationUnitsInStore = (store: Store): Observable => + store.pipe( + map(getAllOrganisationUnits), + map((allOrganisationUnits) => !!allOrganisationUnits), + take(1) + ); + +const hasOrganisationUnitsInApi = ( + store: Store, + service: ReferenceDataService +) => + service.fetchOrganisationUnits(true).pipe( + tap((allOrganisationUnits) => + store.dispatch(ReferenceDataActions.loadAllOrganisationUnitsSuccess({ allOrganisationUnits })) + ), + map(() => true) + ); diff --git a/projects/reference-data/src/public_api.ts b/projects/reference-data/src/public_api.ts index 51f56f7..72a8ffe 100644 --- a/projects/reference-data/src/public_api.ts +++ b/projects/reference-data/src/public_api.ts @@ -12,7 +12,7 @@ export * from './guards/cps-business-units.guard'; export * from './guards/cps-case-status.guard'; export * from './guards/fixed-lists.guard'; export * from './guards/court-centres.guard'; -export * from './guards/court-centre-units.gard'; +export * from './guards/get-all-court-centre-units.guard'; export * from './guards/hearing-type.guard'; export * from './guards/local-justice-areas.guard'; export * from './guards/plea-types.guard'; diff --git a/projects/reference-data/src/reducers/__tests__/__snapshots__/index.reducer.spec.ts.snap b/projects/reference-data/src/reducers/__tests__/__snapshots__/index.reducer.spec.ts.snap index bd69e34..4818b7c 100644 --- a/projects/reference-data/src/reducers/__tests__/__snapshots__/index.reducer.spec.ts.snap +++ b/projects/reference-data/src/reducers/__tests__/__snapshots__/index.reducer.spec.ts.snap @@ -147,6 +147,34 @@ exports[`referenceDataReducer Local Justice Areas ReferenceDataActions.loadLocal } `; +exports[`referenceDataReducer all court centres HearingResultsActions.loadAllOrganisationUnitsError should remove the all court centres key 1`] = `{}`; + +exports[`referenceDataReducer all court centres HearingResultsActions.loadAllOrganisationUnitsSuccess should add the all court centres to the state 1`] = ` +{ + "allOrganisationUnits": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer all court centres ReferenceDataActions.loadAllOrganisationUnits should install the all court centres key 1`] = ` +{ + "allOrganisationUnits": null, +} +`; + +exports[`referenceDataReducer all court centres ReferenceDataActions.loadAllOrganisationUnits should not overwrite any existing all court centres 1`] = ` +{ + "allOrganisationUnits": [ + { + "id": "*", + }, + ], +} +`; + exports[`referenceDataReducer application types HearingResultsActions.loadApplicationTypesError should remove the application types key 1`] = `{}`; exports[`referenceDataReducer application types HearingResultsActions.loadApplicationTypesSuccess should add the application types to the state 1`] = ` diff --git a/projects/reference-data/src/reducers/__tests__/index.reducer.spec.ts b/projects/reference-data/src/reducers/__tests__/index.reducer.spec.ts index 67864ba..1cf228c 100644 --- a/projects/reference-data/src/reducers/__tests__/index.reducer.spec.ts +++ b/projects/reference-data/src/reducers/__tests__/index.reducer.spec.ts @@ -442,6 +442,49 @@ describe('referenceDataReducer', () => { }); }); + describe('all court centres', () => { + describe('ReferenceDataActions.loadAllOrganisationUnits', () => { + it('should install the all court centres key', () => { + const action = ReferenceDataActions.loadAllOrganisationUnits(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing all court centres', () => { + const action = ReferenceDataActions.loadAllOrganisationUnits(); + const result = fromReferenceData.referenceDataReducer( + { allOrganisationUnits: [{ id: '*' }] as OrganisationUnit[] }, + action + ); + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadAllOrganisationUnitsSuccess', () => { + it('should add the all court centres to the state', () => { + const action = ReferenceDataActions.loadAllOrganisationUnitsSuccess({ + allOrganisationUnits: [{ id: '*' }] as OrganisationUnit[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadAllOrganisationUnitsError', () => { + it('should remove the all court centres key', () => { + const action = ReferenceDataActions.loadAllOrganisationUnitsError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer( + { allOrganisationUnits: null }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + }); + describe('Local Justice Areas', () => { describe('ReferenceDataActions.loadLocalJusticeAreas', () => { it('should install the localJusticeAreas', () => { diff --git a/projects/reference-data/src/reducers/index.ts b/projects/reference-data/src/reducers/index.ts index 9dd0169..979c4a0 100644 --- a/projects/reference-data/src/reducers/index.ts +++ b/projects/reference-data/src/reducers/index.ts @@ -56,6 +56,12 @@ export const getOrganisationUnits = (state: ReferenceDataState) => export const getOrganisationUnitsFetching = (state: ReferenceDataState) => state.referenceData.organisationUnits === null; +export const getAllOrganisationUnits = (state: ReferenceDataState) => + state.referenceData.allOrganisationUnits; + +export const getAllOrganisationUnitsFetching = (state: ReferenceDataState) => + state.referenceData.allOrganisationUnits === null; + export const getPoliceForceList = (state: ReferenceDataState) => state.referenceData.policeForceList; diff --git a/projects/reference-data/src/reducers/reference-data.reducer.ts b/projects/reference-data/src/reducers/reference-data.reducer.ts index ccd38b6..e8de34d 100644 --- a/projects/reference-data/src/reducers/reference-data.reducer.ts +++ b/projects/reference-data/src/reducers/reference-data.reducer.ts @@ -39,6 +39,7 @@ export interface ReferenceDataState { judiciaryGroupTypes?: JudiciaryGroupType[] | null; localJusticeAreas?: LocalJusticeArea[] | null; organisationUnits?: OrganisationUnit[] | null; + allOrganisationUnits?: OrganisationUnit[] | null; policeForceList?: PoliceForce[] | null; prosecutors?: Prosecutor[] | null; resultDefinitions?: ResultDefinition[] | null; @@ -276,6 +277,26 @@ export const referenceData = createReducer( ) ), + // All organisation units (including expired) + + on(ReferenceDataActions.loadAllOrganisationUnits, (state) => ({ + ...state, + allOrganisationUnits: state.allOrganisationUnits || null + })), + on(ReferenceDataActions.loadAllOrganisationUnitsSuccess, (state, { allOrganisationUnits }) => ({ + ...state, + allOrganisationUnits + })), + on(ReferenceDataActions.loadAllOrganisationUnitsError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'allOrganisationUnits' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + // Plea types on(ReferenceDataActions.loadPleaTypes, (state) => ({