From ccd46f613725c36183a424d4563895830f01b65b Mon Sep 17 00:00:00 2001
From: Shaed Parkar
Date: Thu, 14 Mar 2024 16:08:14 +0000
Subject: [PATCH 01/44] GA-203 track the `mo-new-cases` feature toggle key to
hide or show the new cases menu item
---
src/app/app-initializer.ts | 1 +
src/app/app.constants.ts | 12 +++++-
src/app/store/reducers/app.reducer.spec.ts | 9 +++++
src/app/store/selectors/app.selectors.spec.ts | 8 ++++
src/app/store/selectors/app.selectors.ts | 39 +++++++++++++++----
.../store/reducers/organisation.reducer.ts | 7 ++--
6 files changed, 64 insertions(+), 12 deletions(-)
diff --git a/src/app/app-initializer.ts b/src/app/app-initializer.ts
index 8d82e6660..168d246fd 100644
--- a/src/app/app-initializer.ts
+++ b/src/app/app-initializer.ts
@@ -10,6 +10,7 @@ export function initApplication(store: Store): VoidFunction {
store.dispatch(new fromApp.LoadFeatureToggleConfig([AppConstants.FEATURE_NAMES.feeAccount,
AppConstants.FEATURE_NAMES.editUserPermissions,
AppConstants.FEATURE_NAMES.caaMenuItems,
+ AppConstants.FEATURE_NAMES.newCasesItems,
AppConstants.FEATURE_NAMES.newRegisterOrg]));
store.pipe(
diff --git a/src/app/app.constants.ts b/src/app/app.constants.ts
index 38f79edaa..5910b3f22 100644
--- a/src/app/app.constants.ts
+++ b/src/app/app.constants.ts
@@ -8,6 +8,7 @@ const featureNames = {
editUserPermissions: 'edit-permissions',
removeUserFromCase: 'remove-user-from-case-mo',
caaMenuItems: 'mo-caa-menu-items',
+ newCasesItems: 'mo-new-cases',
newRegisterOrg: 'mo-new-register-org'
};
@@ -50,6 +51,15 @@ const navItemsArray: NavItemModel[] = [
featureToggle: {
featureName: featureNames.caaMenuItems
}
+ },
+ {
+ text: 'Cases',
+ href: '/cases',
+ orderId: 6,
+ active: false,
+ featureToggle: {
+ featureName: featureNames.newCasesItems
+ }
}
];
@@ -57,7 +67,7 @@ const roleBasedNav = {
'pui-organisation-manager': navItemsArray[0],
'pui-user-manager': navItemsArray[1],
'pui-finance-manager': navItemsArray[2],
- 'pui-caa': [navItemsArray[3], navItemsArray[4]]
+ 'pui-caa': [navItemsArray[3], navItemsArray[4], navItemsArray[5]]
};
const userNav: UserNavModel = {
diff --git a/src/app/store/reducers/app.reducer.spec.ts b/src/app/store/reducers/app.reducer.spec.ts
index 93d40c902..50bd874f4 100644
--- a/src/app/store/reducers/app.reducer.spec.ts
+++ b/src/app/store/reducers/app.reducer.spec.ts
@@ -99,6 +99,15 @@ describe('AppReducer', () => {
featureToggle: {
featureName: AppConstants.FEATURE_NAMES.caaMenuItems
}
+ },
+ {
+ text: 'Cases',
+ href: '/cases',
+ orderId: 6,
+ active: false,
+ featureToggle: {
+ featureName: AppConstants.FEATURE_NAMES.newCasesItems
+ }
}
];
const action = new fromAppActions.SetUserRoles(payload);
diff --git a/src/app/store/selectors/app.selectors.spec.ts b/src/app/store/selectors/app.selectors.spec.ts
index fe2dbb068..80853368b 100644
--- a/src/app/store/selectors/app.selectors.spec.ts
+++ b/src/app/store/selectors/app.selectors.spec.ts
@@ -112,6 +112,14 @@ describe('App Selectors', () => {
expect(result).toBeUndefined();
});
+ it('should get CAA new cases feature is enabled', () => {
+ const featureFlag: AppFeatureFlag = { featureName: 'mo-new-cases', isEnabled: true };
+ let result;
+ store.dispatch(new fromActions.LoadFeatureToggleConfig(featureFlag));
+ store.pipe(select(fromSelectors.getCaaNewCasesMenuItemsFeatureIsEnabled)).subscribe((value) => (result = value));
+ expect(result).toBeUndefined();
+ });
+
it('should get edit user feature', () => {
const featureFlags: AppFeatureFlag[] = [
{ featureName: 'edit-permissions', isEnabled: true },
diff --git a/src/app/store/selectors/app.selectors.ts b/src/app/store/selectors/app.selectors.ts
index 3f7a853b4..b3a288d2d 100644
--- a/src/app/store/selectors/app.selectors.ts
+++ b/src/app/store/selectors/app.selectors.ts
@@ -28,10 +28,7 @@ export const getHeaderTitle = createSelector(
}
);
-export const getNav = createSelector(
- getAppState,
- fromAppFeature.getNavItems
-);
+export const getNav = createSelector(getAppState, fromAppFeature.getNavItems);
export const getFeatureFlag = createSelector(
getAppState,
@@ -40,7 +37,11 @@ export const getFeatureFlag = createSelector(
export const getFeeAndPayFeature = createSelector(
getFeatureFlag,
- (featureFlags) => featureFlags && featureFlags.find((flag) => flag.featureName === AppConstants.FEATURE_NAMES.feeAccount)
+ (featureFlags) =>
+ featureFlags &&
+ featureFlags.find(
+ (flag) => flag.featureName === AppConstants.FEATURE_NAMES.feeAccount
+ )
);
export const getFeeAndPayFeatureIsEnabled = createSelector(
@@ -50,7 +51,11 @@ export const getFeeAndPayFeatureIsEnabled = createSelector(
export const getCaaMenuItemsFeature = createSelector(
getFeatureFlag,
- (featureFlags) => featureFlags && featureFlags.find((flag) => flag.featureName === AppConstants.FEATURE_NAMES.caaMenuItems)
+ (featureFlags) =>
+ featureFlags &&
+ featureFlags.find(
+ (flag) => flag.featureName === AppConstants.FEATURE_NAMES.caaMenuItems
+ )
);
export const getCaaMenuItemsFeatureIsEnabled = createSelector(
@@ -58,9 +63,28 @@ export const getCaaMenuItemsFeatureIsEnabled = createSelector(
(featureFlag) => featureFlag && featureFlag.isEnabled
);
+export const getCaaNewCasesMenuItemsFeature = createSelector(
+ getFeatureFlag,
+ (featureFlags) =>
+ featureFlags &&
+ featureFlags.find(
+ (flag) => flag.featureName === AppConstants.FEATURE_NAMES.newCasesItems
+ )
+);
+
+export const getCaaNewCasesMenuItemsFeatureIsEnabled = createSelector(
+ getCaaNewCasesMenuItemsFeature,
+ (featureFlag) => featureFlag && featureFlag.isEnabled
+);
+
export const getEditUserFeature = createSelector(
getFeatureFlag,
- (featureFlags) => featureFlags && featureFlags.find((flag) => flag.featureName === AppConstants.FEATURE_NAMES.editUserPermissions)
+ (featureFlags) =>
+ featureFlags &&
+ featureFlags.find(
+ (flag) =>
+ flag.featureName === AppConstants.FEATURE_NAMES.editUserPermissions
+ )
);
export const getEditUserFeatureIsEnabled = createSelector(
@@ -104,7 +128,6 @@ export const getUserNav = createSelector(
(state, routes) => {
return AppUtils.setSetUserNavItems(state, routes);
}
-
);
export const getTermsAndConditions = createSelector(
diff --git a/src/organisation/store/reducers/organisation.reducer.ts b/src/organisation/store/reducers/organisation.reducer.ts
index 1eaceb0ae..4adef935a 100644
--- a/src/organisation/store/reducers/organisation.reducer.ts
+++ b/src/organisation/store/reducers/organisation.reducer.ts
@@ -30,8 +30,9 @@ export function reducer(
case fromOrganisation.LOAD_ORGANISATION_SUCCESS: {
const paymentAccount: PBANumberModel[] = [];
// if the users are loaded before organisation, the profile ids will be added since this is not provided by the GET operation
- action.payload = { ...action.payload, organisationProfileIds: state.organisationDetails?.organisationProfileIds };
- action.payload.paymentAccount.forEach((pba) => {
+ const newPayload = { ...action.payload, organisationProfileIds: state.organisationDetails?.organisationProfileIds };
+ const newAction = { ...action, payload: newPayload };
+ newAction.payload.paymentAccount.forEach((pba) => {
let pbaNumberModel: PBANumberModel;
if (typeof pba === 'string') {
pbaNumberModel = {
@@ -41,7 +42,7 @@ export function reducer(
paymentAccount.push(pbaNumberModel);
});
const loadedOrgDetails = {
- ...action.payload,
+ ...newAction.payload,
paymentAccount,
pendingAddPaymentAccount: [],
pendingRemovePaymentAccount: []
From 2a5b7a7ca598038f138cb2104ce5a0d02308d2eb Mon Sep 17 00:00:00 2001
From: Shaed Parkar
Date: Thu, 14 Mar 2024 16:35:30 +0000
Subject: [PATCH 02/44] Create a cases page for the new cases flow
---
src/app/app.constants.ts | 2 +-
src/app/app.routes.ts | 5 ++++
src/caa-cases/caa-cases.module.ts | 3 ++-
src/caa-cases/caa-cases.routing.ts | 12 +++++++++-
.../containers/cases/cases.component.html | 1 +
.../containers/cases/cases.component.scss | 0
.../containers/cases/cases.component.spec.ts | 23 +++++++++++++++++++
.../containers/cases/cases.component.ts | 10 ++++++++
src/caa-cases/containers/index.ts | 5 +++-
.../guards/new-cases-feature-toggle.guard.ts | 14 +++++++++++
10 files changed, 71 insertions(+), 4 deletions(-)
create mode 100644 src/caa-cases/containers/cases/cases.component.html
create mode 100644 src/caa-cases/containers/cases/cases.component.scss
create mode 100644 src/caa-cases/containers/cases/cases.component.spec.ts
create mode 100644 src/caa-cases/containers/cases/cases.component.ts
create mode 100644 src/caa-cases/guards/new-cases-feature-toggle.guard.ts
diff --git a/src/app/app.constants.ts b/src/app/app.constants.ts
index 5910b3f22..3b35654a5 100644
--- a/src/app/app.constants.ts
+++ b/src/app/app.constants.ts
@@ -54,7 +54,7 @@ const navItemsArray: NavItemModel[] = [
},
{
text: 'Cases',
- href: '/cases',
+ href: '/cases/all',
orderId: 6,
active: false,
featureToggle: {
diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts
index 7c299e969..97f1cd206 100644
--- a/src/app/app.routes.ts
+++ b/src/app/app.routes.ts
@@ -25,6 +25,11 @@ export const ROUTES: Routes = [
canActivate: [AuthGuard, HealthCheckGuard],
loadChildren: () => import('../fee-accounts/fee-accounts.module').then((m) => m.FeeAccountsModule)
},
+ {
+ path: 'cases',
+ canActivate: [AuthGuard, HealthCheckGuard],
+ loadChildren: () => import('../caa-cases/caa-cases.module').then((m) => m.CaaCasesModule)
+ },
{
path: 'unassigned-cases',
canActivate: [AuthGuard, HealthCheckGuard],
diff --git a/src/caa-cases/caa-cases.module.ts b/src/caa-cases/caa-cases.module.ts
index 390720a07..076eccaa3 100644
--- a/src/caa-cases/caa-cases.module.ts
+++ b/src/caa-cases/caa-cases.module.ts
@@ -19,6 +19,7 @@ import { FeatureToggleAccountGuard } from './guards/feature-toggle.guard';
import { RoleGuard } from './guards/user-role.guard';
import * as fromServices from './services';
import { effects, reducers } from './store';
+import { NewCaseFeatureToggleGuard } from './guards/new-cases-feature-toggle.guard';
@NgModule({
imports: [
@@ -39,7 +40,7 @@ import { effects, reducers } from './store';
],
exports: [...fromContainers.containers, ...fromComponents.components],
declarations: [...fromContainers.containers, ...fromComponents.components],
- providers: [...fromServices.services, OrganisationService, PBAService, UsersService, InviteUserService, FeatureToggleAccountGuard, RoleGuard],
+ providers: [...fromServices.services, OrganisationService, PBAService, UsersService, InviteUserService, FeatureToggleAccountGuard, NewCaseFeatureToggleGuard, RoleGuard],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
diff --git a/src/caa-cases/caa-cases.routing.ts b/src/caa-cases/caa-cases.routing.ts
index 0823604b6..a1fc6474e 100644
--- a/src/caa-cases/caa-cases.routing.ts
+++ b/src/caa-cases/caa-cases.routing.ts
@@ -2,11 +2,21 @@ import { ModuleWithProviders } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from '../user-profile/guards/auth.guard';
import { CaaCasesModule } from './caa-cases.module';
-import { CaaCasesComponent, CaseShareCompleteComponent, CaseShareComponent, CaseShareConfirmComponent } from './containers';
+import { CaaCasesComponent, CaseShareCompleteComponent, CaseShareComponent, CaseShareConfirmComponent, CasesComponent } from './containers';
import { FeatureToggleAccountGuard } from './guards/feature-toggle.guard';
import { RoleGuard } from './guards/user-role.guard';
+import { NewCaseFeatureToggleGuard } from './guards/new-cases-feature-toggle.guard';
export const ROUTES: Routes = [
+ {
+ path: 'all',
+ component: CasesComponent,
+ canActivate: [
+ AuthGuard,
+ NewCaseFeatureToggleGuard,
+ RoleGuard
+ ]
+ },
{
path: '',
component: CaaCasesComponent,
diff --git a/src/caa-cases/containers/cases/cases.component.html b/src/caa-cases/containers/cases/cases.component.html
new file mode 100644
index 000000000..f98f109c8
--- /dev/null
+++ b/src/caa-cases/containers/cases/cases.component.html
@@ -0,0 +1 @@
+cases works!
diff --git a/src/caa-cases/containers/cases/cases.component.scss b/src/caa-cases/containers/cases/cases.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/caa-cases/containers/cases/cases.component.spec.ts b/src/caa-cases/containers/cases/cases.component.spec.ts
new file mode 100644
index 000000000..e71f6289f
--- /dev/null
+++ b/src/caa-cases/containers/cases/cases.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CasesComponent } from './cases.component';
+
+describe('CasesComponent', () => {
+ let component: CasesComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ CasesComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(CasesComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/caa-cases/containers/cases/cases.component.ts b/src/caa-cases/containers/cases/cases.component.ts
new file mode 100644
index 000000000..00c47bc6d
--- /dev/null
+++ b/src/caa-cases/containers/cases/cases.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'app-cases',
+ templateUrl: './cases.component.html',
+ styleUrls: ['./cases.component.scss']
+})
+export class CasesComponent {
+
+}
diff --git a/src/caa-cases/containers/index.ts b/src/caa-cases/containers/index.ts
index cadbf3923..0e9dfffc5 100644
--- a/src/caa-cases/containers/index.ts
+++ b/src/caa-cases/containers/index.ts
@@ -2,16 +2,19 @@ import { CaaCasesComponent } from './caa-cases/caa-cases.component';
import { CaseShareCompleteComponent } from './case-share-complete/case-share-complete.component';
import { CaseShareConfirmComponent } from './case-share-confirm/case-share-confirm.component';
import { CaseShareComponent } from './case-share/case-share.component';
+import { CasesComponent } from './cases/cases.component';
export const containers: any[] = [
CaaCasesComponent,
CaseShareComponent,
CaseShareConfirmComponent,
- CaseShareCompleteComponent
+ CaseShareCompleteComponent,
+ CasesComponent
];
export * from './caa-cases/caa-cases.component';
export * from './case-share-complete/case-share-complete.component';
export * from './case-share-confirm/case-share-confirm.component';
export * from './case-share/case-share.component';
+export * from './cases/cases.component';
diff --git a/src/caa-cases/guards/new-cases-feature-toggle.guard.ts b/src/caa-cases/guards/new-cases-feature-toggle.guard.ts
new file mode 100644
index 000000000..c722981c4
--- /dev/null
+++ b/src/caa-cases/guards/new-cases-feature-toggle.guard.ts
@@ -0,0 +1,14 @@
+import { Injectable } from '@angular/core';
+import { CanActivate } from '@angular/router';
+import { select, Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+import * as fromRoot from '../../app/store';
+
+@Injectable()
+export class NewCaseFeatureToggleGuard implements CanActivate {
+ constructor(private readonly appStore: Store) {}
+
+ public canActivate(): Observable {
+ return this.appStore.pipe(select(fromRoot.getCaaNewCasesMenuItemsFeatureIsEnabled));
+ }
+}
From 206906041992b7f0a220f5009b506a87c7b2ad52 Mon Sep 17 00:00:00 2001
From: Shaed Parkar
Date: Thu, 14 Mar 2024 17:06:35 +0000
Subject: [PATCH 03/44] WIP cases container component
---
angular.json | 10 +++-
.../containers/cases/cases.component.html | 51 ++++++++++++++++++-
.../containers/cases/cases.component.ts | 39 +++++++++++++-
3 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/angular.json b/angular.json
index dbd52a88e..30f72a28d 100644
--- a/angular.json
+++ b/angular.json
@@ -37,7 +37,12 @@
"src/styles.scss"
],
"scripts": [],
- "sourceMap": true
+ "sourceMap": true,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "buildOptimizer": false,
+ "optimization": false,
+ "namedChunks": true
},
"configurations": {
"production": {
@@ -74,7 +79,8 @@
"production": {
"browserTarget": "rpx-xui-manage-organisations:build:production"
}
- }
+ },
+ "defaultConfiguration": ""
},
"serveTest": {
"builder": "@angular-devkit/build-angular:dev-server",
diff --git a/src/caa-cases/containers/cases/cases.component.html b/src/caa-cases/containers/cases/cases.component.html
index f98f109c8..f4a68679d 100644
--- a/src/caa-cases/containers/cases/cases.component.html
+++ b/src/caa-cases/containers/cases/cases.component.html
@@ -1 +1,50 @@
-cases works!
+
+ {{
+ (selectedOrganisation$ | async)?.name
+ }}
+ {{ pageTitle }}
+
+
+
+ {{ showFilterSection ? "Hide cases filter" : "Show cases filter" }}
+
+
+
+
+
+ There is a problem
+
+
+
+
+
+
+
+
+
diff --git a/src/caa-cases/containers/cases/cases.component.ts b/src/caa-cases/containers/cases/cases.component.ts
index 00c47bc6d..81dccd793 100644
--- a/src/caa-cases/containers/cases/cases.component.ts
+++ b/src/caa-cases/containers/cases/cases.component.ts
@@ -1,10 +1,45 @@
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
+import { CaaCasesService } from 'src/caa-cases/services';
+
+import * as organisationStore from '../../../organisation/store';
+import * as userStore from '../../../users/store';
+import * as caaCasesStore from '../../store';
+import { Store, select } from '@ngrx/store';
+import { OrganisationDetails } from 'src/models/organisation.model';
+import { Observable } from 'rxjs';
+import { Router } from '@angular/router';
+import { ErrorMessage } from 'src/shared/models/error-message.model';
@Component({
selector: 'app-cases',
templateUrl: './cases.component.html',
styleUrls: ['./cases.component.scss']
})
-export class CasesComponent {
+export class CasesComponent implements OnInit {
+ public selectedOrganisation$: Observable;
+
+ public pageTitle = 'Cases';
+ public showFilterSection = false;
+ public errorMessages: ErrorMessage[];
+
+ constructor(private readonly caaCasesStore: Store,
+ private readonly organisationStore: Store,
+ private readonly userStore: Store,
+ private readonly router: Router,
+ private readonly service: CaaCasesService) {
+ }
+
+ public ngOnInit(): void {
+ // Load selected organisation details from store
+ this.organisationStore.dispatch(new organisationStore.LoadOrganisation());
+ this.selectedOrganisation$ = this.organisationStore.pipe(select(organisationStore.getOrganisationSel));
+ }
+
+ public toggleFilterSection(): void {
+ this.showFilterSection = !this.showFilterSection;
+ }
+ public isAnyError(): boolean {
+ return Array.isArray(this.errorMessages) && this.errorMessages.length > 0;
+ }
}
From f84125514698747268f722a8e77ba07e974159a9 Mon Sep 17 00:00:00 2001
From: Shaed Parkar
Date: Fri, 15 Mar 2024 22:18:29 +0000
Subject: [PATCH 04/44] GA-206 Add cases filter component
---
api/caaCases/enums/index.ts | 14 +-
.../cases-filter/cases-filter.component.html | 256 ++++++++++++++++++
.../cases-filter/cases-filter.component.scss | 44 +++
.../cases-filter.component.spec.ts | 23 ++
.../cases-filter/cases-filter.component.ts | 173 ++++++++++++
src/caa-cases/components/index.ts | 5 +-
.../containers/cases/cases.component.html | 7 +-
.../containers/cases/cases.component.ts | 20 +-
src/caa-cases/models/caa-cases.enum.ts | 4 +-
.../models/selected-case-filter.model.ts | 6 +
src/caa-cases/util/caa-cases.util.ts | 12 +
11 files changed, 554 insertions(+), 10 deletions(-)
create mode 100644 src/caa-cases/components/cases-filter/cases-filter.component.html
create mode 100644 src/caa-cases/components/cases-filter/cases-filter.component.scss
create mode 100644 src/caa-cases/components/cases-filter/cases-filter.component.spec.ts
create mode 100644 src/caa-cases/components/cases-filter/cases-filter.component.ts
create mode 100644 src/caa-cases/models/selected-case-filter.model.ts
diff --git a/api/caaCases/enums/index.ts b/api/caaCases/enums/index.ts
index c63cedd96..63c22a790 100644
--- a/api/caaCases/enums/index.ts
+++ b/api/caaCases/enums/index.ts
@@ -1,11 +1,13 @@
export enum CaaCasesPageType {
- AssignedCases = 'assigned-cases',
- UnassignedCases = 'unassigned-cases',
+ AssignedCases = 'assigned-cases',
+ UnassignedCases = 'unassigned-cases',
}
export enum CaaCasesFilterType {
- AllAssignees = 'all-assignees',
- AssigneeName = 'assignee-name',
- CaseReferenceNumber = 'case-reference-number',
- None = 'none',
+ AllAssignees = 'all-assignees',
+ AssigneeName = 'assignee-name',
+ CaseReferenceNumber = 'case-reference-number',
+ NewCasesToAccept = 'new-cases-to-accept',
+ UnassignedCases = 'unassigned-cases',
+ None = 'none',
}
diff --git a/src/caa-cases/components/cases-filter/cases-filter.component.html b/src/caa-cases/components/cases-filter/cases-filter.component.html
new file mode 100644
index 000000000..2aa0d3988
--- /dev/null
+++ b/src/caa-cases/components/cases-filter/cases-filter.component.html
@@ -0,0 +1,256 @@
+
diff --git a/src/caa-cases/components/cases-filter/cases-filter.component.scss b/src/caa-cases/components/cases-filter/cases-filter.component.scss
new file mode 100644
index 000000000..0c0512166
--- /dev/null
+++ b/src/caa-cases/components/cases-filter/cases-filter.component.scss
@@ -0,0 +1,44 @@
+@import "govuk-frontend/govuk/base";
+
+.govuk-grid-row {
+ .govuk-grid-column-one-half {
+ background-color: govuk-colour("light-grey");
+ padding-top: 20px;
+ margin-left: 15px;
+ }
+
+ #filterContainer {
+ margin-bottom: 30px;
+ }
+
+ #assignee-person {
+ width: 90%;
+ }
+
+ #case-reference-number {
+ width: 70%;
+ }
+
+ .hide-autocomplete {
+ display: none;
+ }
+}
+
+.mat-optgroup {
+ .mat-group-header {
+ font-size: 16px !important;
+ font-weight: bold !important;
+ }
+
+ .mat-option {
+ &:hover {
+ background: $govuk-focus-colour;
+ }
+ &.select-option {
+ &:hover {
+ background: govuk-colour("blue");
+ color: govuk-colour("white");
+ }
+ }
+ }
+}
diff --git a/src/caa-cases/components/cases-filter/cases-filter.component.spec.ts b/src/caa-cases/components/cases-filter/cases-filter.component.spec.ts
new file mode 100644
index 000000000..d1c00fb6f
--- /dev/null
+++ b/src/caa-cases/components/cases-filter/cases-filter.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CasesFilterComponent } from './cases-filter.component';
+
+describe('CasesFilterComponent', () => {
+ let component: CasesFilterComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ CasesFilterComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(CasesFilterComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/caa-cases/components/cases-filter/cases-filter.component.ts b/src/caa-cases/components/cases-filter/cases-filter.component.ts
new file mode 100644
index 000000000..c2b7887af
--- /dev/null
+++ b/src/caa-cases/components/cases-filter/cases-filter.component.ts
@@ -0,0 +1,173 @@
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
+import { User } from '@hmcts/rpx-xui-common-lib';
+import { Observable, catchError, debounceTime, of, switchMap, tap } from 'rxjs';
+import { CaaCasesFilterErrorMessage, CaaCasesFilterType } from 'src/caa-cases/models/caa-cases.enum';
+import { SelectedCaseFilter } from 'src/caa-cases/models/selected-case-filter.model';
+import { CaaCasesUtil } from 'src/caa-cases/util/caa-cases.util';
+import { ErrorMessage } from 'src/shared/models/error-message.model';
+
+@Component({
+ selector: 'app-cases-filter',
+ templateUrl: './cases-filter.component.html',
+ styleUrls: ['./cases-filter.component.scss']
+})
+export class CasesFilterComponent implements OnInit{
+ @Input() public selectedOrganisationUsers: User[];
+
+ @Output() public selectedFilter = new EventEmitter();
+ @Output() public emitErrorMessages = new EventEmitter();
+
+ public readonly ACTIVE_USER_GROUP_HEADING = 'Active users:';
+ public readonly INACTIVE_USER_GROUP_HEADING = 'Inactive users:';
+ public readonly ACTIVE_USER_STATUS = 'active';
+
+ public readonly assigneeNameErrorMessage = 'Enter a valid assignee name';
+ public readonly caseReferenceNumberErrorMessage = 'Enter a valid HMCTS case reference number';
+
+ public filteredAndGroupedUsers = new Map();
+
+ public caaCasesFilterType = CaaCasesFilterType;
+ public selectedFilterType: CaaCasesFilterType;
+
+ public errorMessages: ErrorMessage[];
+
+ public form: FormGroup;
+ public showAutocomplete: boolean = false;
+
+ public constructor(private formBuilder: FormBuilder) {}
+
+ ngOnInit(): void {
+ this.createForm();
+ }
+
+ createForm() {
+ this.form = this.formBuilder.group({
+ filterOption: this.formBuilder.control(CaaCasesFilterType.None),
+ assigneePerson: this.formBuilder.control(''),
+ caseReferenceNumber: this.formBuilder.control('')
+ });
+
+ this.form.controls.filterOption.valueChanges.subscribe((value: CaaCasesFilterType) => {
+ this.selectFilterOption(value);
+ this.handleOnFilterOptionChange(value);
+ });
+
+ this.form.controls.assigneePerson.valueChanges.pipe(
+ tap(() => {
+ this.showAutocomplete = false;
+ this.filteredAndGroupedUsers = null;
+ },
+ debounceTime(300)),
+ switchMap((searchTerm: any) => this.filterSelectedOrganisationUsers(searchTerm).pipe(
+ tap(() => this.showAutocomplete = true),
+ catchError(() => this.filteredAndGroupedUsers = null)
+ ))
+ ).subscribe((filteredAndGroupedUsers: Map) => {
+ this.filteredAndGroupedUsers = filteredAndGroupedUsers;
+ });
+ }
+
+ public filterSelectedOrganisationUsers(searchTerm?: string | User): Observable> {
+ const filteredUsers = searchTerm && searchTerm.length > 0
+ ? typeof(searchTerm) === 'string'
+ ? this.selectedOrganisationUsers.filter((user) => this.getDisplayName(user).toLowerCase().includes(searchTerm.toLowerCase()))
+ : this.selectedOrganisationUsers.filter((user) => this.getDisplayName(user).toLowerCase().includes(this.getDisplayName(searchTerm).toLowerCase()))
+ : this.selectedOrganisationUsers;
+ const activeUsers = filteredUsers.filter((user) => user.status.toLowerCase() === this.ACTIVE_USER_STATUS);
+ const inactiveUsers = filteredUsers.filter((user) => user.status.toLowerCase() !== this.ACTIVE_USER_STATUS);
+ const groupedUsers = new Map();
+ groupedUsers.set(this.ACTIVE_USER_GROUP_HEADING, activeUsers);
+ groupedUsers.set(this.INACTIVE_USER_GROUP_HEADING, inactiveUsers);
+ return of(groupedUsers);
+ }
+
+ public getDisplayName(selectedUser: User): string {
+ return `${selectedUser.fullName} - ${selectedUser.email}`;
+ }
+
+ public onSearch(): void {
+ if (this.validateForm()) {
+ let filterValue = null;
+ if (this.form.controls.filterOption.value === CaaCasesFilterType.CaseReferenceNumber) {
+ filterValue = this.form.controls.caseReferenceNumber.value;
+ }
+
+ if (this.form.controls.filterOption.value === CaaCasesFilterType.AssigneeName) {
+ const selectedUser = this.form.controls.assigneePerson.value;
+ const fullName = selectedUser.split(' - ')[0];
+ const email = selectedUser.split(' - ')[1];
+ filterValue = this.selectedOrganisationUsers && this.selectedOrganisationUsers.find(
+ (user) => user.fullName === fullName && user.email === email).userIdentifier;
+ }
+ const selectedFilter: SelectedCaseFilter = {
+ filterType: this.selectedFilterType,
+ filterValue: filterValue
+ };
+ this.selectedFilter.emit(selectedFilter);
+ }
+ }
+
+ public onReset(): void {
+ this.form.reset();
+ this.selectedFilter.emit({ filterType: this.selectedFilterType, filterValue: '' });
+ }
+
+ public onSelectionChange(selectedUser: User) {
+ this.form.controls.assigneePerson.clearValidators();
+ this.form.controls.assigneePerson.updateValueAndValidity();
+ this.form.controls.assigneePerson.setValue(this.getDisplayName(selectedUser), { emitEvent: false, onlySelf: true });
+ }
+
+ public selectFilterOption(caaCasesFilterType: CaaCasesFilterType): void {
+ this.selectedFilterType = caaCasesFilterType;
+ }
+
+ private validateForm(): boolean {
+ let isValid = true;
+ this.errorMessages = [];
+ if (this.form.controls.filterOption.value === CaaCasesFilterType.AssigneeName) {
+ this.form.controls.assigneePerson.updateValueAndValidity({ emitEvent: false, onlySelf: true }); // ensure validation is run even if the field is empty
+ if (this.form.controls.assigneePerson.invalid) {
+ this.errorMessages.push({ title: '', description: CaaCasesFilterErrorMessage.InvalidAssigneeName, fieldId: 'assigneePerson' });
+ isValid = false;
+ }
+ }
+ if (this.form.controls.filterOption.value === CaaCasesFilterType.CaseReferenceNumber) {
+ this.form.controls.caseReferenceNumber.updateValueAndValidity({ emitEvent: false, onlySelf: true }); // ensure validation is run even if the field is empty
+ if (this.form.controls.caseReferenceNumber.invalid) {
+ this.errorMessages.push({ title: '', description: CaaCasesFilterErrorMessage.InvalidCaseReference, fieldId: 'caseReferenceNumber' });
+ isValid = false;
+ }
+ }
+ this.emitErrorMessages.emit(this.errorMessages);
+ return isValid;
+ }
+
+ private handleOnFilterOptionChange(value: CaaCasesFilterType): void {
+ // clear validators for all forms
+ this.form.controls.assigneePerson.clearValidators();
+ this.form.controls.caseReferenceNumber.clearValidators();
+ this.form.controls.assigneePerson.reset();
+ this.form.controls.caseReferenceNumber.reset();
+ switch (value) {
+ case CaaCasesFilterType.AssigneeName:
+ this.form.controls.assigneePerson.setValidators([Validators.required, CaaCasesUtil.assigneeNameValidator2()]);
+ break;
+ case CaaCasesFilterType.CaseReferenceNumber:
+ this.form.controls.caseReferenceNumber.setValidators([Validators.required, CaaCasesUtil.caseReferenceValidator()]);
+ break;
+ case CaaCasesFilterType.AllAssignees:
+ case CaaCasesFilterType.NewCasesToAccept:
+ case CaaCasesFilterType.UnassignedCases:
+ break;
+ }
+ this.form.updateValueAndValidity();
+ }
+}
+
+interface CasesFilterForm {
+ filterOption: FormControl;
+ assigneePerson: FormControl;
+ caseReferenceNumber: FormControl;
+}
diff --git a/src/caa-cases/components/index.ts b/src/caa-cases/components/index.ts
index cb680e597..df597db64 100644
--- a/src/caa-cases/components/index.ts
+++ b/src/caa-cases/components/index.ts
@@ -1,7 +1,10 @@
import { CaaFilterComponent } from './caa-filter/caa-filter.component';
+import { CasesFilterComponent } from './cases-filter/cases-filter.component';
export const components: any[] = [
- CaaFilterComponent
+ CaaFilterComponent,
+ CasesFilterComponent
];
export * from './caa-filter/caa-filter.component';
+export * from './cases-filter/cases-filter.component';
diff --git a/src/caa-cases/containers/cases/cases.component.html b/src/caa-cases/containers/cases/cases.component.html
index f4a68679d..5bef7829e 100644
--- a/src/caa-cases/containers/cases/cases.component.html
+++ b/src/caa-cases/containers/cases/cases.component.html
@@ -13,7 +13,7 @@ {{ pageTitle }}
{{ showFilterSection ? "Hide cases filter" : "Show cases filter" }}
+
;
+ public selectedOrganisationUsers$: Observable;
public pageTitle = 'Cases';
public showFilterSection = false;
- public errorMessages: ErrorMessage[];
+ public errorMessages: ErrorMessage[] = [];
constructor(private readonly caaCasesStore: Store,
private readonly organisationStore: Store,
@@ -33,6 +36,21 @@ export class CasesComponent implements OnInit {
// Load selected organisation details from store
this.organisationStore.dispatch(new organisationStore.LoadOrganisation());
this.selectedOrganisation$ = this.organisationStore.pipe(select(organisationStore.getOrganisationSel));
+
+ // Load users of selected organisation from store
+ this.userStore.dispatch(new userStore.LoadAllUsersNoRoleData());
+ this.selectedOrganisationUsers$ = this.userStore.pipe(select(userStore.getGetUserList));
+ }
+
+ public onSelectedFilter(selectedFilter: SelectedCaseFilter): void {
+ console.log('Selected filter:', selectedFilter);
+ // todo: update session state (i.e. remove or store)
+
+ // load cases types based on fileter and value
+ }
+
+ public onErrorMessages(errorMessages: ErrorMessage[]): void {
+ this.errorMessages = errorMessages;
}
public toggleFilterSection(): void {
diff --git a/src/caa-cases/models/caa-cases.enum.ts b/src/caa-cases/models/caa-cases.enum.ts
index e50f4c00c..bdc718742 100644
--- a/src/caa-cases/models/caa-cases.enum.ts
+++ b/src/caa-cases/models/caa-cases.enum.ts
@@ -14,7 +14,9 @@ export enum CaaCasesFilterType {
AllAssignees = 'all-assignees',
AssigneeName = 'assignee-name',
CaseReferenceNumber = 'case-reference-number',
- None = 'none'
+ NewCasesToAccept = 'new-cases-to-accept',
+ UnassignedCases = 'unassigned-cases',
+ None = 'none',
}
export enum CaaCasesPageTitle {
diff --git a/src/caa-cases/models/selected-case-filter.model.ts b/src/caa-cases/models/selected-case-filter.model.ts
new file mode 100644
index 000000000..77a3e7548
--- /dev/null
+++ b/src/caa-cases/models/selected-case-filter.model.ts
@@ -0,0 +1,6 @@
+import { CaaCasesFilterType } from './caa-cases.enum';
+
+export interface SelectedCaseFilter {
+ filterType: CaaCasesFilterType;
+ filterValue: string;
+}
diff --git a/src/caa-cases/util/caa-cases.util.ts b/src/caa-cases/util/caa-cases.util.ts
index bc178e193..c8ef2a00e 100644
--- a/src/caa-cases/util/caa-cases.util.ts
+++ b/src/caa-cases/util/caa-cases.util.ts
@@ -47,4 +47,16 @@ export class CaaCasesUtil {
return null;
};
}
+
+ public static assigneeNameValidator2(): ValidatorFn {
+ return (control: AbstractControl): ValidationErrors | null => {
+ if (!control.value) {
+ return { assigneeName: true };
+ }
+ if (typeof control.value !== 'string' || control.value.includes('@') || control.value.includes('-')) {
+ return { assigneeName: true };
+ }
+ return null;
+ };
+ }
}
From 09ba297c11e396d4866875d8d6a7b307d353e4e6 Mon Sep 17 00:00:00 2001
From: Shaed Parkar
Date: Fri, 15 Mar 2024 23:21:32 +0000
Subject: [PATCH 05/44] GA-206 track and populate filter selection from session
storage
---
.../cases-filter/cases-filter.component.html | 2 +-
.../cases-filter/cases-filter.component.ts | 47 ++++++++++++++++---
.../containers/cases/cases.component.html | 11 +----
.../containers/cases/cases.component.ts | 37 +++++++++++++++
4 files changed, 80 insertions(+), 17 deletions(-)
diff --git a/src/caa-cases/components/cases-filter/cases-filter.component.html b/src/caa-cases/components/cases-filter/cases-filter.component.html
index 2aa0d3988..271c46716 100644
--- a/src/caa-cases/components/cases-filter/cases-filter.component.html
+++ b/src/caa-cases/components/cases-filter/cases-filter.component.html
@@ -94,7 +94,7 @@ Filter cases
autoActiveFirstOption
#auto="matAutocomplete"
(optionSelected)="
- onSelectionChange($event.option.value)
+ onUserSelectionChange($event.option.value)
"
>
();
@Output() public emitErrorMessages = new EventEmitter();
@@ -27,8 +29,8 @@ export class CasesFilterComponent implements OnInit{
public filteredAndGroupedUsers = new Map();
- public caaCasesFilterType = CaaCasesFilterType;
- public selectedFilterType: CaaCasesFilterType;
+ public caaCasesFilterType = CaaCasesFilterType; // used in the template
+ public selectedFilterType = CaaCasesFilterType.None;
public errorMessages: ErrorMessage[];
@@ -41,6 +43,17 @@ export class CasesFilterComponent implements OnInit{
this.createForm();
}
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes.selectedOrganisationUsers &&
+ changes.selectedOrganisationUsers.currentValue &&
+ changes.selectedOrganisationUsers.currentValue.length > 0) {
+ this.filterSelectedOrganisationUsers().subscribe((filteredAndGroupedUsers) => {
+ this.filteredAndGroupedUsers = filteredAndGroupedUsers;
+ });
+ this.populateFormFromSessionState();
+ }
+ }
+
createForm() {
this.form = this.formBuilder.group({
filterOption: this.formBuilder.control(CaaCasesFilterType.None),
@@ -68,6 +81,28 @@ export class CasesFilterComponent implements OnInit{
});
}
+ public populateFormFromSessionState(): void {
+ if (this.sessionStateValue) {
+ const filterOptionValue = this.sessionStateValue.filterType as CaaCasesFilterType;
+ this.form.controls.filterOption.setValue(filterOptionValue, { emitEvent: false, onlySelf: true });
+
+ this.selectFilterOption(filterOptionValue);
+ if (filterOptionValue === CaaCasesFilterType.AssigneeName) {
+ const assigneePersonValue = this.sessionStateValue.assigneeName;
+ const user = this.selectedOrganisationUsers.find((user) => user.userIdentifier === assigneePersonValue);
+
+ this.form.controls.assigneePerson.setValue(this.getDisplayName(user), { emitEvent: false, onlySelf: true });
+ }
+
+ if (filterOptionValue === CaaCasesFilterType.CaseReferenceNumber) {
+ const caseReferenceNumberValue = this.sessionStateValue.caseReferenceNumber;
+ this.form.controls.caseReferenceNumber.setValue(caseReferenceNumberValue, { emitEvent: false, onlySelf: true });
+ }
+
+ this.form.markAsDirty();
+ }
+ }
+
public filterSelectedOrganisationUsers(searchTerm?: string | User): Observable> {
const filteredUsers = searchTerm && searchTerm.length > 0
? typeof(searchTerm) === 'string'
@@ -109,11 +144,11 @@ export class CasesFilterComponent implements OnInit{
}
public onReset(): void {
- this.form.reset();
+ this.form.reset({ filterOption: CaaCasesFilterType.None, assigneePerson: '', caseReferenceNumber: '' });
this.selectedFilter.emit({ filterType: this.selectedFilterType, filterValue: '' });
}
- public onSelectionChange(selectedUser: User) {
+ public onUserSelectionChange(selectedUser: User) {
this.form.controls.assigneePerson.clearValidators();
this.form.controls.assigneePerson.updateValueAndValidity();
this.form.controls.assigneePerson.setValue(this.getDisplayName(selectedUser), { emitEvent: false, onlySelf: true });
diff --git a/src/caa-cases/containers/cases/cases.component.html b/src/caa-cases/containers/cases/cases.component.html
index 5bef7829e..4c7a4b6fe 100644
--- a/src/caa-cases/containers/cases/cases.component.html
+++ b/src/caa-cases/containers/cases/cases.component.html
@@ -37,19 +37,10 @@
-
-
diff --git a/src/caa-cases/containers/cases/cases.component.ts b/src/caa-cases/containers/cases/cases.component.ts
index 6c9e9978e..a3fd55704 100644
--- a/src/caa-cases/containers/cases/cases.component.ts
+++ b/src/caa-cases/containers/cases/cases.component.ts
@@ -11,6 +11,8 @@ import { Router } from '@angular/router';
import { ErrorMessage } from 'src/shared/models/error-message.model';
import { User } from '@hmcts/rpx-xui-common-lib';
import { SelectedCaseFilter } from 'src/caa-cases/models/selected-case-filter.model';
+import { CaaCasesSessionState, CaaCasesSessionStateValue } from 'src/caa-cases/models/caa-cases.model';
+import { CaaCasesFilterType } from 'src/caa-cases/models/caa-cases.enum';
@Component({
selector: 'app-cases',
@@ -18,12 +20,15 @@ import { SelectedCaseFilter } from 'src/caa-cases/models/selected-case-filter.mo
styleUrls: ['./cases.component.scss']
})
export class CasesComponent implements OnInit {
+ private readonly caaCasesPageType = 'all-cases-filter';
+
public selectedOrganisation$: Observable;
public selectedOrganisationUsers$: Observable;
public pageTitle = 'Cases';
public showFilterSection = false;
public errorMessages: ErrorMessage[] = [];
+ public sessionStateValue: CaaCasesSessionStateValue;
constructor(private readonly caaCasesStore: Store,
private readonly organisationStore: Store,
@@ -40,11 +45,19 @@ export class CasesComponent implements OnInit {
// Load users of selected organisation from store
this.userStore.dispatch(new userStore.LoadAllUsersNoRoleData());
this.selectedOrganisationUsers$ = this.userStore.pipe(select(userStore.getGetUserList));
+
+ // Retrieve session state to check and pre-populate the previous state if any
+ this.retrieveSessionState();
}
public onSelectedFilter(selectedFilter: SelectedCaseFilter): void {
console.log('Selected filter:', selectedFilter);
// todo: update session state (i.e. remove or store)
+ if (selectedFilter.filterType === CaaCasesFilterType.None) {
+ this.removeSessionState(this.caaCasesPageType);
+ } else {
+ this.storeSessionState(selectedFilter);
+ }
// load cases types based on fileter and value
}
@@ -60,4 +73,28 @@ export class CasesComponent implements OnInit {
public isAnyError(): boolean {
return Array.isArray(this.errorMessages) && this.errorMessages.length > 0;
}
+
+ public removeSessionState(key: string): void {
+ this.service.removeSessionState(key);
+ }
+
+ public retrieveSessionState(): void {
+ this.sessionStateValue = this.service.retrieveSessionState(this.caaCasesPageType);
+ if (this.sessionStateValue) {
+ this.toggleFilterSection();
+ }
+ }
+
+ public storeSessionState(selectedFilter: SelectedCaseFilter): void {
+ const sessionStateToUpdate: CaaCasesSessionState = {
+ key: this.caaCasesPageType,
+ value: {
+ filterType: selectedFilter.filterType,
+ caseReferenceNumber: selectedFilter.filterType === CaaCasesFilterType.CaseReferenceNumber ? selectedFilter.filterValue : null,
+ assigneeName: selectedFilter.filterType === CaaCasesFilterType.AssigneeName ? selectedFilter.filterValue : null
+ }
+ };
+ this.sessionStateValue = sessionStateToUpdate.value;
+ this.service.storeSessionState(sessionStateToUpdate);
+ }
}
From 9e1ff0834a14437ddfe01e18c9be3df6fdcd446b Mon Sep 17 00:00:00 2001
From: Shaed Parkar
Date: Mon, 18 Mar 2024 23:27:38 +0000
Subject: [PATCH 06/44] WIP: create a results table component to display case
data
---
.../cases-results-table.component.html | 76 +++++++++
.../cases-results-table.component.scss | 0
.../cases-results-table.component.spec.ts | 23 +++
.../cases-results-table.component.ts | 149 ++++++++++++++++++
src/caa-cases/components/index.ts | 5 +-
.../caa-cases/caa-cases.component.ts | 2 +-
.../containers/cases/cases.component.html | 10 ++
.../containers/cases/cases.component.ts | 103 +++++++++++-
8 files changed, 362 insertions(+), 6 deletions(-)
create mode 100644 src/caa-cases/components/cases-results-table/cases-results-table.component.html
create mode 100644 src/caa-cases/components/cases-results-table/cases-results-table.component.scss
create mode 100644 src/caa-cases/components/cases-results-table/cases-results-table.component.spec.ts
create mode 100644 src/caa-cases/components/cases-results-table/cases-results-table.component.ts
diff --git a/src/caa-cases/components/cases-results-table/cases-results-table.component.html b/src/caa-cases/components/cases-results-table/cases-results-table.component.html
new file mode 100644
index 000000000..c4efd9392
--- /dev/null
+++ b/src/caa-cases/components/cases-results-table/cases-results-table.component.html
@@ -0,0 +1,76 @@
+ 0"
+>
+
+
+ This view has not been configured for the case type.
+
+ 0">
+
+
+
+ Showing {{ getFirstResult() }} to
+ {{ getLastResult() }} of
+ {{ getTotalResults() }} {{ currentCaseType }} cases
+
+
+
+ Select any {{ currentCaseType }} cases you want to
+ manage case sharing for.
+
+
+
+
+
+
+
+ Share case
+
+
+
0 && tableConfig"
+ [cases]="cases"
+ [selectedCases]="selectedCases"
+ [tableConfig]="tableConfig"
+ [selectionEnabled]="true"
+ (selection)="onCaseSelection($event)"
+ (pageChange)="onPaginationHandler($event)"
+ [currentPageNo]="currentPageNo"
+ [totalResultsCount]="totalCases"
+ [pageSize]="paginationPageSize"
+ >
+
+
+
+
diff --git a/src/caa-cases/components/cases-results-table/cases-results-table.component.scss b/src/caa-cases/components/cases-results-table/cases-results-table.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/caa-cases/components/cases-results-table/cases-results-table.component.spec.ts b/src/caa-cases/components/cases-results-table/cases-results-table.component.spec.ts
new file mode 100644
index 000000000..f4447ed40
--- /dev/null
+++ b/src/caa-cases/components/cases-results-table/cases-results-table.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CasesResultsTableComponent } from './cases-results-table.component';
+
+describe('CasesResultsTableComponent', () => {
+ let component: CasesResultsTableComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ CasesResultsTableComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(CasesResultsTableComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/caa-cases/components/cases-results-table/cases-results-table.component.ts b/src/caa-cases/components/cases-results-table/cases-results-table.component.ts
new file mode 100644
index 000000000..2c3dff734
--- /dev/null
+++ b/src/caa-cases/components/cases-results-table/cases-results-table.component.ts
@@ -0,0 +1,149 @@
+import { HttpErrorResponse } from '@angular/common/http';
+import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
+import { MatTabGroup } from '@angular/material/tabs';
+import { TableConfig } from '@hmcts/ccd-case-ui-toolkit';
+import { SharedCase, SubNavigation } from '@hmcts/rpx-xui-common-lib';
+import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+
+import * as fromStore from '../../store';
+import { CaaCases } from 'api/caaCases/interfaces';
+
+@Component({
+ selector: 'app-cases-results-table',
+ templateUrl: './cases-results-table.component.html',
+ styleUrls: ['./cases-results-table.component.scss']
+})
+export class CasesResultsTableComponent {
+ private _allCaseTypes: SubNavigation[];
+ private _cases: any; // can we type this?
+
+ @Input() set allCaseTypes(value: SubNavigation[]) {
+ this._allCaseTypes = value;
+ this.fixCurrentTab(this._allCaseTypes);
+ }
+
+ @Input() set casesConfig(value: CaaCases) {
+ if (value){
+ this.tableConfig = value;
+ this.setTableConfig(this.tableConfig);
+ }
+ }
+
+ get cases(): SubNavigation[] {
+ return this._cases;
+ }
+
+ @Input() set cases(value: any) {
+ if (value){
+ this._cases = value;
+ }
+ }
+
+ @Input() shareAssignedCases$: Observable;
+ @Input() shareUnassignedCases$: Observable;
+ @Input() paginationPageSize: number = 25;
+
+ @Output() public caseSelected = new EventEmitter();
+ @Output() public pageChanged = new EventEmitter();
+
+ // Needed for the tab group
+ public navItems: any[];
+ public currentPageNo: number;
+ public totalCases: number = 0;
+ public tableConfig: TableConfig;
+ public currentCaseType: string;
+
+ public casesError$: Observable;
+ public noCasesFoundMessage = '';
+
+ public selectedCases: any[] = [];
+ public selectedAssignedCases: any[] = [];
+ public selectedUnassignedCases: any[] = [];
+
+ @ViewChild('tabGroup') public tabGroup: MatTabGroup;
+
+ /**
+ *
+ */
+ constructor(private readonly store: Store,) {
+
+ }
+
+ private fixCurrentTab(items: any): void {
+ this.navItems = items;
+ if (items && items.length > 0) {
+ this.totalCases = items[0].total ? items[0].total : 0;
+ this.setTabItems(items[0].text);
+ } else {
+ this.totalCases = 0;
+ // this.noCasesFoundMessage = this.getNoCasesFoundMessage();
+ }
+ }
+
+ private setTabItems(tabName: string, fromTabChangedEvent?: boolean): void {
+ this.resetPaginationParameters();
+ // if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases) {
+ // this.store.pipe(select(fromStore.getAllUnassignedCases));
+ // } else {
+ // this.store.pipe(select(fromStore.getAllAssignedCases));
+ // }
+ // this.shareAssignedCases$ = this.store.pipe(select(fromStore.getShareAssignedCaseListState));
+ // this.shareUnassignedCases$ = this.store.pipe(select(fromStore.getShareUnassignedCaseListState));
+ this.currentCaseType = tabName;
+ if (!fromTabChangedEvent && this.tabGroup) {
+ this.tabGroup.selectedIndex = 0;
+ }
+ // this.loadDataFromStore();
+ }
+
+ public resetPaginationParameters(): void {
+ this.currentPageNo = 1;
+ }
+
+ public hasResults(): any {
+ return this.totalCases;
+ }
+
+ public getFirstResult(): number {
+ return ((this.currentPageNo - 1) * this.paginationPageSize) + 1;
+ }
+
+ public getLastResult(): number {
+ const count = ((this.currentPageNo) * this.paginationPageSize);
+ return count >= this.totalCases ? this.totalCases : count < this.totalCases ? count : 1;
+ }
+
+ public getTotalResults(): number {
+ return this.totalCases;
+ }
+
+ public setTableConfig(config: TableConfig): void {
+ if (config !== null) {
+ this.tableConfig = {
+ idField: config.idField,
+ columnConfigs: config.columnConfigs
+ };
+ }
+ }
+
+ public onCaseSelection(selectedCases: any[]): void {
+ this.caseSelected.emit(selectedCases);
+ }
+
+ public onPaginationHandler(pageNo: number): void {
+ this.currentPageNo = pageNo;
+ this.pageChanged.emit(pageNo);
+ }
+
+ public shareAssignedCaseSubmit(): void {
+ // TODO: emit this action
+ }
+
+ public shareUnassignedCaseSubmit(): void {
+ // this.store.dispatch(new fromStore.AddShareUnassignedCases({
+ // sharedCases: converters.toShareCaseConverter(this.selectedUnassignedCases, this.currentCaseType)
+ // }));
+ // TODO: emit this action
+ }
+}
diff --git a/src/caa-cases/components/index.ts b/src/caa-cases/components/index.ts
index df597db64..0931b4ec4 100644
--- a/src/caa-cases/components/index.ts
+++ b/src/caa-cases/components/index.ts
@@ -1,10 +1,13 @@
import { CaaFilterComponent } from './caa-filter/caa-filter.component';
import { CasesFilterComponent } from './cases-filter/cases-filter.component';
+import { CasesResultsTableComponent } from './cases-results-table/cases-results-table.component';
export const components: any[] = [
CaaFilterComponent,
- CasesFilterComponent
+ CasesFilterComponent,
+ CasesResultsTableComponent
];
export * from './caa-filter/caa-filter.component';
export * from './cases-filter/cases-filter.component';
+export * from './cases-results-table/cases-results-table.component';
diff --git a/src/caa-cases/containers/caa-cases/caa-cases.component.ts b/src/caa-cases/containers/caa-cases/caa-cases.component.ts
index f0e65c2b2..7465a0d10 100644
--- a/src/caa-cases/containers/caa-cases/caa-cases.component.ts
+++ b/src/caa-cases/containers/caa-cases/caa-cases.component.ts
@@ -45,7 +45,7 @@ export class CaaCasesComponent implements OnInit {
public navItems: any[];
public currentPageNo: number;
- public paginationPageSize: number = 25;
+ public paginationPageSize: number = 1;
public totalCases: number = 0;
public pageTitle: string;
public caaCasesPageType: string;
diff --git a/src/caa-cases/containers/cases/cases.component.html b/src/caa-cases/containers/cases/cases.component.html
index 4c7a4b6fe..2b7235615 100644
--- a/src/caa-cases/containers/cases/cases.component.html
+++ b/src/caa-cases/containers/cases/cases.component.html
@@ -42,5 +42,15 @@
(emitErrorMessages)="onErrorMessages($event)"
>
+
diff --git a/src/caa-cases/containers/cases/cases.component.ts b/src/caa-cases/containers/cases/cases.component.ts
index a3fd55704..1e52be747 100644
--- a/src/caa-cases/containers/cases/cases.component.ts
+++ b/src/caa-cases/containers/cases/cases.component.ts
@@ -9,10 +9,12 @@ import { OrganisationDetails } from 'src/models/organisation.model';
import { Observable } from 'rxjs';
import { Router } from '@angular/router';
import { ErrorMessage } from 'src/shared/models/error-message.model';
-import { User } from '@hmcts/rpx-xui-common-lib';
+import { SharedCase, SubNavigation, User } from '@hmcts/rpx-xui-common-lib';
import { SelectedCaseFilter } from 'src/caa-cases/models/selected-case-filter.model';
-import { CaaCasesSessionState, CaaCasesSessionStateValue } from 'src/caa-cases/models/caa-cases.model';
-import { CaaCasesFilterType } from 'src/caa-cases/models/caa-cases.enum';
+import { CaaCases, CaaCasesSessionState, CaaCasesSessionStateValue } from 'src/caa-cases/models/caa-cases.model';
+import { CaaCasesFilterType, CaaCasesPageType } from 'src/caa-cases/models/caa-cases.enum';
+import { HttpErrorResponse } from '@angular/common/http';
+import * as converters from '../../converters/case-converter';
@Component({
selector: 'app-cases',
@@ -30,6 +32,16 @@ export class CasesComponent implements OnInit {
public errorMessages: ErrorMessage[] = [];
public sessionStateValue: CaaCasesSessionStateValue;
+ // for the results table
+ public allCaseTypes: SubNavigation[];
+ public currentPageNo: number;
+ public paginationPageSize: number = 25;
+ public casesConfig: CaaCases;
+ public cases: any; // can we type this?
+ public casesError$: Observable;
+ public shareAssignedCases$: Observable;
+ public shareUnassignedCases$: Observable;
+
constructor(private readonly caaCasesStore: Store,
private readonly organisationStore: Store,
private readonly userStore: Store,
@@ -38,6 +50,9 @@ export class CasesComponent implements OnInit {
}
public ngOnInit(): void {
+ // this.loadCaseTypes(selectedFilterType, selectedFilterValue);
+ this.loadCaseTypes();
+
// Load selected organisation details from store
this.organisationStore.dispatch(new organisationStore.LoadOrganisation());
this.selectedOrganisation$ = this.organisationStore.pipe(select(organisationStore.getOrganisationSel));
@@ -48,6 +63,61 @@ export class CasesComponent implements OnInit {
// Retrieve session state to check and pre-populate the previous state if any
this.retrieveSessionState();
+
+ // TODO: clean this up to get all cases
+ this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCases)).subscribe((config: CaaCases) => {
+ if (config){
+ this.casesConfig = config;
+ }
+ });
+ this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCaseData)).subscribe((items) => {
+ if (items){
+ this.cases = items;
+ }
+ });
+ this.casesError$ = this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCasesError));
+
+ this.shareAssignedCases$ = this.caaCasesStore.pipe(select(caaCasesStore.getShareAssignedCaseListState));
+ this.shareUnassignedCases$ = this.caaCasesStore.pipe(select(caaCasesStore.getShareUnassignedCaseListState));
+ }
+
+ /**
+ * This will load all case types based on the selected filter type and value
+ */
+ public loadCaseTypes() {
+ // TODO: get selected filter type and selected filter value from somewhere
+ const selectedFilterType = CaaCasesPageType.UnassignedCases; // todo: this will be all cases since it's a merge of both assigned and unassigned cases
+ const pageType = CaaCasesPageType.UnassignedCases; // todo: this will be all cases since it's a merge of both assigned and unassigned cases
+ const selectedFilterValue = null;
+ // Load case types based on current page type according to filtered value
+ this.caaCasesStore.dispatch(new caaCasesStore.LoadCaseTypes({
+ caaCasesPageType: pageType,
+ caaCasesFilterType: selectedFilterType,
+ caaCasesFilterValue: selectedFilterValue })
+ );
+ this.caaCasesStore.pipe(select(caaCasesStore.getAllCaseTypes)).subscribe((items) => {
+ this.allCaseTypes = items;
+ this.loadCases();
+ });
+ }
+
+ /**
+ * This will load cases (i.e. unassigned or assigned) from the API with the selected filter type and value
+ */
+ public loadCases(){
+ if (this.allCaseTypes && this.allCaseTypes.length > 0) {
+ const selectedFilterType = CaaCasesFilterType.None; // todo: this will be all cases since it's a merge of both assigned and unassigned cases
+ const selectedFilterValue = null;
+ const currentCaseType = this.allCaseTypes[0].text;
+
+ this.caaCasesStore.dispatch(new caaCasesStore.LoadUnassignedCases({
+ caseType: currentCaseType,
+ pageNo: this.currentPageNo,
+ pageSize: this.paginationPageSize,
+ caaCasesFilterType: selectedFilterType,
+ caaCasesFilterValue: selectedFilterValue
+ }));
+ }
}
public onSelectedFilter(selectedFilter: SelectedCaseFilter): void {
@@ -59,7 +129,7 @@ export class CasesComponent implements OnInit {
this.storeSessionState(selectedFilter);
}
- // load cases types based on fileter and value
+ // load cases types based on filter and value
}
public onErrorMessages(errorMessages: ErrorMessage[]): void {
@@ -97,4 +167,29 @@ export class CasesComponent implements OnInit {
this.sessionStateValue = sessionStateToUpdate.value;
this.service.storeSessionState(sessionStateToUpdate);
}
+
+ public onCaseSelected(selectedCases: any[]): void {
+ // if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases) {
+ // this.selectedUnassignedCases = selectedCases;
+ // this.store.dispatch(new fromStore.SynchronizeStateToStoreUnassignedCases(
+ // converters.toShareCaseConverter(selectedCases, this.currentCaseType)
+ // ));
+ // } else {
+ // this.selectedAssignedCases = selectedCases;
+ // this.store.dispatch(new fromStore.SynchronizeStateToStoreAssignedCases(
+ // converters.toShareCaseConverter(selectedCases, this.currentCaseType)
+ // ));
+ // }
+
+ // do i need the line below?
+ // this.selectedUnassignedCases = selectedCases;
+ this.caaCasesStore.dispatch(new caaCasesStore.SynchronizeStateToStoreUnassignedCases(
+ converters.toShareCaseConverter(selectedCases, CaaCasesPageType.UnassignedCases)
+ ));
+ }
+
+ public onPageChanged(pageNo: number): void {
+ this.currentPageNo = pageNo;
+ this.loadCases();
+ }
}
From 3802e24c85e93c2207f0218ddc1000e715c93636 Mon Sep 17 00:00:00 2001
From: Shaed Parkar
Date: Wed, 20 Mar 2024 22:14:05 +0000
Subject: [PATCH 07/44] WIP Add new route for case sharing and update filter
type enum
---
src/caa-cases/caa-cases.routing.ts | 9 +
.../caa-filter/caa-filter.component.html | 14 +-
.../caa-filter/caa-filter.component.spec.ts | 8 +-
.../caa-filter/caa-filter.component.ts | 4 +-
.../cases-filter/cases-filter.component.html | 25 ++-
.../cases-filter/cases-filter.component.ts | 16 +-
.../cases-results-table.component.html | 21 +-
.../cases-results-table.component.ts | 72 +++----
.../caa-cases/caa-cases.component.spec.ts | 14 +-
.../caa-cases/caa-cases.component.ts | 8 +-
.../containers/cases/cases.component.html | 5 +-
.../containers/cases/cases.component.ts | 184 +++++++++++++-----
src/caa-cases/models/caa-cases.enum.ts | 8 +-
.../services/caa-cases.service.spec.ts | 2 +-
14 files changed, 244 insertions(+), 146 deletions(-)
diff --git a/src/caa-cases/caa-cases.routing.ts b/src/caa-cases/caa-cases.routing.ts
index a1fc6474e..e7f7b8862 100644
--- a/src/caa-cases/caa-cases.routing.ts
+++ b/src/caa-cases/caa-cases.routing.ts
@@ -35,6 +35,15 @@ export const ROUTES: Routes = [
RoleGuard
]
},
+ {
+ path: 'all/case-share',
+ component: CaseShareComponent,
+ canActivate: [
+ AuthGuard,
+ FeatureToggleAccountGuard,
+ RoleGuard
+ ]
+ },
{
path: 'case-share-confirm/:pageType',
component: CaseShareConfirmComponent,
diff --git a/src/caa-cases/components/caa-filter/caa-filter.component.html b/src/caa-cases/components/caa-filter/caa-filter.component.html
index 416b25f15..a5abdd5dd 100644
--- a/src/caa-cases/components/caa-filter/caa-filter.component.html
+++ b/src/caa-cases/components/caa-filter/caa-filter.component.html
@@ -18,26 +18,26 @@
+ (click)="selectFilterOption(caaCasesFilterType.AllAssignedCases)">
All assignees
+ (click)="selectFilterOption(caaCasesFilterType.CasesAssignedToAUser)">
Assignee name
-
+
+
+
+ !
+
+ Warning
+ The tabs below list all of your organisation's cases which are not assigned to any users. You can assign
+ cases to users by selecting 'Manage cases'.
+
+ You do not need to assigned cases to users if they have 'Access all cases in the organisation' enabled for
+ that case type.
+
+
+
+
diff --git a/src/caa-cases/components/cases-filter/cases-filter.component.ts b/src/caa-cases/components/cases-filter/cases-filter.component.ts
index 7c2cff65a..5e5fa34a5 100644
--- a/src/caa-cases/components/cases-filter/cases-filter.component.ts
+++ b/src/caa-cases/components/cases-filter/cases-filter.component.ts
@@ -36,6 +36,7 @@ export class CasesFilterComponent implements OnInit, OnChanges{
public form: FormGroup;
public showAutocomplete: boolean = false;
+ public filterApplied: boolean = false;
public constructor(private formBuilder: FormBuilder) {}
@@ -87,7 +88,7 @@ export class CasesFilterComponent implements OnInit, OnChanges{
this.form.controls.filterOption.setValue(filterOptionValue, { emitEvent: false, onlySelf: true });
this.selectFilterOption(filterOptionValue);
- if (filterOptionValue === CaaCasesFilterType.AssigneeName) {
+ if (filterOptionValue === CaaCasesFilterType.CasesAssignedToAUser) {
const assigneePersonValue = this.sessionStateValue.assigneeName;
const user = this.selectedOrganisationUsers.find((user) => user.userIdentifier === assigneePersonValue);
@@ -98,8 +99,9 @@ export class CasesFilterComponent implements OnInit, OnChanges{
const caseReferenceNumberValue = this.sessionStateValue.caseReferenceNumber;
this.form.controls.caseReferenceNumber.setValue(caseReferenceNumberValue, { emitEvent: false, onlySelf: true });
}
-
+ this.filterApplied = true;
this.form.markAsDirty();
+ this.onSearch();
}
}
@@ -128,7 +130,7 @@ export class CasesFilterComponent implements OnInit, OnChanges{
filterValue = this.form.controls.caseReferenceNumber.value;
}
- if (this.form.controls.filterOption.value === CaaCasesFilterType.AssigneeName) {
+ if (this.form.controls.filterOption.value === CaaCasesFilterType.CasesAssignedToAUser) {
const selectedUser = this.form.controls.assigneePerson.value;
const fullName = selectedUser.split(' - ')[0];
const email = selectedUser.split(' - ')[1];
@@ -139,6 +141,7 @@ export class CasesFilterComponent implements OnInit, OnChanges{
filterType: this.selectedFilterType,
filterValue: filterValue
};
+ this.filterApplied = true;
this.selectedFilter.emit(selectedFilter);
}
}
@@ -146,6 +149,7 @@ export class CasesFilterComponent implements OnInit, OnChanges{
public onReset(): void {
this.form.reset({ filterOption: CaaCasesFilterType.None, assigneePerson: '', caseReferenceNumber: '' });
this.selectedFilter.emit({ filterType: this.selectedFilterType, filterValue: '' });
+ this.filterApplied = false;
}
public onUserSelectionChange(selectedUser: User) {
@@ -161,7 +165,7 @@ export class CasesFilterComponent implements OnInit, OnChanges{
private validateForm(): boolean {
let isValid = true;
this.errorMessages = [];
- if (this.form.controls.filterOption.value === CaaCasesFilterType.AssigneeName) {
+ if (this.form.controls.filterOption.value === CaaCasesFilterType.CasesAssignedToAUser) {
this.form.controls.assigneePerson.updateValueAndValidity({ emitEvent: false, onlySelf: true }); // ensure validation is run even if the field is empty
if (this.form.controls.assigneePerson.invalid) {
this.errorMessages.push({ title: '', description: CaaCasesFilterErrorMessage.InvalidAssigneeName, fieldId: 'assigneePerson' });
@@ -186,13 +190,13 @@ export class CasesFilterComponent implements OnInit, OnChanges{
this.form.controls.assigneePerson.reset();
this.form.controls.caseReferenceNumber.reset();
switch (value) {
- case CaaCasesFilterType.AssigneeName:
+ case CaaCasesFilterType.CasesAssignedToAUser:
this.form.controls.assigneePerson.setValidators([Validators.required, CaaCasesUtil.assigneeNameValidator2()]);
break;
case CaaCasesFilterType.CaseReferenceNumber:
this.form.controls.caseReferenceNumber.setValidators([Validators.required, CaaCasesUtil.caseReferenceValidator()]);
break;
- case CaaCasesFilterType.AllAssignees:
+ case CaaCasesFilterType.AllAssignedCases:
case CaaCasesFilterType.NewCasesToAccept:
case CaaCasesFilterType.UnassignedCases:
break;
diff --git a/src/caa-cases/components/cases-results-table/cases-results-table.component.html b/src/caa-cases/components/cases-results-table/cases-results-table.component.html
index c4efd9392..8342c913d 100644
--- a/src/caa-cases/components/cases-results-table/cases-results-table.component.html
+++ b/src/caa-cases/components/cases-results-table/cases-results-table.component.html
@@ -30,32 +30,17 @@
manage case sharing for.
-
-
-
-
- Share case
+ {{ shareButtonText }}
;
- @Input() shareUnassignedCases$: Observable;
@Input() paginationPageSize: number = 25;
+ @Input() shareButtonText = 'Share case';
@Output() public caseSelected = new EventEmitter();
@Output() public pageChanged = new EventEmitter();
+ @Output() public shareButtonClicked = new EventEmitter();
// Needed for the tab group
public navItems: any[];
@@ -56,6 +56,7 @@ export class CasesResultsTableComponent {
public casesError$: Observable;
public noCasesFoundMessage = '';
+ public enableShareButton = false;
public selectedCases: any[] = [];
public selectedAssignedCases: any[] = [];
@@ -70,31 +71,11 @@ export class CasesResultsTableComponent {
}
- private fixCurrentTab(items: any): void {
- this.navItems = items;
- if (items && items.length > 0) {
- this.totalCases = items[0].total ? items[0].total : 0;
- this.setTabItems(items[0].text);
- } else {
- this.totalCases = 0;
- // this.noCasesFoundMessage = this.getNoCasesFoundMessage();
- }
- }
-
- private setTabItems(tabName: string, fromTabChangedEvent?: boolean): void {
- this.resetPaginationParameters();
- // if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases) {
- // this.store.pipe(select(fromStore.getAllUnassignedCases));
- // } else {
- // this.store.pipe(select(fromStore.getAllAssignedCases));
- // }
- // this.shareAssignedCases$ = this.store.pipe(select(fromStore.getShareAssignedCaseListState));
- // this.shareUnassignedCases$ = this.store.pipe(select(fromStore.getShareUnassignedCaseListState));
- this.currentCaseType = tabName;
- if (!fromTabChangedEvent && this.tabGroup) {
- this.tabGroup.selectedIndex = 0;
- }
- // this.loadDataFromStore();
+ public tabChanged(event: { tab: { textLabel: string }}): void {
+ this.totalCases = this.navItems.find((data) => data.text === event.tab.textLabel)
+ ? this.navItems.find((data) => data.text === event.tab.textLabel).total
+ : 0;
+ this.setTabItems(event.tab.textLabel, true);
}
public resetPaginationParameters(): void {
@@ -129,6 +110,7 @@ export class CasesResultsTableComponent {
public onCaseSelection(selectedCases: any[]): void {
this.caseSelected.emit(selectedCases);
+ this.enableShareButton = selectedCases.length > 0;
}
public onPaginationHandler(pageNo: number): void {
@@ -136,14 +118,38 @@ export class CasesResultsTableComponent {
this.pageChanged.emit(pageNo);
}
- public shareAssignedCaseSubmit(): void {
- // TODO: emit this action
- }
-
- public shareUnassignedCaseSubmit(): void {
+ public onShareButtonClicked(): void {
// this.store.dispatch(new fromStore.AddShareUnassignedCases({
// sharedCases: converters.toShareCaseConverter(this.selectedUnassignedCases, this.currentCaseType)
// }));
// TODO: emit this action
+ this.shareButtonClicked.emit();
+ }
+
+ private fixCurrentTab(items: any): void {
+ this.navItems = items;
+ if (items && items.length > 0) {
+ this.totalCases = items[0].total ? items[0].total : 0;
+ this.setTabItems(items[0].text);
+ } else {
+ this.totalCases = 0;
+ // this.noCasesFoundMessage = this.getNoCasesFoundMessage();
+ }
+ }
+
+ private setTabItems(tabName: string, fromTabChangedEvent?: boolean): void {
+ this.resetPaginationParameters();
+ // if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases) {
+ // this.store.pipe(select(fromStore.getAllUnassignedCases));
+ // } else {
+ // this.store.pipe(select(fromStore.getAllAssignedCases));
+ // }
+ // this.shareAssignedCases$ = this.store.pipe(select(fromStore.getShareAssignedCaseListState));
+ // this.shareUnassignedCases$ = this.store.pipe(select(fromStore.getShareUnassignedCaseListState));
+ this.currentCaseType = tabName;
+ if (!fromTabChangedEvent && this.tabGroup) {
+ this.tabGroup.selectedIndex = 0;
+ }
+ // this.loadDataFromStore();
}
}
diff --git a/src/caa-cases/containers/caa-cases/caa-cases.component.spec.ts b/src/caa-cases/containers/caa-cases/caa-cases.component.spec.ts
index 075c950df..ab64ae592 100644
--- a/src/caa-cases/containers/caa-cases/caa-cases.component.spec.ts
+++ b/src/caa-cases/containers/caa-cases/caa-cases.component.spec.ts
@@ -30,7 +30,7 @@ describe('CaaCasesComponent', () => {
let router: Router;
let caaCasesService: jasmine.SpyObj;
const sessionStateValue: CaaCasesSessionStateValue = {
- filterType: CaaCasesFilterType.AssigneeName,
+ filterType: CaaCasesFilterType.CasesAssignedToAUser,
caseReferenceNumber: null,
assigneeName: 'assignee123'
};
@@ -114,7 +114,7 @@ describe('CaaCasesComponent', () => {
expect(component.selectedFilterType).toEqual(CaaCasesFilterType.None);
component.caaCasesPageType = CaaCasesPageType.AssignedCases;
component.setSelectedFilterTypeAndValue();
- expect(component.selectedFilterType).toEqual(CaaCasesFilterType.AllAssignees);
+ expect(component.selectedFilterType).toEqual(CaaCasesFilterType.AllAssignedCases);
expect(component.selectedFilterValue).toBeNull();
});
@@ -196,12 +196,12 @@ describe('CaaCasesComponent', () => {
component.selectedFilterType = CaaCasesFilterType.CaseReferenceNumber;
expect(component.getNoCasesFoundMessage()).toEqual(CaaCasesNoDataMessage.UnassignedCasesFilterMessage);
component.caaCasesPageType = CaaCasesPageType.AssignedCases;
- component.selectedFilterType = CaaCasesFilterType.AllAssignees;
+ component.selectedFilterType = CaaCasesFilterType.AllAssignedCases;
expect(component.getNoCasesFoundMessage()).toEqual(CaaCasesNoDataMessage.NoAssignedCases);
component.caaCasesPageType = CaaCasesPageType.AssignedCases;
component.selectedFilterType = CaaCasesFilterType.CaseReferenceNumber;
expect(component.getNoCasesFoundMessage()).toEqual(CaaCasesNoDataMessage.AssignedCasesFilterMessage);
- component.selectedFilterType = CaaCasesFilterType.AssigneeName;
+ component.selectedFilterType = CaaCasesFilterType.CasesAssignedToAUser;
expect(component.getNoCasesFoundMessage()).toEqual(CaaCasesNoDataMessage.AssignedCasesFilterMessage);
component.totalCases = 1;
expect(component.getNoCasesFoundMessage()).toEqual('');
@@ -230,8 +230,8 @@ describe('CaaCasesComponent', () => {
});
it('should remove session state', () => {
- component.removeSessionState(CaaCasesFilterType.AssigneeName);
- expect(caaCasesService.removeSessionState).toHaveBeenCalledWith(CaaCasesFilterType.AssigneeName);
+ component.removeSessionState(CaaCasesFilterType.CasesAssignedToAUser);
+ expect(caaCasesService.removeSessionState).toHaveBeenCalledWith(CaaCasesFilterType.CasesAssignedToAUser);
});
it('should retrieve session state', () => {
@@ -240,7 +240,7 @@ describe('CaaCasesComponent', () => {
component.caaCasesPageType = CaaCasesPageType.AssignedCases;
component.retrieveSessionState();
expect(component.sessionStateValue).toEqual(sessionStateValue);
- expect(component.selectedFilterType).toEqual(CaaCasesFilterType.AssigneeName);
+ expect(component.selectedFilterType).toEqual(CaaCasesFilterType.CasesAssignedToAUser);
expect(component.selectedFilterValue).toEqual('assignee123');
expect(component.toggleFilterSection).toHaveBeenCalled();
});
diff --git a/src/caa-cases/containers/caa-cases/caa-cases.component.ts b/src/caa-cases/containers/caa-cases/caa-cases.component.ts
index 7465a0d10..d456af579 100644
--- a/src/caa-cases/containers/caa-cases/caa-cases.component.ts
+++ b/src/caa-cases/containers/caa-cases/caa-cases.component.ts
@@ -175,7 +175,7 @@ export class CaaCasesComponent implements OnInit {
public setSelectedFilterTypeAndValue(): void {
this.selectedFilterType = this.caaCasesPageType === CaaCasesPageType.UnassignedCases
? CaaCasesFilterType.None
- : CaaCasesFilterType.AllAssignees;
+ : CaaCasesFilterType.AllAssignedCases;
this.selectedFilterValue = null;
}
@@ -315,7 +315,7 @@ export class CaaCasesComponent implements OnInit {
if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases && caseReferenceNumber) {
this.selectedFilterValue = caseReferenceNumber;
} else if (this.caaCasesPageType === CaaCasesPageType.AssignedCases) {
- if (this.selectedFilterType === CaaCasesFilterType.AssigneeName && assigneeName) {
+ if (this.selectedFilterType === CaaCasesFilterType.CasesAssignedToAUser && assigneeName) {
this.selectedFilterValue = assigneeName;
} else if (this.selectedFilterType === CaaCasesFilterType.CaseReferenceNumber && caseReferenceNumber) {
this.selectedFilterValue = caseReferenceNumber;
@@ -335,7 +335,7 @@ export class CaaCasesComponent implements OnInit {
value: {
filterType: this.selectedFilterType,
caseReferenceNumber: this.selectedFilterType === CaaCasesFilterType.CaseReferenceNumber ? this.selectedFilterValue : caseReferenceNumber,
- assigneeName: this.selectedFilterType === CaaCasesFilterType.AssigneeName ? this.selectedFilterValue : assigneeName
+ assigneeName: this.selectedFilterType === CaaCasesFilterType.CasesAssignedToAUser ? this.selectedFilterValue : assigneeName
}
};
this.service.storeSessionState(sessionStateToUpdate);
@@ -356,7 +356,7 @@ export class CaaCasesComponent implements OnInit {
}
// Return no cases found messages related to assigned cases
if (this.caaCasesPageType === CaaCasesPageType.AssignedCases) {
- if (this.selectedFilterType === CaaCasesFilterType.AssigneeName || this.selectedFilterType === CaaCasesFilterType.CaseReferenceNumber) {
+ if (this.selectedFilterType === CaaCasesFilterType.CasesAssignedToAUser || this.selectedFilterType === CaaCasesFilterType.CaseReferenceNumber) {
return CaaCasesNoDataMessage.AssignedCasesFilterMessage;
}
return CaaCasesNoDataMessage.NoAssignedCases;
diff --git a/src/caa-cases/containers/cases/cases.component.html b/src/caa-cases/containers/cases/cases.component.html
index 2b7235615..8712d3cc6 100644
--- a/src/caa-cases/containers/cases/cases.component.html
+++ b/src/caa-cases/containers/cases/cases.component.html
@@ -43,14 +43,15 @@
>
diff --git a/src/caa-cases/containers/cases/cases.component.ts b/src/caa-cases/containers/cases/cases.component.ts
index 1e52be747..3002bfc97 100644
--- a/src/caa-cases/containers/cases/cases.component.ts
+++ b/src/caa-cases/containers/cases/cases.component.ts
@@ -9,7 +9,7 @@ import { OrganisationDetails } from 'src/models/organisation.model';
import { Observable } from 'rxjs';
import { Router } from '@angular/router';
import { ErrorMessage } from 'src/shared/models/error-message.model';
-import { SharedCase, SubNavigation, User } from '@hmcts/rpx-xui-common-lib';
+import { SubNavigation, User } from '@hmcts/rpx-xui-common-lib';
import { SelectedCaseFilter } from 'src/caa-cases/models/selected-case-filter.model';
import { CaaCases, CaaCasesSessionState, CaaCasesSessionStateValue } from 'src/caa-cases/models/caa-cases.model';
import { CaaCasesFilterType, CaaCasesPageType } from 'src/caa-cases/models/caa-cases.enum';
@@ -22,7 +22,8 @@ import * as converters from '../../converters/case-converter';
styleUrls: ['./cases.component.scss']
})
export class CasesComponent implements OnInit {
- private readonly caaCasesPageType = 'all-cases-filter';
+ // private caaCasesPageType = 'all-cases-filter'; // todo: this will be all cases since it's a merge of both assigned and unassigned cases
+ private caaCasesPageType = CaaCasesPageType.UnassignedCases; // todo: this will be all cases since it's a merge of both assigned and unassigned cases
public selectedOrganisation$: Observable;
public selectedOrganisationUsers$: Observable;
@@ -32,15 +33,19 @@ export class CasesComponent implements OnInit {
public errorMessages: ErrorMessage[] = [];
public sessionStateValue: CaaCasesSessionStateValue;
+ public selectedFilterType: CaaCasesFilterType = CaaCasesFilterType.None;
+ public selectedFilterValue: string = null;
+ public selectedCaseType: string;
+
// for the results table
- public allCaseTypes: SubNavigation[];
- public currentPageNo: number;
+ public allCaseTypes: SubNavigation[] = [];
+ public currentPageNo: number = 1;
public paginationPageSize: number = 25;
public casesConfig: CaaCases;
public cases: any; // can we type this?
public casesError$: Observable;
- public shareAssignedCases$: Observable;
- public shareUnassignedCases$: Observable;
+ public caseResultsTableShareButtonText: string = 'Share cases';
+ private selectedCases: any[] = [];
constructor(private readonly caaCasesStore: Store,
private readonly organisationStore: Store,
@@ -50,8 +55,12 @@ export class CasesComponent implements OnInit {
}
public ngOnInit(): void {
- // this.loadCaseTypes(selectedFilterType, selectedFilterValue);
- this.loadCaseTypes();
+ // Retrieve session state to check and pre-populate the previous state if any
+ this.retrieveSessionState();
+ // if session state is found, then filter component will emit filter values to avoid double query
+ if (!this.sessionStateValue) {
+ this.loadCaseTypes();
+ }
// Load selected organisation details from store
this.organisationStore.dispatch(new organisationStore.LoadOrganisation());
@@ -61,9 +70,6 @@ export class CasesComponent implements OnInit {
this.userStore.dispatch(new userStore.LoadAllUsersNoRoleData());
this.selectedOrganisationUsers$ = this.userStore.pipe(select(userStore.getGetUserList));
- // Retrieve session state to check and pre-populate the previous state if any
- this.retrieveSessionState();
-
// TODO: clean this up to get all cases
this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCases)).subscribe((config: CaaCases) => {
if (config){
@@ -75,54 +81,70 @@ export class CasesComponent implements OnInit {
this.cases = items;
}
});
- this.casesError$ = this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCasesError));
+ this.caaCasesStore.pipe(select(caaCasesStore.getAllAssignedCases)).subscribe((config: CaaCases) => {
+ if (config){
+ this.casesConfig = config;
+ }
+ });
+ this.caaCasesStore.pipe(select(caaCasesStore.getAllAssignedCaseData)).subscribe((items) => {
+ if (items){
+ this.cases = items;
+ }
+ });
- this.shareAssignedCases$ = this.caaCasesStore.pipe(select(caaCasesStore.getShareAssignedCaseListState));
- this.shareUnassignedCases$ = this.caaCasesStore.pipe(select(caaCasesStore.getShareUnassignedCaseListState));
+ this.casesError$ = this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCasesError));
+ this.casesError$ = this.caaCasesStore.pipe(select(caaCasesStore.getAllAssignedCasesError));
}
/**
* This will load all case types based on the selected filter type and value
*/
public loadCaseTypes() {
- // TODO: get selected filter type and selected filter value from somewhere
- const selectedFilterType = CaaCasesPageType.UnassignedCases; // todo: this will be all cases since it's a merge of both assigned and unassigned cases
- const pageType = CaaCasesPageType.UnassignedCases; // todo: this will be all cases since it's a merge of both assigned and unassigned cases
- const selectedFilterValue = null;
- // Load case types based on current page type according to filtered value
this.caaCasesStore.dispatch(new caaCasesStore.LoadCaseTypes({
- caaCasesPageType: pageType,
- caaCasesFilterType: selectedFilterType,
- caaCasesFilterValue: selectedFilterValue })
+ caaCasesPageType: this.caaCasesPageType,
+ caaCasesFilterType: this.selectedFilterType,
+ caaCasesFilterValue: this.selectedFilterValue })
);
this.caaCasesStore.pipe(select(caaCasesStore.getAllCaseTypes)).subscribe((items) => {
this.allCaseTypes = items;
- this.loadCases();
+ if (this.allCaseTypes && this.allCaseTypes.length > 0) {
+ this.selectedCaseType = this.allCaseTypes[0].text;
+ this.loadCaseData();
+ }
});
}
/**
* This will load cases (i.e. unassigned or assigned) from the API with the selected filter type and value
*/
- public loadCases(){
+ public loadCaseData(){
if (this.allCaseTypes && this.allCaseTypes.length > 0) {
- const selectedFilterType = CaaCasesFilterType.None; // todo: this will be all cases since it's a merge of both assigned and unassigned cases
- const selectedFilterValue = null;
- const currentCaseType = this.allCaseTypes[0].text;
-
- this.caaCasesStore.dispatch(new caaCasesStore.LoadUnassignedCases({
- caseType: currentCaseType,
- pageNo: this.currentPageNo,
- pageSize: this.paginationPageSize,
- caaCasesFilterType: selectedFilterType,
- caaCasesFilterValue: selectedFilterValue
- }));
+ if (this.caaCasesPageType === CaaCasesPageType.AssignedCases) {
+ this.caaCasesStore.dispatch(new caaCasesStore.LoadAssignedCases({
+ caseType: this.selectedCaseType,
+ pageNo: this.currentPageNo,
+ pageSize: this.paginationPageSize,
+ caaCasesFilterType: this.selectedFilterType,
+ caaCasesFilterValue: this.selectedFilterValue
+ }));
+ }
+ if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases){
+ this.caaCasesStore.dispatch(new caaCasesStore.LoadUnassignedCases({
+ caseType: this.selectedCaseType,
+ pageNo: this.currentPageNo,
+ pageSize: this.paginationPageSize,
+ caaCasesFilterType: this.selectedFilterType,
+ caaCasesFilterValue: this.selectedFilterValue
+ }));
+ }
}
}
public onSelectedFilter(selectedFilter: SelectedCaseFilter): void {
console.log('Selected filter:', selectedFilter);
- // todo: update session state (i.e. remove or store)
+ this.selectedFilterType = selectedFilter.filterType;
+ this.selectedFilterValue = selectedFilter.filterValue;
+
if (selectedFilter.filterType === CaaCasesFilterType.None) {
this.removeSessionState(this.caaCasesPageType);
} else {
@@ -130,6 +152,28 @@ export class CasesComponent implements OnInit {
}
// load cases types based on filter and value
+ if (selectedFilter.filterType === CaaCasesFilterType.CaseReferenceNumber) {
+ // dispatch action to load case by ref number
+ this.caseResultsTableShareButtonText = 'Accept and assign cases';
+ }
+ if (selectedFilter.filterType === CaaCasesFilterType.CasesAssignedToAUser) {
+ // dispatch action to load case by assignee name
+ this.caaCasesPageType = CaaCasesPageType.AssignedCases;
+ this.caseResultsTableShareButtonText = 'Manage cases';
+ }
+ if (selectedFilter.filterType === CaaCasesFilterType.AllAssignedCases) {
+ // dispatch action to load all cases
+ this.caseResultsTableShareButtonText = 'Manage cases';
+ }
+ if (selectedFilter.filterType === CaaCasesFilterType.NewCasesToAccept) {
+ // dispatch action to load new cases to accept
+ this.caseResultsTableShareButtonText = 'Accept cases';
+ }
+ if (selectedFilter.filterType === CaaCasesFilterType.UnassignedCases) {
+ // dispatch action to load unassigned cases
+ this.caseResultsTableShareButtonText = 'Manage cases';
+ }
+ this.loadCaseTypes();
}
public onErrorMessages(errorMessages: ErrorMessage[]): void {
@@ -161,7 +205,7 @@ export class CasesComponent implements OnInit {
value: {
filterType: selectedFilter.filterType,
caseReferenceNumber: selectedFilter.filterType === CaaCasesFilterType.CaseReferenceNumber ? selectedFilter.filterValue : null,
- assigneeName: selectedFilter.filterType === CaaCasesFilterType.AssigneeName ? selectedFilter.filterValue : null
+ assigneeName: selectedFilter.filterType === CaaCasesFilterType.CasesAssignedToAUser ? selectedFilter.filterValue : null
}
};
this.sessionStateValue = sessionStateToUpdate.value;
@@ -169,27 +213,59 @@ export class CasesComponent implements OnInit {
}
public onCaseSelected(selectedCases: any[]): void {
- // if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases) {
- // this.selectedUnassignedCases = selectedCases;
- // this.store.dispatch(new fromStore.SynchronizeStateToStoreUnassignedCases(
- // converters.toShareCaseConverter(selectedCases, this.currentCaseType)
- // ));
- // } else {
- // this.selectedAssignedCases = selectedCases;
- // this.store.dispatch(new fromStore.SynchronizeStateToStoreAssignedCases(
- // converters.toShareCaseConverter(selectedCases, this.currentCaseType)
- // ));
- // }
-
- // do i need the line below?
+ // do i need the line below? and remove the selector in ngOnInit
// this.selectedUnassignedCases = selectedCases;
- this.caaCasesStore.dispatch(new caaCasesStore.SynchronizeStateToStoreUnassignedCases(
- converters.toShareCaseConverter(selectedCases, CaaCasesPageType.UnassignedCases)
- ));
+ if (this.caaCasesPageType === CaaCasesPageType.AssignedCases){
+ this.caaCasesStore.dispatch(new caaCasesStore.SynchronizeStateToStoreAssignedCases(
+ converters.toShareCaseConverter(selectedCases, CaaCasesPageType.AssignedCases)
+ ));
+ }
+
+ if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases){
+ this.caaCasesStore.dispatch(new caaCasesStore.SynchronizeStateToStoreUnassignedCases(
+ converters.toShareCaseConverter(selectedCases, CaaCasesPageType.UnassignedCases)
+ ));
+ }
+ this.selectedCases = selectedCases;
}
public onPageChanged(pageNo: number): void {
this.currentPageNo = pageNo;
- this.loadCases();
+ this.loadCaseData();
+ }
+
+ onShareButtonClicked($event: void) {
+ // load cases types based on filter and value
+ if (this.selectedFilterType === CaaCasesFilterType.CaseReferenceNumber) {
+ // TODO: need to handle the `new_case` flag
+ // if returning new case then go to add recipient page
+ // else if returning non-new case then go to manage case assignments
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareAssignedCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ }));
+ }
+ if (this.selectedFilterType === CaaCasesFilterType.CasesAssignedToAUser) {
+ // todo: go to manage case assignments
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareAssignedCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ }
+ ));
+ }
+ if (this.selectedFilterType === CaaCasesFilterType.AllAssignedCases) {
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareAssignedCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ }
+ ));
+ }
+ if (this.selectedFilterType === CaaCasesFilterType.NewCasesToAccept) {
+ // dispatch action to load new cases to accept
+ // if group_access is enabled then go to accept cases page
+ // else go to add recipient
+ }
+ if (this.selectedFilterType === CaaCasesFilterType.UnassignedCases) {
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareUnassignedCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ }));
+ }
}
}
diff --git a/src/caa-cases/models/caa-cases.enum.ts b/src/caa-cases/models/caa-cases.enum.ts
index bdc718742..edd89f7ad 100644
--- a/src/caa-cases/models/caa-cases.enum.ts
+++ b/src/caa-cases/models/caa-cases.enum.ts
@@ -11,11 +11,11 @@ export enum CaaCasesShowHideFilterButtonText {
}
export enum CaaCasesFilterType {
- AllAssignees = 'all-assignees',
- AssigneeName = 'assignee-name',
+ AllAssignedCases = 'all-assignees',
+ CasesAssignedToAUser = 'assignee-name',
CaseReferenceNumber = 'case-reference-number',
- NewCasesToAccept = 'new-cases-to-accept',
- UnassignedCases = 'unassigned-cases',
+ NewCasesToAccept = 'new-cases-to-accept', // new enum
+ UnassignedCases = 'unassigned-cases', // new enum
None = 'none',
}
diff --git a/src/caa-cases/services/caa-cases.service.spec.ts b/src/caa-cases/services/caa-cases.service.spec.ts
index 52992412f..89a0f1ab7 100644
--- a/src/caa-cases/services/caa-cases.service.spec.ts
+++ b/src/caa-cases/services/caa-cases.service.spec.ts
@@ -10,7 +10,7 @@ describe('CaaCasesService', () => {
let mockSessionStorage: any;
let mockHttp: any;
const sessionStateValue: CaaCasesSessionStateValue = {
- filterType: CaaCasesFilterType.AssigneeName,
+ filterType: CaaCasesFilterType.CasesAssignedToAUser,
caseReferenceNumber: null,
assigneeName: 'assignee123'
};
From dd0adb9876babe96922f5073666c0f150b7820b9 Mon Sep 17 00:00:00 2001
From: Shaed Parkar
Date: Mon, 25 Mar 2024 10:06:57 +0000
Subject: [PATCH 08/44] Refactor routes and constants
---
src/app/app.constants.ts | 2 +-
src/app/app.routes.ts | 2 +-
src/caa-cases/caa-cases.routing.ts | 21 +-
src/cases/cases.module.ts | 47 +++
src/cases/cases.routing.ts | 48 +++
.../cases-filter/cases-filter.component.html | 273 ++++++++++++++++++
.../cases-filter/cases-filter.component.scss | 44 +++
.../cases-filter.component.spec.ts | 23 ++
.../cases-filter/cases-filter.component.ts | 212 ++++++++++++++
.../cases-results-table.component.html | 61 ++++
.../cases-results-table.component.scss | 0
.../cases-results-table.component.spec.ts | 23 ++
.../cases-results-table.component.ts | 155 ++++++++++
src/cases/components/index.ts | 10 +
.../case-share-complete.component.html | 68 +++++
.../case-share-complete.component.scss | 11 +
.../case-share-complete.component.spec.ts | 213 ++++++++++++++
.../case-share-complete.component.ts | 90 ++++++
.../case-share-confirm.component.html | 10 +
.../case-share-confirm.component.scss | 0
.../case-share-confirm.component.spec.ts | 63 ++++
.../case-share-confirm.component.ts | 51 ++++
.../case-share/case-share.component.html | 15 +
.../case-share/case-share.component.scss | 0
.../case-share/case-share.component.spec.ts | 69 +++++
.../case-share/case-share.component.ts | 103 +++++++
src/cases/containers/case-share/index.ts | 45 +++
src/cases/containers/case-share/test.spec.ts | 120 ++++++++
.../containers/cases/cases.component.html | 57 ++++
.../containers/cases/cases.component.scss | 0
.../containers/cases/cases.component.spec.ts | 23 ++
src/cases/containers/cases/cases.component.ts | 271 +++++++++++++++++
src/cases/containers/index.ts | 17 ++
src/cases/converters/case-converter.ts | 75 +++++
src/cases/converters/case-converters.spec.ts | 104 +++++++
src/cases/guards/feature-toggle.guard.ts | 14 +
src/cases/guards/user-role.guard.ts | 15 +
src/cases/models/caa-cases.enum.ts | 42 +++
src/cases/models/caa-cases.model.ts | 37 +++
.../models/selected-case-filter.model.ts | 6 +
src/cases/services/caa-cases.service.spec.ts | 101 +++++++
src/cases/services/caa-cases.service.ts | 54 ++++
src/cases/services/index.ts | 10 +
src/cases/services/share-case.service.spec.ts | 54 ++++
src/cases/services/share-case.service.ts | 28 ++
.../store/actions/caa-cases.actions.spec.ts | 99 +++++++
src/cases/store/actions/caa-cases.actions.ts | 76 +++++
src/cases/store/actions/index.ts | 20 ++
.../store/actions/share-case.action.spec.ts | 195 +++++++++++++
src/cases/store/actions/share-case.action.ts | 208 +++++++++++++
.../store/effects/caa-cases.effects.spec.ts | 160 ++++++++++
src/cases/store/effects/caa-cases.effects.ts | 74 +++++
src/cases/store/effects/index.ts | 11 +
.../store/effects/share-case.effects.spec.ts | 265 +++++++++++++++++
src/cases/store/effects/share-case.effects.ts | 148 ++++++++++
src/cases/store/index.ts | 4 +
.../store/reducers/caa-cases.reducer.spec.ts | 61 ++++
src/cases/store/reducers/caa-cases.reducer.ts | 49 ++++
src/cases/store/reducers/index.ts | 21 ++
.../store/reducers/share-case.reducer.spec.ts | 273 ++++++++++++++++++
.../store/reducers/share-case.reducer.ts | 250 ++++++++++++++++
.../selectors/caa-cases.selector.spec.ts | 75 +++++
.../store/selectors/caa-cases.selector.ts | 58 ++++
src/cases/store/selectors/index.ts | 2 +
.../store/selectors/share-case.selector.ts | 23 ++
.../selectors/share-case.selectors.spec.ts | 68 +++++
src/cases/util/caa-cases.util.spec.ts | 115 ++++++++
src/cases/util/caa-cases.util.ts | 62 ++++
68 files changed, 4982 insertions(+), 22 deletions(-)
create mode 100644 src/cases/cases.module.ts
create mode 100644 src/cases/cases.routing.ts
create mode 100644 src/cases/components/cases-filter/cases-filter.component.html
create mode 100644 src/cases/components/cases-filter/cases-filter.component.scss
create mode 100644 src/cases/components/cases-filter/cases-filter.component.spec.ts
create mode 100644 src/cases/components/cases-filter/cases-filter.component.ts
create mode 100644 src/cases/components/cases-results-table/cases-results-table.component.html
create mode 100644 src/cases/components/cases-results-table/cases-results-table.component.scss
create mode 100644 src/cases/components/cases-results-table/cases-results-table.component.spec.ts
create mode 100644 src/cases/components/cases-results-table/cases-results-table.component.ts
create mode 100644 src/cases/components/index.ts
create mode 100644 src/cases/containers/case-share-complete/case-share-complete.component.html
create mode 100644 src/cases/containers/case-share-complete/case-share-complete.component.scss
create mode 100644 src/cases/containers/case-share-complete/case-share-complete.component.spec.ts
create mode 100644 src/cases/containers/case-share-complete/case-share-complete.component.ts
create mode 100644 src/cases/containers/case-share-confirm/case-share-confirm.component.html
create mode 100644 src/cases/containers/case-share-confirm/case-share-confirm.component.scss
create mode 100644 src/cases/containers/case-share-confirm/case-share-confirm.component.spec.ts
create mode 100644 src/cases/containers/case-share-confirm/case-share-confirm.component.ts
create mode 100644 src/cases/containers/case-share/case-share.component.html
create mode 100644 src/cases/containers/case-share/case-share.component.scss
create mode 100644 src/cases/containers/case-share/case-share.component.spec.ts
create mode 100644 src/cases/containers/case-share/case-share.component.ts
create mode 100644 src/cases/containers/case-share/index.ts
create mode 100644 src/cases/containers/case-share/test.spec.ts
create mode 100644 src/cases/containers/cases/cases.component.html
create mode 100644 src/cases/containers/cases/cases.component.scss
create mode 100644 src/cases/containers/cases/cases.component.spec.ts
create mode 100644 src/cases/containers/cases/cases.component.ts
create mode 100644 src/cases/containers/index.ts
create mode 100644 src/cases/converters/case-converter.ts
create mode 100644 src/cases/converters/case-converters.spec.ts
create mode 100644 src/cases/guards/feature-toggle.guard.ts
create mode 100644 src/cases/guards/user-role.guard.ts
create mode 100644 src/cases/models/caa-cases.enum.ts
create mode 100644 src/cases/models/caa-cases.model.ts
create mode 100644 src/cases/models/selected-case-filter.model.ts
create mode 100644 src/cases/services/caa-cases.service.spec.ts
create mode 100644 src/cases/services/caa-cases.service.ts
create mode 100644 src/cases/services/index.ts
create mode 100644 src/cases/services/share-case.service.spec.ts
create mode 100644 src/cases/services/share-case.service.ts
create mode 100644 src/cases/store/actions/caa-cases.actions.spec.ts
create mode 100644 src/cases/store/actions/caa-cases.actions.ts
create mode 100644 src/cases/store/actions/index.ts
create mode 100644 src/cases/store/actions/share-case.action.spec.ts
create mode 100644 src/cases/store/actions/share-case.action.ts
create mode 100644 src/cases/store/effects/caa-cases.effects.spec.ts
create mode 100644 src/cases/store/effects/caa-cases.effects.ts
create mode 100644 src/cases/store/effects/index.ts
create mode 100644 src/cases/store/effects/share-case.effects.spec.ts
create mode 100644 src/cases/store/effects/share-case.effects.ts
create mode 100644 src/cases/store/index.ts
create mode 100644 src/cases/store/reducers/caa-cases.reducer.spec.ts
create mode 100644 src/cases/store/reducers/caa-cases.reducer.ts
create mode 100644 src/cases/store/reducers/index.ts
create mode 100644 src/cases/store/reducers/share-case.reducer.spec.ts
create mode 100644 src/cases/store/reducers/share-case.reducer.ts
create mode 100644 src/cases/store/selectors/caa-cases.selector.spec.ts
create mode 100644 src/cases/store/selectors/caa-cases.selector.ts
create mode 100644 src/cases/store/selectors/index.ts
create mode 100644 src/cases/store/selectors/share-case.selector.ts
create mode 100644 src/cases/store/selectors/share-case.selectors.spec.ts
create mode 100644 src/cases/util/caa-cases.util.spec.ts
create mode 100644 src/cases/util/caa-cases.util.ts
diff --git a/src/app/app.constants.ts b/src/app/app.constants.ts
index 3b35654a5..5910b3f22 100644
--- a/src/app/app.constants.ts
+++ b/src/app/app.constants.ts
@@ -54,7 +54,7 @@ const navItemsArray: NavItemModel[] = [
},
{
text: 'Cases',
- href: '/cases/all',
+ href: '/cases',
orderId: 6,
active: false,
featureToggle: {
diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts
index 97f1cd206..09f667583 100644
--- a/src/app/app.routes.ts
+++ b/src/app/app.routes.ts
@@ -28,7 +28,7 @@ export const ROUTES: Routes = [
{
path: 'cases',
canActivate: [AuthGuard, HealthCheckGuard],
- loadChildren: () => import('../caa-cases/caa-cases.module').then((m) => m.CaaCasesModule)
+ loadChildren: () => import('../cases/cases.module').then((m) => m.CaaCasesModule)
},
{
path: 'unassigned-cases',
diff --git a/src/caa-cases/caa-cases.routing.ts b/src/caa-cases/caa-cases.routing.ts
index e7f7b8862..0823604b6 100644
--- a/src/caa-cases/caa-cases.routing.ts
+++ b/src/caa-cases/caa-cases.routing.ts
@@ -2,21 +2,11 @@ import { ModuleWithProviders } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from '../user-profile/guards/auth.guard';
import { CaaCasesModule } from './caa-cases.module';
-import { CaaCasesComponent, CaseShareCompleteComponent, CaseShareComponent, CaseShareConfirmComponent, CasesComponent } from './containers';
+import { CaaCasesComponent, CaseShareCompleteComponent, CaseShareComponent, CaseShareConfirmComponent } from './containers';
import { FeatureToggleAccountGuard } from './guards/feature-toggle.guard';
import { RoleGuard } from './guards/user-role.guard';
-import { NewCaseFeatureToggleGuard } from './guards/new-cases-feature-toggle.guard';
export const ROUTES: Routes = [
- {
- path: 'all',
- component: CasesComponent,
- canActivate: [
- AuthGuard,
- NewCaseFeatureToggleGuard,
- RoleGuard
- ]
- },
{
path: '',
component: CaaCasesComponent,
@@ -35,15 +25,6 @@ export const ROUTES: Routes = [
RoleGuard
]
},
- {
- path: 'all/case-share',
- component: CaseShareComponent,
- canActivate: [
- AuthGuard,
- FeatureToggleAccountGuard,
- RoleGuard
- ]
- },
{
path: 'case-share-confirm/:pageType',
component: CaseShareConfirmComponent,
diff --git a/src/cases/cases.module.ts b/src/cases/cases.module.ts
new file mode 100644
index 000000000..83699a373
--- /dev/null
+++ b/src/cases/cases.module.ts
@@ -0,0 +1,47 @@
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { MatLegacyAutocompleteModule as MatAutocompleteModule } from '@angular/material/legacy-autocomplete';
+import { MatLegacyTabsModule as MatTabsModule } from '@angular/material/legacy-tabs';
+import { CaseListModule } from '@hmcts/ccd-case-ui-toolkit';
+import { ExuiCommonLibModule } from '@hmcts/rpx-xui-common-lib';
+import { EffectsModule } from '@ngrx/effects';
+import { StoreModule } from '@ngrx/store';
+import { OrganisationService, PBAService } from '../organisation/services';
+import { effects as orgEffects, reducers as orgReducers } from '../organisation/store';
+import { SharedModule } from '../shared/shared.module';
+import { InviteUserService, UsersService } from '../users/services';
+import { effects as userEffects, reducers as userReducers } from '../users/store';
+import { casesRouting } from './cases.routing';
+import * as fromComponents from './components';
+import * as fromContainers from './containers';
+import { FeatureToggleAccountGuard } from './guards/feature-toggle.guard';
+import { RoleGuard } from './guards/user-role.guard';
+import * as fromServices from './services';
+import { effects, reducers } from './store';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ ExuiCommonLibModule,
+ HttpClientModule,
+ SharedModule,
+ casesRouting,
+ StoreModule.forFeature('org', orgReducers),
+ EffectsModule.forFeature(orgEffects),
+ StoreModule.forFeature('users', userReducers),
+ EffectsModule.forFeature(userEffects),
+ StoreModule.forFeature('caaCases', reducers),
+ EffectsModule.forFeature(effects),
+ CaseListModule,
+ MatTabsModule,
+ MatAutocompleteModule
+ ],
+ exports: [...fromContainers.containers, ...fromComponents.components],
+ declarations: [...fromContainers.containers, ...fromComponents.components],
+ providers: [...fromServices.services, OrganisationService, PBAService, UsersService, InviteUserService, FeatureToggleAccountGuard, RoleGuard],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
+})
+
+export class CaaCasesModule {
+}
diff --git a/src/cases/cases.routing.ts b/src/cases/cases.routing.ts
new file mode 100644
index 000000000..a42866983
--- /dev/null
+++ b/src/cases/cases.routing.ts
@@ -0,0 +1,48 @@
+import { ModuleWithProviders } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { AuthGuard } from '../user-profile/guards/auth.guard';
+import { CaaCasesModule } from './cases.module';
+import { CaseShareCompleteComponent, CaseShareComponent, CaseShareConfirmComponent, CasesComponent } from './containers';
+import { FeatureToggleAccountGuard } from './guards/feature-toggle.guard';
+import { RoleGuard } from './guards/user-role.guard';
+
+export const ROUTES: Routes = [
+ {
+ path: '',
+ component: CasesComponent,
+ canActivate: [
+ AuthGuard,
+ FeatureToggleAccountGuard,
+ RoleGuard
+ ]
+ },
+ {
+ path: 'case-share',
+ component: CaseShareComponent,
+ canActivate: [
+ AuthGuard,
+ FeatureToggleAccountGuard,
+ RoleGuard
+ ]
+ },
+ {
+ path: 'case-share-confirm/:pageType',
+ component: CaseShareConfirmComponent,
+ canActivate: [
+ AuthGuard,
+ FeatureToggleAccountGuard,
+ RoleGuard
+ ]
+ },
+ {
+ path: 'case-share-complete/:pageType',
+ component: CaseShareCompleteComponent,
+ canActivate: [
+ AuthGuard,
+ FeatureToggleAccountGuard,
+ RoleGuard
+ ]
+ }
+];
+
+export const casesRouting: ModuleWithProviders = RouterModule.forChild(ROUTES);
diff --git a/src/cases/components/cases-filter/cases-filter.component.html b/src/cases/components/cases-filter/cases-filter.component.html
new file mode 100644
index 000000000..c203d4047
--- /dev/null
+++ b/src/cases/components/cases-filter/cases-filter.component.html
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+ !
+
+ Warning
+ The tabs below list all of your organisation's cases which are not assigned to any users. You can assign
+ cases to users by selecting 'Manage cases'.
+
+ You do not need to assigned cases to users if they have 'Access all cases in the organisation' enabled for
+ that case type.
+
+
+
+
+
+
+
diff --git a/src/cases/components/cases-filter/cases-filter.component.scss b/src/cases/components/cases-filter/cases-filter.component.scss
new file mode 100644
index 000000000..0c0512166
--- /dev/null
+++ b/src/cases/components/cases-filter/cases-filter.component.scss
@@ -0,0 +1,44 @@
+@import "govuk-frontend/govuk/base";
+
+.govuk-grid-row {
+ .govuk-grid-column-one-half {
+ background-color: govuk-colour("light-grey");
+ padding-top: 20px;
+ margin-left: 15px;
+ }
+
+ #filterContainer {
+ margin-bottom: 30px;
+ }
+
+ #assignee-person {
+ width: 90%;
+ }
+
+ #case-reference-number {
+ width: 70%;
+ }
+
+ .hide-autocomplete {
+ display: none;
+ }
+}
+
+.mat-optgroup {
+ .mat-group-header {
+ font-size: 16px !important;
+ font-weight: bold !important;
+ }
+
+ .mat-option {
+ &:hover {
+ background: $govuk-focus-colour;
+ }
+ &.select-option {
+ &:hover {
+ background: govuk-colour("blue");
+ color: govuk-colour("white");
+ }
+ }
+ }
+}
diff --git a/src/cases/components/cases-filter/cases-filter.component.spec.ts b/src/cases/components/cases-filter/cases-filter.component.spec.ts
new file mode 100644
index 000000000..d1c00fb6f
--- /dev/null
+++ b/src/cases/components/cases-filter/cases-filter.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CasesFilterComponent } from './cases-filter.component';
+
+describe('CasesFilterComponent', () => {
+ let component: CasesFilterComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ CasesFilterComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(CasesFilterComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/cases/components/cases-filter/cases-filter.component.ts b/src/cases/components/cases-filter/cases-filter.component.ts
new file mode 100644
index 000000000..0531f8ade
--- /dev/null
+++ b/src/cases/components/cases-filter/cases-filter.component.ts
@@ -0,0 +1,212 @@
+import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
+import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
+import { User } from '@hmcts/rpx-xui-common-lib';
+import { Observable, catchError, debounceTime, of, switchMap, tap } from 'rxjs';
+import { CaaCasesFilterErrorMessage, CaaCasesFilterType } from 'src/cases/models/caa-cases.enum';
+import { CaaCasesSessionStateValue } from 'src/cases/models/caa-cases.model';
+import { SelectedCaseFilter } from 'src/cases/models/selected-case-filter.model';
+import { CaaCasesUtil } from 'src/cases/util/caa-cases.util';
+import { ErrorMessage } from 'src/shared/models/error-message.model';
+
+@Component({
+ selector: 'app-cases-filter',
+ templateUrl: './cases-filter.component.html',
+ styleUrls: ['./cases-filter.component.scss']
+})
+export class CasesFilterComponent implements OnInit, OnChanges{
+ @Input() public selectedOrganisationUsers: User[];
+ @Input() public sessionStateValue: CaaCasesSessionStateValue;
+
+ @Output() public selectedFilter = new EventEmitter();
+ @Output() public emitErrorMessages = new EventEmitter();
+
+ public readonly ACTIVE_USER_GROUP_HEADING = 'Active users:';
+ public readonly INACTIVE_USER_GROUP_HEADING = 'Inactive users:';
+ public readonly ACTIVE_USER_STATUS = 'active';
+
+ public readonly assigneeNameErrorMessage = 'Enter a valid assignee name';
+ public readonly caseReferenceNumberErrorMessage = 'Enter a valid HMCTS case reference number';
+
+ public filteredAndGroupedUsers = new Map();
+
+ public caaCasesFilterType = CaaCasesFilterType; // used in the template
+ public selectedFilterType = CaaCasesFilterType.None;
+
+ public errorMessages: ErrorMessage[];
+
+ public form: FormGroup;
+ public showAutocomplete: boolean = false;
+ public filterApplied: boolean = false;
+
+ public constructor(private formBuilder: FormBuilder) {}
+
+ ngOnInit(): void {
+ this.createForm();
+ }
+
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes.selectedOrganisationUsers &&
+ changes.selectedOrganisationUsers.currentValue &&
+ changes.selectedOrganisationUsers.currentValue.length > 0) {
+ this.filterSelectedOrganisationUsers().subscribe((filteredAndGroupedUsers) => {
+ this.filteredAndGroupedUsers = filteredAndGroupedUsers;
+ });
+ this.populateFormFromSessionState();
+ }
+ }
+
+ createForm() {
+ this.form = this.formBuilder.group({
+ filterOption: this.formBuilder.control(CaaCasesFilterType.None),
+ assigneePerson: this.formBuilder.control(''),
+ caseReferenceNumber: this.formBuilder.control('')
+ });
+
+ this.form.controls.filterOption.valueChanges.subscribe((value: CaaCasesFilterType) => {
+ this.selectFilterOption(value);
+ this.handleOnFilterOptionChange(value);
+ });
+
+ this.form.controls.assigneePerson.valueChanges.pipe(
+ tap(() => {
+ this.showAutocomplete = false;
+ this.filteredAndGroupedUsers = null;
+ },
+ debounceTime(300)),
+ switchMap((searchTerm: any) => this.filterSelectedOrganisationUsers(searchTerm).pipe(
+ tap(() => this.showAutocomplete = true),
+ catchError(() => this.filteredAndGroupedUsers = null)
+ ))
+ ).subscribe((filteredAndGroupedUsers: Map) => {
+ this.filteredAndGroupedUsers = filteredAndGroupedUsers;
+ });
+ }
+
+ public populateFormFromSessionState(): void {
+ if (this.sessionStateValue) {
+ const filterOptionValue = this.sessionStateValue.filterType as CaaCasesFilterType;
+ this.form.controls.filterOption.setValue(filterOptionValue, { emitEvent: false, onlySelf: true });
+
+ this.selectFilterOption(filterOptionValue);
+ if (filterOptionValue === CaaCasesFilterType.CasesAssignedToAUser) {
+ const assigneePersonValue = this.sessionStateValue.assigneeName;
+ const user = this.selectedOrganisationUsers.find((user) => user.userIdentifier === assigneePersonValue);
+
+ this.form.controls.assigneePerson.setValue(this.getDisplayName(user), { emitEvent: false, onlySelf: true });
+ }
+
+ if (filterOptionValue === CaaCasesFilterType.CaseReferenceNumber) {
+ const caseReferenceNumberValue = this.sessionStateValue.caseReferenceNumber;
+ this.form.controls.caseReferenceNumber.setValue(caseReferenceNumberValue, { emitEvent: false, onlySelf: true });
+ }
+ this.filterApplied = true;
+ this.form.markAsDirty();
+ this.onSearch();
+ }
+ }
+
+ public filterSelectedOrganisationUsers(searchTerm?: string | User): Observable> {
+ const filteredUsers = searchTerm && searchTerm.length > 0
+ ? typeof(searchTerm) === 'string'
+ ? this.selectedOrganisationUsers.filter((user) => this.getDisplayName(user).toLowerCase().includes(searchTerm.toLowerCase()))
+ : this.selectedOrganisationUsers.filter((user) => this.getDisplayName(user).toLowerCase().includes(this.getDisplayName(searchTerm).toLowerCase()))
+ : this.selectedOrganisationUsers;
+ const activeUsers = filteredUsers.filter((user) => user.status.toLowerCase() === this.ACTIVE_USER_STATUS);
+ const inactiveUsers = filteredUsers.filter((user) => user.status.toLowerCase() !== this.ACTIVE_USER_STATUS);
+ const groupedUsers = new Map();
+ groupedUsers.set(this.ACTIVE_USER_GROUP_HEADING, activeUsers);
+ groupedUsers.set(this.INACTIVE_USER_GROUP_HEADING, inactiveUsers);
+ return of(groupedUsers);
+ }
+
+ public getDisplayName(selectedUser: User): string {
+ return `${selectedUser.fullName} - ${selectedUser.email}`;
+ }
+
+ public onSearch(): void {
+ if (this.validateForm()) {
+ let filterValue = null;
+ if (this.form.controls.filterOption.value === CaaCasesFilterType.CaseReferenceNumber) {
+ filterValue = this.form.controls.caseReferenceNumber.value;
+ }
+
+ if (this.form.controls.filterOption.value === CaaCasesFilterType.CasesAssignedToAUser) {
+ const selectedUser = this.form.controls.assigneePerson.value;
+ const fullName = selectedUser.split(' - ')[0];
+ const email = selectedUser.split(' - ')[1];
+ filterValue = this.selectedOrganisationUsers && this.selectedOrganisationUsers.find(
+ (user) => user.fullName === fullName && user.email === email).userIdentifier;
+ }
+ const selectedFilter: SelectedCaseFilter = {
+ filterType: this.selectedFilterType,
+ filterValue: filterValue
+ };
+ this.filterApplied = true;
+ this.selectedFilter.emit(selectedFilter);
+ }
+ }
+
+ public onReset(): void {
+ this.form.reset({ filterOption: CaaCasesFilterType.None, assigneePerson: '', caseReferenceNumber: '' });
+ this.selectedFilter.emit({ filterType: this.selectedFilterType, filterValue: '' });
+ this.filterApplied = false;
+ }
+
+ public onUserSelectionChange(selectedUser: User) {
+ this.form.controls.assigneePerson.clearValidators();
+ this.form.controls.assigneePerson.updateValueAndValidity();
+ this.form.controls.assigneePerson.setValue(this.getDisplayName(selectedUser), { emitEvent: false, onlySelf: true });
+ }
+
+ public selectFilterOption(caaCasesFilterType: CaaCasesFilterType): void {
+ this.selectedFilterType = caaCasesFilterType;
+ }
+
+ private validateForm(): boolean {
+ let isValid = true;
+ this.errorMessages = [];
+ if (this.form.controls.filterOption.value === CaaCasesFilterType.CasesAssignedToAUser) {
+ this.form.controls.assigneePerson.updateValueAndValidity({ emitEvent: false, onlySelf: true }); // ensure validation is run even if the field is empty
+ if (this.form.controls.assigneePerson.invalid) {
+ this.errorMessages.push({ title: '', description: CaaCasesFilterErrorMessage.InvalidAssigneeName, fieldId: 'assigneePerson' });
+ isValid = false;
+ }
+ }
+ if (this.form.controls.filterOption.value === CaaCasesFilterType.CaseReferenceNumber) {
+ this.form.controls.caseReferenceNumber.updateValueAndValidity({ emitEvent: false, onlySelf: true }); // ensure validation is run even if the field is empty
+ if (this.form.controls.caseReferenceNumber.invalid) {
+ this.errorMessages.push({ title: '', description: CaaCasesFilterErrorMessage.InvalidCaseReference, fieldId: 'caseReferenceNumber' });
+ isValid = false;
+ }
+ }
+ this.emitErrorMessages.emit(this.errorMessages);
+ return isValid;
+ }
+
+ private handleOnFilterOptionChange(value: CaaCasesFilterType): void {
+ // clear validators for all forms
+ this.form.controls.assigneePerson.clearValidators();
+ this.form.controls.caseReferenceNumber.clearValidators();
+ this.form.controls.assigneePerson.reset();
+ this.form.controls.caseReferenceNumber.reset();
+ switch (value) {
+ case CaaCasesFilterType.CasesAssignedToAUser:
+ this.form.controls.assigneePerson.setValidators([Validators.required, CaaCasesUtil.assigneeNameValidator2()]);
+ break;
+ case CaaCasesFilterType.CaseReferenceNumber:
+ this.form.controls.caseReferenceNumber.setValidators([Validators.required, CaaCasesUtil.caseReferenceValidator()]);
+ break;
+ case CaaCasesFilterType.AllAssignedCases:
+ case CaaCasesFilterType.NewCasesToAccept:
+ case CaaCasesFilterType.UnassignedCases:
+ break;
+ }
+ this.form.updateValueAndValidity();
+ }
+}
+
+interface CasesFilterForm {
+ filterOption: FormControl;
+ assigneePerson: FormControl;
+ caseReferenceNumber: FormControl;
+}
diff --git a/src/cases/components/cases-results-table/cases-results-table.component.html b/src/cases/components/cases-results-table/cases-results-table.component.html
new file mode 100644
index 000000000..8342c913d
--- /dev/null
+++ b/src/cases/components/cases-results-table/cases-results-table.component.html
@@ -0,0 +1,61 @@
+ 0"
+>
+
+
+ This view has not been configured for the case type.
+
+ 0">
+
+
+
+ Showing {{ getFirstResult() }} to
+ {{ getLastResult() }} of
+ {{ getTotalResults() }} {{ currentCaseType }} cases
+
+
+
+ Select any {{ currentCaseType }} cases you want to
+ manage case sharing for.
+
+
+
+ {{ shareButtonText }}
+
+
+
0 && tableConfig"
+ [cases]="cases"
+ [selectedCases]="selectedCases"
+ [tableConfig]="tableConfig"
+ [selectionEnabled]="true"
+ (selection)="onCaseSelection($event)"
+ (pageChange)="onPaginationHandler($event)"
+ [currentPageNo]="currentPageNo"
+ [totalResultsCount]="totalCases"
+ [pageSize]="paginationPageSize"
+ >
+
+
+
+
diff --git a/src/cases/components/cases-results-table/cases-results-table.component.scss b/src/cases/components/cases-results-table/cases-results-table.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/cases/components/cases-results-table/cases-results-table.component.spec.ts b/src/cases/components/cases-results-table/cases-results-table.component.spec.ts
new file mode 100644
index 000000000..f4447ed40
--- /dev/null
+++ b/src/cases/components/cases-results-table/cases-results-table.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CasesResultsTableComponent } from './cases-results-table.component';
+
+describe('CasesResultsTableComponent', () => {
+ let component: CasesResultsTableComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ CasesResultsTableComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(CasesResultsTableComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/cases/components/cases-results-table/cases-results-table.component.ts b/src/cases/components/cases-results-table/cases-results-table.component.ts
new file mode 100644
index 000000000..5c857f2d9
--- /dev/null
+++ b/src/cases/components/cases-results-table/cases-results-table.component.ts
@@ -0,0 +1,155 @@
+import { HttpErrorResponse } from '@angular/common/http';
+import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
+import { MatTabGroup } from '@angular/material/tabs';
+import { TableConfig } from '@hmcts/ccd-case-ui-toolkit';
+import { SubNavigation } from '@hmcts/rpx-xui-common-lib';
+import { Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+
+import * as fromStore from '../../store';
+import { CaaCases } from 'api/caaCases/interfaces';
+
+@Component({
+ selector: 'app-cases-results-table',
+ templateUrl: './cases-results-table.component.html',
+ styleUrls: ['./cases-results-table.component.scss']
+})
+export class CasesResultsTableComponent {
+ private _allCaseTypes: SubNavigation[];
+ private _cases: any; // can we type this?
+
+ @Input() set allCaseTypes(value: SubNavigation[]) {
+ this._allCaseTypes = value;
+ this.fixCurrentTab(this._allCaseTypes);
+ }
+
+ @Input() set casesConfig(value: CaaCases) {
+ if (value){
+ this.tableConfig = value;
+ this.setTableConfig(this.tableConfig);
+ }
+ }
+
+ get cases(): SubNavigation[] {
+ return this._cases;
+ }
+
+ @Input() set cases(value: any) {
+ if (value){
+ this._cases = value;
+ }
+ }
+
+ @Input() paginationPageSize: number = 25;
+ @Input() shareButtonText = 'Share case';
+
+ @Output() public caseSelected = new EventEmitter();
+ @Output() public pageChanged = new EventEmitter();
+ @Output() public shareButtonClicked = new EventEmitter();
+
+ // Needed for the tab group
+ public navItems: any[];
+ public currentPageNo: number;
+ public totalCases: number = 0;
+ public tableConfig: TableConfig;
+ public currentCaseType: string;
+
+ public casesError$: Observable;
+ public noCasesFoundMessage = '';
+ public enableShareButton = false;
+
+ public selectedCases: any[] = [];
+ public selectedAssignedCases: any[] = [];
+ public selectedUnassignedCases: any[] = [];
+
+ @ViewChild('tabGroup') public tabGroup: MatTabGroup;
+
+ /**
+ *
+ */
+ constructor(private readonly store: Store,) {
+
+ }
+
+ public tabChanged(event: { tab: { textLabel: string }}): void {
+ this.totalCases = this.navItems.find((data) => data.text === event.tab.textLabel)
+ ? this.navItems.find((data) => data.text === event.tab.textLabel).total
+ : 0;
+ this.setTabItems(event.tab.textLabel, true);
+ }
+
+ public resetPaginationParameters(): void {
+ this.currentPageNo = 1;
+ }
+
+ public hasResults(): any {
+ return this.totalCases;
+ }
+
+ public getFirstResult(): number {
+ return ((this.currentPageNo - 1) * this.paginationPageSize) + 1;
+ }
+
+ public getLastResult(): number {
+ const count = ((this.currentPageNo) * this.paginationPageSize);
+ return count >= this.totalCases ? this.totalCases : count < this.totalCases ? count : 1;
+ }
+
+ public getTotalResults(): number {
+ return this.totalCases;
+ }
+
+ public setTableConfig(config: TableConfig): void {
+ if (config !== null) {
+ this.tableConfig = {
+ idField: config.idField,
+ columnConfigs: config.columnConfigs
+ };
+ }
+ }
+
+ public onCaseSelection(selectedCases: any[]): void {
+ this.caseSelected.emit(selectedCases);
+ this.enableShareButton = selectedCases.length > 0;
+ }
+
+ public onPaginationHandler(pageNo: number): void {
+ this.currentPageNo = pageNo;
+ this.pageChanged.emit(pageNo);
+ }
+
+ public onShareButtonClicked(): void {
+ // this.store.dispatch(new fromStore.AddShareUnassignedCases({
+ // sharedCases: converters.toShareCaseConverter(this.selectedUnassignedCases, this.currentCaseType)
+ // }));
+ // TODO: emit this action
+ this.shareButtonClicked.emit();
+ }
+
+ private fixCurrentTab(items: any): void {
+ this.navItems = items;
+ if (items && items.length > 0) {
+ this.totalCases = items[0].total ? items[0].total : 0;
+ this.setTabItems(items[0].text);
+ } else {
+ this.totalCases = 0;
+ // this.noCasesFoundMessage = this.getNoCasesFoundMessage();
+ }
+ }
+
+ private setTabItems(tabName: string, fromTabChangedEvent?: boolean): void {
+ this.resetPaginationParameters();
+ // if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases) {
+ // this.store.pipe(select(fromStore.getAllUnassignedCases));
+ // } else {
+ // this.store.pipe(select(fromStore.getAllAssignedCases));
+ // }
+ // this.shareAssignedCases$ = this.store.pipe(select(fromStore.getShareAssignedCaseListState));
+ // this.shareUnassignedCases$ = this.store.pipe(select(fromStore.getShareUnassignedCaseListState));
+ this.currentCaseType = tabName;
+ if (!fromTabChangedEvent && this.tabGroup) {
+ this.tabGroup.selectedIndex = 0;
+ }
+ // this.loadDataFromStore();
+ }
+}
diff --git a/src/cases/components/index.ts b/src/cases/components/index.ts
new file mode 100644
index 000000000..e55c65f6c
--- /dev/null
+++ b/src/cases/components/index.ts
@@ -0,0 +1,10 @@
+import { CasesFilterComponent } from './cases-filter/cases-filter.component';
+import { CasesResultsTableComponent } from './cases-results-table/cases-results-table.component';
+
+export const components: any[] = [
+ CasesFilterComponent,
+ CasesResultsTableComponent
+];
+
+export * from './cases-filter/cases-filter.component';
+export * from './cases-results-table/cases-results-table.component';
diff --git a/src/cases/containers/case-share-complete/case-share-complete.component.html b/src/cases/containers/case-share-complete/case-share-complete.component.html
new file mode 100644
index 000000000..e31e795c2
--- /dev/null
+++ b/src/cases/containers/case-share-complete/case-share-complete.component.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+ Your selected cases have been updated
+
+
+
What happens next
+
The people you added can now access and update the selected cases from their case list.
+
If you removed someone from a case, they cannot access the case anymore.
+
If you've shared one or more cases, your colleagues will now be able to access them from their case list.
+
+
To continue managing case sharing for other users or case types:
+
Go to assigned cases list
+
Go to unassigned cases list
+
+
+
+
+
+
+
+
+
Sorry, there is a problem
+
We couldn't share or remove access to the following cases:
+
We couldn't share access to the following cases:
+
+
+
{{ acase.caseTitle }}
+
+
+ {{ acase.caseId }}
+
+
+
+
+
+ Name
+ Email address
+ Actions
+
+
+
+
+ {{ user.firstName + ' ' + user.lastName }}
+ {{ user.email }}
+
+ To be added
+
+
+
+ {{ user.firstName + ' ' + user.lastName }}
+ {{ user.email }}
+
+ To be removed
+
+
+
+
+
+
+
Access to all your other selected cases was shared or removed.
+
Access to all your other selected cases was shared.
+
Try again or get help if you're still having problems
+
diff --git a/src/cases/containers/case-share-complete/case-share-complete.component.scss b/src/cases/containers/case-share-complete/case-share-complete.component.scss
new file mode 100644
index 000000000..6b852b331
--- /dev/null
+++ b/src/cases/containers/case-share-complete/case-share-complete.component.scss
@@ -0,0 +1,11 @@
+.complete_banner {
+ text-align: center;
+ padding: 30px 0 30px 0;
+ margin-top: 75px;
+}
+.govuk-table-column-header {
+ width: 45%;
+}
+.govuk-table-column-actions {
+ width: 10%;
+}
diff --git a/src/cases/containers/case-share-complete/case-share-complete.component.spec.ts b/src/cases/containers/case-share-complete/case-share-complete.component.spec.ts
new file mode 100644
index 000000000..51c760c11
--- /dev/null
+++ b/src/cases/containers/case-share-complete/case-share-complete.component.spec.ts
@@ -0,0 +1,213 @@
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Router } from '@angular/router';
+import { RouterTestingModule } from '@angular/router/testing';
+import { FeatureToggleService } from '@hmcts/rpx-xui-common-lib';
+import { Store } from '@ngrx/store';
+import { provideMockStore } from '@ngrx/store/testing';
+import { of } from 'rxjs';
+import { CaaCasesPageType } from '../../models/caa-cases.enum';
+import { CaaCasesState } from '../../store/reducers';
+import { CaseShareCompleteComponent } from './case-share-complete.component';
+
+describe('CaseShareCompleteComponent', () => {
+ let component: CaseShareCompleteComponent;
+ let fixture: ComponentFixture;
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ let store: Store;
+ const mockFeatureToggleService = jasmine.createSpyObj('FeatureToggleService', ['getValue']);
+ let router: Router;
+ const mockRoute = {
+ snapshot: {
+ params: {
+ pageType: CaaCasesPageType.AssignedCases
+ }
+ }
+ };
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ declarations: [CaseShareCompleteComponent],
+ imports: [RouterTestingModule],
+ providers: [
+ provideMockStore(),
+ { provide: FeatureToggleService, useValue: mockFeatureToggleService },
+ { provide: ActivatedRoute, useValue: mockRoute }
+ ]
+ }).compileComponents();
+ store = TestBed.inject(Store);
+ router = TestBed.inject(Router);
+ fixture = TestBed.createComponent(CaseShareCompleteComponent);
+ component = fixture.componentInstance;
+ mockFeatureToggleService.getValue.and.returnValue(of(true));
+ component.shareCases$ = of([{
+ caseId: '9417373995765133',
+ caseTitle: 'Sam Green Vs Williams Lee',
+ pendingShares: [
+ {
+ idamId: 'u666666',
+ firstName: 'Kate',
+ lastName: 'Grant',
+ email: 'kate.grant@lambbrooks.com'
+ }]
+ }]);
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should check if pending', () => {
+ const sharedCases = [{
+ caseId: '9417373995765133',
+ caseTitle: 'Sam Green Vs Williams Lee',
+ sharedWith: [
+ {
+ idamId: 'u666666',
+ firstName: 'Kate',
+ lastName: 'Grant',
+ email: 'kate.grant@lambbrooks.com'
+ }],
+ pendingUnshares: [
+ {
+ idamId: 'u777777',
+ firstName: 'Nick',
+ lastName: 'Rodrigues',
+ email: 'nick.rodrigues@lambbrooks.com'
+ }]
+ }];
+ component.isLoading = true;
+ const returnValue = component.checkIfIncomplete(sharedCases);
+ expect(returnValue).toEqual('PENDING');
+ });
+
+ it('should check if complete', () => {
+ const sharedCases = [{
+ caseId: '9417373995765133',
+ caseTitle: 'Sam Green Vs Williams Lee',
+ sharedWith: [
+ {
+ idamId: 'u666666',
+ firstName: 'Kate',
+ lastName: 'Grant',
+ email: 'kate.grant@lambbrooks.com'
+ }]
+ }];
+ component.isLoading = true;
+ const returnValue = component.checkIfIncomplete(sharedCases);
+ expect(returnValue).toEqual('COMPLETE');
+ });
+
+ it('should user access block', () => {
+ const case1 = {
+ caseId: '9417373995765133',
+ caseTitle: 'Sam Green Vs Williams Lee',
+ sharedWith: [
+ {
+ idamId: 'u666666',
+ firstName: 'Kate',
+ lastName: 'Grant',
+ email: 'kate.grant@lambbrooks.com'
+ }]
+ };
+ const case2 = {
+ caseId: '9417373995765133',
+ caseTitle: 'Sam Green Vs Williams Lee',
+ pendingShares: [
+ {
+ idamId: 'u666666',
+ firstName: 'Kate',
+ lastName: 'Grant',
+ email: 'kate.grant@lambbrooks.com'
+ }]
+ };
+ const case3 = {
+ caseId: '9417373995765133',
+ caseTitle: 'Sam Green Vs Williams Lee',
+ pendingUnshares: [
+ {
+ idamId: 'u666666',
+ firstName: 'Kate',
+ lastName: 'Grant',
+ email: 'kate.grant@lambbrooks.com'
+ }]
+ };
+ expect(component.showUserAccessBlock(case1)).toBeFalsy();
+ expect(component.showUserAccessBlock(case2)).toBeTruthy();
+ expect(component.showUserAccessBlock(case3)).toBeTruthy();
+ });
+
+ xit('should tidy up shared case if complete', () => {
+ component.completeScreenMode = 'COMPLETE';
+ component.ngOnDestroy();
+ expect(component.shareCases.length).toEqual(0);
+ });
+
+ it('should see add user info only from case if remove user feature is toggled off', () => {
+ component.completeScreenMode = 'PENDING';
+ component.removeUserFromCaseToggleOn$ = of(false);
+ fixture.detectChanges();
+ const removeUserError = fixture.debugElement.nativeElement.querySelector('#add-user-error');
+ expect(removeUserError).toBeTruthy();
+ const addAndRemoveUserError = fixture.debugElement.nativeElement.querySelector('#add-and-remove-user-error');
+ expect(addAndRemoveUserError).toBeFalsy();
+ const removeUserInfo = fixture.debugElement.nativeElement.querySelector('#add-user-info');
+ expect(removeUserInfo).toBeTruthy();
+ const addAndRemoveUserInfo = fixture.debugElement.nativeElement.querySelector('#add-and-remove-user-info');
+ expect(addAndRemoveUserInfo).toBeFalsy();
+ });
+
+ it('should see add and remove user info from case if remove user feature is toggled on', () => {
+ component.completeScreenMode = 'PENDING';
+ component.removeUserFromCaseToggleOn$ = of(true);
+ fixture.detectChanges();
+ const removeUserError = fixture.debugElement.nativeElement.querySelector('#add-user-error');
+ expect(removeUserError).toBeFalsy();
+ const addAndRemoveUserError = fixture.debugElement.nativeElement.querySelector('#add-and-remove-user-error');
+ expect(addAndRemoveUserError).toBeTruthy();
+ const removeUserInfo = fixture.debugElement.nativeElement.querySelector('#add-user-info');
+ expect(removeUserInfo).toBeFalsy();
+ const addAndRemoveUserInfo = fixture.debugElement.nativeElement.querySelector('#add-and-remove-user-info');
+ expect(addAndRemoveUserInfo).toBeTruthy();
+ });
+
+ it('should display the correct success text for Assigned Cases', () => {
+ spyOn(store, 'pipe').and.returnValue(of({}));
+ spyOnProperty(router, 'url', 'get').and.returnValue('/assigned-cases/case-share-complete');
+ component.ngOnInit();
+ component.completeScreenMode = 'COMPLETE';
+ fixture.detectChanges();
+ expect(component.isFromAssignedCasesRoute).toBe(true);
+ const successTextAssignedCases1 = fixture.debugElement.nativeElement.querySelector('#what-happens-next-added');
+ expect(successTextAssignedCases1).toBeTruthy();
+ expect(successTextAssignedCases1.textContent).toContain('The people you added');
+ const successTextAssignedCases2 = fixture.debugElement.nativeElement.querySelector('#what-happens-next-removed');
+ expect(successTextAssignedCases2).toBeTruthy();
+ expect(successTextAssignedCases2.textContent).toContain('If you removed someone');
+ const successTextUnassignedCases = fixture.debugElement.nativeElement.querySelector('#what-happens-next-shared');
+ expect(successTextUnassignedCases).toBeNull();
+ });
+
+ it('should display the correct success text for Unassigned Cases', () => {
+ spyOn(store, 'pipe').and.returnValue(of({}));
+ spyOnProperty(router, 'url', 'get').and.returnValue('/unassigned-cases/case-share-complete');
+ component.ngOnInit();
+ component.completeScreenMode = 'COMPLETE';
+ fixture.detectChanges();
+ expect(component.isFromAssignedCasesRoute).toBe(false);
+ const successTextAssignedCases1 = fixture.debugElement.nativeElement.querySelector('#what-happens-next-added');
+ expect(successTextAssignedCases1).toBeNull();
+ const successTextAssignedCases2 = fixture.debugElement.nativeElement.querySelector('#what-happens-next-removed');
+ expect(successTextAssignedCases2).toBeNull();
+ const successTextUnassignedCases = fixture.debugElement.nativeElement.querySelector('#what-happens-next-shared');
+ expect(successTextUnassignedCases).toBeTruthy();
+ expect(successTextUnassignedCases.textContent).toContain('If you\'ve shared');
+ });
+
+ afterEach(() => {
+ fixture.destroy();
+ });
+});
diff --git a/src/cases/containers/case-share-complete/case-share-complete.component.ts b/src/cases/containers/case-share-complete/case-share-complete.component.ts
new file mode 100644
index 000000000..d70eca271
--- /dev/null
+++ b/src/cases/containers/case-share-complete/case-share-complete.component.ts
@@ -0,0 +1,90 @@
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { FeatureToggleService } from '@hmcts/rpx-xui-common-lib';
+import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
+import { select, Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+import { CaaCasesPageType } from '../../models/caa-cases.enum';
+import * as fromCasesFeature from '../../store';
+import * as fromCaseList from '../../store/reducers';
+
+@Component({
+ selector: 'app-exui-case-share-complete',
+ templateUrl: './case-share-complete.component.html',
+ styleUrls: ['case-share-complete.component.scss']
+})
+export class CaseShareCompleteComponent implements OnInit, OnDestroy {
+ public shareCases$: Observable;
+ public shareCases: SharedCase[];
+ public newShareCases$: Observable;
+ public newShareCases: SharedCase[];
+ public shareCaseState$: Observable;
+ public pageType: string;
+ public isLoading: boolean;
+ public completeScreenMode: string;
+ public removeUserFromCaseToggleOn$: Observable;
+ public isFromAssignedCasesRoute: boolean = false;
+
+ constructor(
+ private readonly store: Store,
+ private readonly featureToggleService: FeatureToggleService,
+ private readonly route: ActivatedRoute,
+ private readonly router: Router
+ ) {
+ this.pageType = this.route.snapshot.params.pageType;
+ }
+
+ public ngOnInit(): void {
+ this.shareCaseState$ = this.store.pipe(select(fromCasesFeature.getCaseShareState));
+ this.shareCaseState$.subscribe((state) => this.isLoading = state.loading);
+
+ this.shareCases$ = this.pageType === CaaCasesPageType.UnassignedCases
+ ? this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState))
+ : this.store.pipe(select(fromCasesFeature.getShareAssignedCaseListState));
+ this.shareCases$.subscribe((shareCases) => this.shareCases = shareCases);
+
+ if (this.pageType === CaaCasesPageType.UnassignedCases) {
+ this.store.dispatch(new fromCasesFeature.AssignUsersToUnassignedCase(this.shareCases));
+ this.newShareCases$ = this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState));
+ } else {
+ this.store.dispatch(new fromCasesFeature.AssignUsersToAssignedCase(this.shareCases));
+ this.newShareCases$ = this.store.pipe(select(fromCasesFeature.getShareAssignedCaseListState));
+ }
+
+ this.newShareCases$.subscribe((shareCases) => {
+ this.completeScreenMode = this.checkIfIncomplete(shareCases);
+ this.newShareCases = shareCases;
+ });
+
+ this.removeUserFromCaseToggleOn$ = this.featureToggleService.getValue('remove-user-from-case-mo', false);
+ this.isFromAssignedCasesRoute = this.router.url.startsWith('/assigned-cases');
+ }
+
+ public ngOnDestroy(): void {
+ if (this.completeScreenMode === 'COMPLETE') {
+ if (this.pageType === CaaCasesPageType.UnassignedCases) {
+ this.store.dispatch(new fromCasesFeature.ResetUnassignedCaseSelection());
+ } else {
+ this.store.dispatch(new fromCasesFeature.ResetAssignedCaseSelection());
+ }
+ }
+ }
+
+ public checkIfIncomplete(shareCases: SharedCase[]): string {
+ if (this.isLoading) {
+ if (shareCases.some((aCase) => aCase.pendingShares && aCase.pendingShares.length > 0)
+ || shareCases.some((aCase) => aCase.pendingUnshares && aCase.pendingUnshares.length > 0)) {
+ return 'PENDING';
+ }
+ return 'COMPLETE';
+ }
+ }
+
+ public showUserAccessBlock(aCase: SharedCase): boolean {
+ if ((aCase.pendingShares && aCase.pendingShares.length > 0)
+ || (aCase.pendingUnshares && aCase.pendingUnshares.length > 0)) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/cases/containers/case-share-confirm/case-share-confirm.component.html b/src/cases/containers/case-share-confirm/case-share-confirm.component.html
new file mode 100644
index 000000000..16f0afca5
--- /dev/null
+++ b/src/cases/containers/case-share-confirm/case-share-confirm.component.html
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/src/cases/containers/case-share-confirm/case-share-confirm.component.scss b/src/cases/containers/case-share-confirm/case-share-confirm.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/cases/containers/case-share-confirm/case-share-confirm.component.spec.ts b/src/cases/containers/case-share-confirm/case-share-confirm.component.spec.ts
new file mode 100644
index 000000000..0eb8c6eb8
--- /dev/null
+++ b/src/cases/containers/case-share-confirm/case-share-confirm.component.spec.ts
@@ -0,0 +1,63 @@
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+import { ActivatedRoute, Router } from '@angular/router';
+import { RouterTestingModule } from '@angular/router/testing';
+import { Store } from '@ngrx/store';
+import { provideMockStore } from '@ngrx/store/testing';
+import { CaaCasesPageType } from '../../models/caa-cases.enum';
+import { CaaCasesState } from '../../store/reducers';
+import { CaseShareConfirmComponent } from './case-share-confirm.component';
+
+describe('CaseShareConfirmComponent', () => {
+ let component: CaseShareConfirmComponent;
+ let fixture: ComponentFixture;
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ let store: Store;
+ const mockRoute = {
+ snapshot: {
+ params: {
+ pageType: CaaCasesPageType.AssignedCases
+ }
+ }
+ };
+ const mockRouter = {
+ url: '/assigned-cases'
+ };
+
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [RouterTestingModule],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ declarations: [CaseShareConfirmComponent],
+ providers: [
+ provideMockStore(),
+ { provide: Router, useValue: mockRouter },
+ { provide: ActivatedRoute, useValue: mockRoute }
+ ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ store = TestBed.inject(Store);
+ fixture = TestBed.createComponent(CaseShareConfirmComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ afterEach(() => {
+ fixture.destroy();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should set correct fnTitle, backLink, changeLink and completeLink for assigned cases', () => {
+ fixture.detectChanges();
+ expect(component.fnTitle).toEqual('Manage case sharing');
+ expect(component.backLink).toEqual('/assigned-cases/case-share');
+ expect(component.changeLink).toEqual('/assigned-cases/case-share');
+ expect(component.completeLink).toEqual('/assigned-cases/case-share-complete/assigned-cases');
+ });
+});
diff --git a/src/cases/containers/case-share-confirm/case-share-confirm.component.ts b/src/cases/containers/case-share-confirm/case-share-confirm.component.ts
new file mode 100644
index 000000000..85aed976f
--- /dev/null
+++ b/src/cases/containers/case-share-confirm/case-share-confirm.component.ts
@@ -0,0 +1,51 @@
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
+import { select, Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+import { CaaCasesPageType } from '../../models/caa-cases.enum';
+import * as fromCasesFeature from '../../store';
+import * as fromCaseList from '../../store/reducers';
+
+@Component({
+ selector: 'app-exui-case-share-confirm',
+ templateUrl: './case-share-confirm.component.html',
+ styleUrls: ['./case-share-confirm.component.scss']
+})
+export class CaseShareConfirmComponent implements OnInit {
+ public shareCases$: Observable;
+ public shareCases: SharedCase[];
+ public url: string;
+ public pageType: string;
+ public fnTitle: string;
+ public backLink: string;
+ public changeLink: string;
+ public completeLink: string;
+
+ constructor(private readonly store: Store,
+ private readonly route: ActivatedRoute,
+ private readonly router: Router) {
+ this.url = this.router?.url;
+ this.pageType = this.route.snapshot.params.pageType;
+ }
+
+ public ngOnInit(): void {
+ // Set fnTitle, backLink, changeLink (these two links are the same as each other) and confirmLink depending on
+ // whether navigation is via the Unassigned Cases or Assigned Cases page
+ if (this.url.startsWith('/unassigned-cases')) {
+ this.fnTitle = 'Share a case';
+ this.backLink = '/unassigned-cases/case-share';
+ this.changeLink = '/unassigned-cases/case-share';
+ this.completeLink = `/unassigned-cases/case-share-complete/${this.pageType}`;
+ } else {
+ this.fnTitle = 'Manage case sharing';
+ this.backLink = '/assigned-cases/case-share';
+ this.changeLink = '/assigned-cases/case-share';
+ this.completeLink = `/assigned-cases/case-share-complete/${this.pageType}`;
+ }
+ this.shareCases$ = this.pageType === CaaCasesPageType.UnassignedCases
+ ? this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState))
+ : this.store.pipe(select(fromCasesFeature.getShareAssignedCaseListState));
+ this.shareCases$.subscribe((shareCases) => this.shareCases = shareCases);
+ }
+}
diff --git a/src/cases/containers/case-share/case-share.component.html b/src/cases/containers/case-share/case-share.component.html
new file mode 100644
index 000000000..215e07533
--- /dev/null
+++ b/src/cases/containers/case-share/case-share.component.html
@@ -0,0 +1,15 @@
+Back
+
+
diff --git a/src/cases/containers/case-share/case-share.component.scss b/src/cases/containers/case-share/case-share.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/cases/containers/case-share/case-share.component.spec.ts b/src/cases/containers/case-share/case-share.component.spec.ts
new file mode 100644
index 000000000..efceb84e8
--- /dev/null
+++ b/src/cases/containers/case-share/case-share.component.spec.ts
@@ -0,0 +1,69 @@
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { FeatureToggleService } from '@hmcts/rpx-xui-common-lib';
+import { Store } from '@ngrx/store';
+import { provideMockStore } from '@ngrx/store/testing';
+import { of } from 'rxjs';
+import { CaaCasesState } from '../../store/reducers';
+import { CaseShareComponent } from './case-share.component';
+
+describe('CaseShareComponent', () => {
+ let component: CaseShareComponent;
+ let fixture: ComponentFixture;
+
+ let mockStore: Store;
+ let dispatchSpy: jasmine.Spy;
+ const mockFeatureToggleService = jasmine.createSpyObj('FeatureToggleService', ['getValue']);
+
+ const sharedCases = [{
+ caseId: '9417373995765133',
+ caseTitle: 'Sam Green Vs Williams Lee',
+ sharedWith: [
+ {
+ idamId: 'u666666',
+ firstName: 'Kate',
+ lastName: 'Grant',
+ email: 'kate.grant@lambbrooks.com'
+ }]
+ }];
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [RouterTestingModule],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ declarations: [CaseShareComponent],
+ providers: [
+ provideMockStore(),
+ {
+ provide: FeatureToggleService,
+ useValue: mockFeatureToggleService
+ }
+ ]
+ }).compileComponents();
+ mockStore = TestBed.inject(Store);
+ mockFeatureToggleService.getValue.and.returnValue(of(true));
+ dispatchSpy = spyOn(mockStore, 'dispatch');
+ fixture = TestBed.createComponent(CaseShareComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should deselect case', () => {
+ component.deselect(sharedCases);
+ expect(dispatchSpy).toHaveBeenCalled();
+ });
+
+ it('should synchronize to store', () => {
+ component.synchronizeStore(sharedCases);
+ expect(dispatchSpy).toHaveBeenCalled();
+ });
+
+ afterEach(() => {
+ fixture.destroy();
+ });
+});
diff --git a/src/cases/containers/case-share/case-share.component.ts b/src/cases/containers/case-share/case-share.component.ts
new file mode 100644
index 000000000..2217c1d83
--- /dev/null
+++ b/src/cases/containers/case-share/case-share.component.ts
@@ -0,0 +1,103 @@
+import { Component, OnInit } from '@angular/core';
+import { FeatureToggleService } from '@hmcts/rpx-xui-common-lib';
+import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
+import { UserDetails } from '@hmcts/rpx-xui-common-lib/lib/models/user-details.model';
+import { RouterReducerState } from '@ngrx/router-store';
+import { select, Store } from '@ngrx/store';
+import { initAll } from 'govuk-frontend';
+import { Observable } from 'rxjs';
+import { getRouterState, RouterStateUrl } from '../../../app/store/reducers';
+import { CaaCasesPageType } from '../../models/caa-cases.enum';
+import * as fromCasesFeature from '../../store';
+import { LoadShareAssignedCases, LoadShareUnassignedCases, LoadUserFromOrgForCase } from '../../store/actions';
+import * as fromCaseList from '../../store/reducers';
+
+@Component({
+ selector: 'app-exui-case-share',
+ templateUrl: './case-share.component.html',
+ styleUrls: ['./case-share.component.scss']
+})
+export class CaseShareComponent implements OnInit {
+ public routerState$: Observable>;
+ public init: boolean;
+ public pageType: string;
+ public shareCases$: Observable;
+ public shareCases: SharedCase[];
+ public orgUsers$: Observable;
+ public removeUserFromCaseToggleOn$: Observable;
+ public backLink: string;
+ public fnTitle: string;
+ public title: string;
+ public confirmLink: string;
+ public addUserLabel: string;
+ public showRemoveUsers: boolean = false;
+
+ constructor(
+ public store: Store,
+ public featureToggleService: FeatureToggleService
+ ) {}
+
+ public ngOnInit(): void {
+ this.routerState$ = this.store.pipe(select(getRouterState));
+ this.routerState$.subscribe((router) => {
+ this.init = router.state.queryParams.init;
+ this.pageType = router.state.queryParams.pageType;
+ // Set backLink, fnTitle, title, confirmLink, addUserLabel, and showRemoveUsers depending on whether navigation
+ // is via the Unassigned Cases or Assigned Cases page
+ const url = router.state.url.substring(0, router.state.url.indexOf('/', 1));
+ // Set backLink and confirmLink only if the URL is either "/unassigned-cases" or "/assigned-cases"
+ if (url === '/unassigned-cases' || url === '/assigned-cases') {
+ this.backLink = `${url}`;
+ this.confirmLink = `${url}/case-share-confirm/${this.pageType}`;
+ }
+ if (url === '/unassigned-cases') {
+ this.fnTitle = 'Share a case';
+ this.title = 'Add recipient';
+ this.addUserLabel = 'Enter email address';
+ this.showRemoveUsers = false;
+ } else if (url === '/assigned-cases') {
+ this.fnTitle = 'Manage case sharing';
+ this.title = 'Manage shared access to a case';
+ this.addUserLabel = 'Add people to share access to the selected cases';
+ this.showRemoveUsers = true;
+ }
+
+ this.shareCases$ = this.pageType === CaaCasesPageType.UnassignedCases
+ ? this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState))
+ : this.store.pipe(select(fromCasesFeature.getShareAssignedCaseListState));
+ this.shareCases$.subscribe((shareCases) => this.shareCases = shareCases);
+ });
+
+ this.orgUsers$ = this.store.pipe(select(fromCasesFeature.getOrganisationUsersState));
+ if (this.init) {
+ // call api to retrieve case share users
+ if (this.pageType === CaaCasesPageType.UnassignedCases) {
+ this.store.dispatch(new LoadShareUnassignedCases(this.shareCases));
+ } else {
+ this.store.dispatch(new LoadShareAssignedCases(this.shareCases));
+ }
+ // call api to retrieve users in the same organisation
+ this.store.dispatch(new LoadUserFromOrgForCase());
+ }
+ this.removeUserFromCaseToggleOn$ = this.featureToggleService.getValue('remove-user-from-case-mo', false);
+
+ // initialize javascript for accordion component to enable open/close button
+ setTimeout(() => initAll(), 1000);
+ }
+
+ public deselect($event): void {
+ if (this.pageType === CaaCasesPageType.UnassignedCases) {
+ this.store.dispatch(new fromCasesFeature.DeleteAShareUnassignedCase($event));
+ } else {
+ this.store.dispatch(new fromCasesFeature.DeleteAShareAssignedCase($event));
+ }
+ }
+
+ public synchronizeStore($event): void {
+ if (this.pageType === CaaCasesPageType.UnassignedCases) {
+ this.store.dispatch(new fromCasesFeature.SynchronizeStateToStoreUnassignedCases($event));
+ } else {
+ this.store.dispatch(new fromCasesFeature.SynchronizeStateToStoreAssignedCases($event));
+ }
+ }
+}
diff --git a/src/cases/containers/case-share/index.ts b/src/cases/containers/case-share/index.ts
new file mode 100644
index 000000000..80856c0f6
--- /dev/null
+++ b/src/cases/containers/case-share/index.ts
@@ -0,0 +1,45 @@
+import { Params } from '@angular/router';
+import * as fromNgrxRouter from '@ngrx/router-store';
+import {
+ ActionReducerMap,
+ createFeatureSelector,
+ createSelector
+} from '@ngrx/store';
+
+// import * as fromAuth from './auth.reducer';
+
+export interface RouterStateUrl {
+ url: string;
+ queryParams: Params;
+ params: Params;
+}
+
+export interface State {
+ routerX: fromNgrxRouter.RouterReducerState;
+ // auth: fromAuth.AuthState;
+}
+
+export const reducers: ActionReducerMap = {
+ routerX: fromNgrxRouter.routerReducer
+ // auth: fromAuth.reducer,
+};
+
+export const getRouterState =
+ createFeatureSelector>(
+ 'routerX'
+ );
+
+export const getRouterStateUrl = createSelector(
+ getRouterState,
+ (routerState: fromNgrxRouter.RouterReducerState) =>
+ routerState.state
+);
+
+export const isSomeIdParamValid = createSelector(getRouterState, (routerS) => {
+ return (
+ routerS &&
+ routerS.state &&
+ routerS.state.params &&
+ routerS.state.params.someId
+ );
+});
diff --git a/src/cases/containers/case-share/test.spec.ts b/src/cases/containers/case-share/test.spec.ts
new file mode 100644
index 000000000..1336d3815
--- /dev/null
+++ b/src/cases/containers/case-share/test.spec.ts
@@ -0,0 +1,120 @@
+import { Component } from '@angular/core';
+import { TestBed } from '@angular/core/testing';
+import { Router, RouterStateSnapshot } from '@angular/router';
+import { RouterTestingModule } from '@angular/router/testing';
+import { RouterReducerState, RouterStateSerializer, StoreRouterConnectingModule } from '@ngrx/router-store';
+import { Store, StoreModule, combineReducers } from '@ngrx/store';
+import { skip } from 'rxjs/operators';
+import { RouterStateUrl, State, getRouterState, reducers } from './';
+
+class CustomRouterStateSerializer implements RouterStateSerializer {
+ public serialize(routerState: RouterStateSnapshot): RouterStateUrl {
+ let route = routerState.root;
+
+ while (route.firstChild) {
+ route = route.firstChild;
+ }
+
+ const {
+ url,
+ root: { queryParams }
+ } = routerState;
+ const { params } = route;
+
+ return { url, params, queryParams };
+ }
+}
+
+@Component({
+ template: ''
+})
+class ListMockComponent {}
+
+describe('Router Selectors', () => {
+ let store: Store;
+ let router: Router;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ RouterTestingModule.withRoutes([
+ {
+ path: 'list/:someId',
+ component: ListMockComponent
+ }
+ ]),
+ StoreModule.forRoot({
+ routerX: combineReducers(reducers)
+ }),
+ StoreRouterConnectingModule.forRoot({
+ stateKey: 'routerX'
+ })
+ ],
+ declarations: [ListMockComponent],
+ providers: [
+ {
+ provide: RouterStateSerializer,
+ useClass: CustomRouterStateSerializer
+ }
+ ]
+ });
+
+ store = TestBed.inject(Store);
+ router = TestBed.inject(Router);
+ });
+
+ describe('getRouterStateUrl', () => {
+ it('should retrieve routerState', (done) => {
+ const result = {
+ routerX: {
+ state: {
+ url: '/list/123',
+ params: { someId: '123' },
+ queryParams: {}
+ },
+ navigationId: 1
+ } as RouterReducerState
+ };
+ router.navigateByUrl('/list/123');
+ store
+ .select(getRouterState)
+ .pipe(skip(1))
+ .subscribe((routerState) => {
+ // eslint-disable-next-line dot-notation
+ expect(routerState['routerX']).toEqual(result.routerX);
+ done();
+ });
+
+ // PRINTS
+ /**
+ *
+ * { router:
+ * { state: { url: '/list/123', params: {someId: 123}, queryParams: {} },
+ * navigationId: 1 },
+ * auth:
+ * { loggedIn: false } }
+ *
+ */
+ });
+
+ // it('should retrieve routerStateUrl', () => {
+ // router.navigateByUrl('/list/123');
+ // store.select(getRouterStateUrl).subscribe(value => console.log(value));
+
+ // PRINTS
+ // undefined
+ // TypeError: Cannot read property 'state' of undefined
+
+ // Since the state object returned by getRouterState doesn't expose the router chunk directly but an object wrapping router + auth, then of course, state is not present where the selector tries to reach it.
+ // });
+
+ // it('should retrieve isSomeIdParamValid', () => {
+ // router.navigateByUrl('/list/123');
+ // store.select(isSomeIdParamValid).subscribe(value => console.log(value));
+
+ // PRINTS
+ // undefined
+ // TypeError: Cannot read property 'state' of undefined
+ // });
+ });
+});
diff --git a/src/cases/containers/cases/cases.component.html b/src/cases/containers/cases/cases.component.html
new file mode 100644
index 000000000..8712d3cc6
--- /dev/null
+++ b/src/cases/containers/cases/cases.component.html
@@ -0,0 +1,57 @@
+
+ {{
+ (selectedOrganisation$ | async)?.name
+ }}
+ {{ pageTitle }}
+
+
+
+ {{ showFilterSection ? "Hide cases filter" : "Show cases filter" }}
+
+
+
0">
+
+
+ There is a problem
+
+
+
+
+
+
+
+
+
diff --git a/src/cases/containers/cases/cases.component.scss b/src/cases/containers/cases/cases.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/cases/containers/cases/cases.component.spec.ts b/src/cases/containers/cases/cases.component.spec.ts
new file mode 100644
index 000000000..e71f6289f
--- /dev/null
+++ b/src/cases/containers/cases/cases.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CasesComponent } from './cases.component';
+
+describe('CasesComponent', () => {
+ let component: CasesComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ CasesComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(CasesComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/cases/containers/cases/cases.component.ts b/src/cases/containers/cases/cases.component.ts
new file mode 100644
index 000000000..8e95d69b7
--- /dev/null
+++ b/src/cases/containers/cases/cases.component.ts
@@ -0,0 +1,271 @@
+import { Component, OnInit } from '@angular/core';
+import { CaaCasesService } from 'src/cases/services';
+
+import * as organisationStore from '../../../organisation/store';
+import * as userStore from '../../../users/store';
+import * as caaCasesStore from '../../store';
+import { Store, select } from '@ngrx/store';
+import { OrganisationDetails } from 'src/models/organisation.model';
+import { Observable } from 'rxjs';
+import { Router } from '@angular/router';
+import { ErrorMessage } from 'src/shared/models/error-message.model';
+import { SubNavigation, User } from '@hmcts/rpx-xui-common-lib';
+import { SelectedCaseFilter } from 'src/cases/models/selected-case-filter.model';
+import { CaaCases, CaaCasesSessionState, CaaCasesSessionStateValue } from 'src/cases/models/caa-cases.model';
+import { CaaCasesFilterType, CaaCasesPageType } from 'src/cases/models/caa-cases.enum';
+import { HttpErrorResponse } from '@angular/common/http';
+import * as converters from '../../converters/case-converter';
+
+@Component({
+ selector: 'app-cases',
+ templateUrl: './cases.component.html',
+ styleUrls: ['./cases.component.scss']
+})
+export class CasesComponent implements OnInit {
+ // private caaCasesPageType = 'all-cases-filter'; // todo: this will be all cases since it's a merge of both assigned and unassigned cases
+ private caaCasesPageType = CaaCasesPageType.UnassignedCases; // todo: this will be all cases since it's a merge of both assigned and unassigned cases
+
+ public selectedOrganisation$: Observable;
+ public selectedOrganisationUsers$: Observable;
+
+ public pageTitle = 'Cases';
+ public showFilterSection = false;
+ public errorMessages: ErrorMessage[] = [];
+ public sessionStateValue: CaaCasesSessionStateValue;
+
+ public selectedFilterType: CaaCasesFilterType = CaaCasesFilterType.None;
+ public selectedFilterValue: string = null;
+ public selectedCaseType: string;
+
+ // for the results table
+ public allCaseTypes: SubNavigation[] = [];
+ public currentPageNo: number = 1;
+ public paginationPageSize: number = 25;
+ public casesConfig: CaaCases;
+ public cases: any; // can we type this?
+ public casesError$: Observable;
+ public caseResultsTableShareButtonText: string = 'Share cases';
+ private selectedCases: any[] = [];
+
+ constructor(private readonly caaCasesStore: Store,
+ private readonly organisationStore: Store,
+ private readonly userStore: Store,
+ private readonly router: Router,
+ private readonly service: CaaCasesService) {
+ }
+
+ public ngOnInit(): void {
+ // Retrieve session state to check and pre-populate the previous state if any
+ this.retrieveSessionState();
+ // if session state is found, then filter component will emit filter values to avoid double query
+ if (!this.sessionStateValue) {
+ this.loadCaseTypes();
+ }
+
+ // Load selected organisation details from store
+ this.organisationStore.dispatch(new organisationStore.LoadOrganisation());
+ this.selectedOrganisation$ = this.organisationStore.pipe(select(organisationStore.getOrganisationSel));
+
+ // Load users of selected organisation from store
+ this.userStore.dispatch(new userStore.LoadAllUsersNoRoleData());
+ this.selectedOrganisationUsers$ = this.userStore.pipe(select(userStore.getGetUserList));
+
+ // TODO: clean this up to get all cases
+ this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCases)).subscribe((config: CaaCases) => {
+ if (config){
+ this.casesConfig = config;
+ }
+ });
+ this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCaseData)).subscribe((items) => {
+ if (items){
+ this.cases = items;
+ }
+ });
+ this.caaCasesStore.pipe(select(caaCasesStore.getAllAssignedCases)).subscribe((config: CaaCases) => {
+ if (config){
+ this.casesConfig = config;
+ }
+ });
+ this.caaCasesStore.pipe(select(caaCasesStore.getAllAssignedCaseData)).subscribe((items) => {
+ if (items){
+ this.cases = items;
+ }
+ });
+
+ this.casesError$ = this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCasesError));
+ this.casesError$ = this.caaCasesStore.pipe(select(caaCasesStore.getAllAssignedCasesError));
+ }
+
+ /**
+ * This will load all case types based on the selected filter type and value
+ */
+ public loadCaseTypes() {
+ this.caaCasesStore.dispatch(new caaCasesStore.LoadCaseTypes({
+ caaCasesPageType: this.caaCasesPageType,
+ caaCasesFilterType: this.selectedFilterType,
+ caaCasesFilterValue: this.selectedFilterValue })
+ );
+ this.caaCasesStore.pipe(select(caaCasesStore.getAllCaseTypes)).subscribe((items) => {
+ this.allCaseTypes = items;
+ if (this.allCaseTypes && this.allCaseTypes.length > 0) {
+ this.selectedCaseType = this.allCaseTypes[0].text;
+ this.loadCaseData();
+ }
+ });
+ }
+
+ /**
+ * This will load cases (i.e. unassigned or assigned) from the API with the selected filter type and value
+ */
+ public loadCaseData(){
+ if (this.allCaseTypes && this.allCaseTypes.length > 0) {
+ if (this.caaCasesPageType === CaaCasesPageType.AssignedCases) {
+ this.caaCasesStore.dispatch(new caaCasesStore.LoadAssignedCases({
+ caseType: this.selectedCaseType,
+ pageNo: this.currentPageNo,
+ pageSize: this.paginationPageSize,
+ caaCasesFilterType: this.selectedFilterType,
+ caaCasesFilterValue: this.selectedFilterValue
+ }));
+ }
+ if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases){
+ this.caaCasesStore.dispatch(new caaCasesStore.LoadUnassignedCases({
+ caseType: this.selectedCaseType,
+ pageNo: this.currentPageNo,
+ pageSize: this.paginationPageSize,
+ caaCasesFilterType: this.selectedFilterType,
+ caaCasesFilterValue: this.selectedFilterValue
+ }));
+ }
+ }
+ }
+
+ public onSelectedFilter(selectedFilter: SelectedCaseFilter): void {
+ console.log('Selected filter:', selectedFilter);
+ this.selectedFilterType = selectedFilter.filterType;
+ this.selectedFilterValue = selectedFilter.filterValue;
+
+ if (selectedFilter.filterType === CaaCasesFilterType.None) {
+ this.removeSessionState(this.caaCasesPageType);
+ } else {
+ this.storeSessionState(selectedFilter);
+ }
+
+ // load cases types based on filter and value
+ if (selectedFilter.filterType === CaaCasesFilterType.CaseReferenceNumber) {
+ // dispatch action to load case by ref number
+ this.caseResultsTableShareButtonText = 'Accept and assign cases';
+ }
+ if (selectedFilter.filterType === CaaCasesFilterType.CasesAssignedToAUser) {
+ // dispatch action to load case by assignee name
+ this.caaCasesPageType = CaaCasesPageType.AssignedCases;
+ this.caseResultsTableShareButtonText = 'Manage cases';
+ }
+ if (selectedFilter.filterType === CaaCasesFilterType.AllAssignedCases) {
+ // dispatch action to load all cases
+ this.caseResultsTableShareButtonText = 'Manage cases';
+ }
+ if (selectedFilter.filterType === CaaCasesFilterType.NewCasesToAccept) {
+ // dispatch action to load new cases to accept
+ this.caseResultsTableShareButtonText = 'Accept cases';
+ }
+ if (selectedFilter.filterType === CaaCasesFilterType.UnassignedCases) {
+ // dispatch action to load unassigned cases
+ this.caseResultsTableShareButtonText = 'Manage cases';
+ }
+ this.loadCaseTypes();
+ }
+
+ public onErrorMessages(errorMessages: ErrorMessage[]): void {
+ this.errorMessages = errorMessages;
+ }
+
+ public toggleFilterSection(): void {
+ this.showFilterSection = !this.showFilterSection;
+ }
+
+ public isAnyError(): boolean {
+ return Array.isArray(this.errorMessages) && this.errorMessages.length > 0;
+ }
+
+ public removeSessionState(key: string): void {
+ this.service.removeSessionState(key);
+ }
+
+ public retrieveSessionState(): void {
+ this.sessionStateValue = this.service.retrieveSessionState(this.caaCasesPageType);
+ if (this.sessionStateValue) {
+ this.toggleFilterSection();
+ }
+ }
+
+ public storeSessionState(selectedFilter: SelectedCaseFilter): void {
+ const sessionStateToUpdate: CaaCasesSessionState = {
+ key: this.caaCasesPageType,
+ value: {
+ filterType: selectedFilter.filterType,
+ caseReferenceNumber: selectedFilter.filterType === CaaCasesFilterType.CaseReferenceNumber ? selectedFilter.filterValue : null,
+ assigneeName: selectedFilter.filterType === CaaCasesFilterType.CasesAssignedToAUser ? selectedFilter.filterValue : null
+ }
+ };
+ this.sessionStateValue = sessionStateToUpdate.value;
+ this.service.storeSessionState(sessionStateToUpdate);
+ }
+
+ public onCaseSelected(selectedCases: any[]): void {
+ // do i need the line below? and remove the selector in ngOnInit
+ // this.selectedUnassignedCases = selectedCases;
+ if (this.caaCasesPageType === CaaCasesPageType.AssignedCases){
+ this.caaCasesStore.dispatch(new caaCasesStore.SynchronizeStateToStoreAssignedCases(
+ converters.toShareCaseConverter(selectedCases, CaaCasesPageType.AssignedCases)
+ ));
+ }
+
+ if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases){
+ this.caaCasesStore.dispatch(new caaCasesStore.SynchronizeStateToStoreUnassignedCases(
+ converters.toShareCaseConverter(selectedCases, CaaCasesPageType.UnassignedCases)
+ ));
+ }
+ this.selectedCases = selectedCases;
+ }
+
+ public onPageChanged(pageNo: number): void {
+ this.currentPageNo = pageNo;
+ this.loadCaseData();
+ }
+
+ onShareButtonClicked($event: void) {
+ // load cases types based on filter and value
+ if (this.selectedFilterType === CaaCasesFilterType.CaseReferenceNumber) {
+ // TODO: need to handle the `new_case` flag
+ // if returning new case then go to add recipient page
+ // else if returning non-new case then go to manage case assignments
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareAssignedCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ }));
+ }
+ if (this.selectedFilterType === CaaCasesFilterType.CasesAssignedToAUser) {
+ // todo: go to manage case assignments
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareAssignedCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ }
+ ));
+ }
+ if (this.selectedFilterType === CaaCasesFilterType.AllAssignedCases) {
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareAssignedCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ }
+ ));
+ }
+ if (this.selectedFilterType === CaaCasesFilterType.NewCasesToAccept) {
+ // dispatch action to load new cases to accept
+ // if group_access is enabled then go to accept cases page
+ // else go to add recipient
+ }
+ if (this.selectedFilterType === CaaCasesFilterType.UnassignedCases) {
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareUnassignedCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ }));
+ }
+ }
+}
diff --git a/src/cases/containers/index.ts b/src/cases/containers/index.ts
new file mode 100644
index 000000000..eb154eea7
--- /dev/null
+++ b/src/cases/containers/index.ts
@@ -0,0 +1,17 @@
+import { CaseShareCompleteComponent } from './case-share-complete/case-share-complete.component';
+import { CaseShareConfirmComponent } from './case-share-confirm/case-share-confirm.component';
+import { CaseShareComponent } from './case-share/case-share.component';
+import { CasesComponent } from './cases/cases.component';
+
+export const containers: any[] = [
+ CaseShareComponent,
+ CaseShareConfirmComponent,
+ CaseShareCompleteComponent,
+ CasesComponent
+];
+
+export * from './case-share-complete/case-share-complete.component';
+export * from './case-share-confirm/case-share-confirm.component';
+export * from './case-share/case-share.component';
+export * from './cases/cases.component';
+
diff --git a/src/cases/converters/case-converter.ts b/src/cases/converters/case-converter.ts
new file mode 100644
index 000000000..9e0f52bbd
--- /dev/null
+++ b/src/cases/converters/case-converter.ts
@@ -0,0 +1,75 @@
+import { SearchResultViewItem } from '@hmcts/ccd-case-ui-toolkit';
+import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
+
+const BLANK_SPACE: string = ' ';
+const EMPTY_SPACE: string = '';
+const VERSUS_SPACE: string = ' Vs ';
+export function toShareCaseConverter(selectedCases: any[], theCaseTypeId: string): SharedCase[] {
+ const sharedCases: SharedCase[] = [];
+ for (const selectCase of selectedCases) {
+ const caseTypeId = getValueByPropertyName(selectCase, 'caseType') ? getValueByPropertyName(selectCase, 'caseType') : theCaseTypeId;
+ const caseTitle = getValueByPropertyName(selectCase, 'case_title');
+ const shareCase = {
+ caseId: selectCase.case_id,
+ caseTitle: caseTitle ? caseTitle : combineCaseTitleByCaseType(caseTypeId, selectCase),
+ caseTypeId
+ };
+ sharedCases.push(shareCase);
+ }
+ return sharedCases;
+}
+
+export function toSearchResultViewItemConverter(shareCases: SharedCase[]): any[] {
+ const searchResultViewItems: any[] = [];
+ for (const shareCase of shareCases) {
+ const searchResultViewItem = {
+ case_id: shareCase.caseId,
+ caseType: shareCase.caseTypeId,
+ case_title: shareCase.caseTitle
+ };
+ searchResultViewItems.push(searchResultViewItem);
+ }
+ return searchResultViewItems;
+}
+
+function getValueByPropertyName(selectCase: SearchResultViewItem, propName: string): any {
+ return selectCase.hasOwnProperty(propName) ? selectCase[propName] : '';
+}
+
+function combineCaseTitleByCaseType(caseTypeId: string, selectCase: SearchResultViewItem): string {
+ if (caseTypeId.includes('FinancialRemedy')) {
+ const applicantName = getApplicantName(selectCase);
+ const respondentName = getRespondentName(selectCase);
+ return applicantName + showVersus(applicantName, respondentName) + respondentName;
+ } else if (caseTypeId.includes('DIVORCE')) {
+ const marriagePetitionerName = getValueByPropertyName(selectCase, 'D8PetitionerFirstName') + BLANK_SPACE + getValueByPropertyName(selectCase, 'D8PetitionerLastName');
+ const marriageRespondentName = getValueByPropertyName(selectCase, 'D8RespondentFirstName') + BLANK_SPACE + getValueByPropertyName(selectCase, 'D8RespondentLastName');
+ return marriagePetitionerName + showVersus(marriagePetitionerName, marriageRespondentName) + marriageRespondentName;
+ }
+ return selectCase.case_id;
+}
+
+function getApplicantName(selectCase: SearchResultViewItem) {
+ return getValueByPropertyName(selectCase, 'applicantFMName') && getValueByPropertyName(selectCase, 'applicantLName') ?
+ getValueByPropertyName(selectCase, 'applicantFMName') + BLANK_SPACE + getValueByPropertyName(selectCase, 'applicantLName') :
+ getValueByPropertyName(selectCase, 'applicantLName') ? getValueByPropertyName(selectCase, 'applicantLName') : EMPTY_SPACE;
+}
+
+function getRespondentName(selectCase: SearchResultViewItem) {
+ let respondentName = getValueByPropertyName(selectCase, 'appRespondentFMName') && getValueByPropertyName(selectCase, 'appRespondentLName') ?
+ getValueByPropertyName(selectCase, 'appRespondentFMName') + BLANK_SPACE + getValueByPropertyName(selectCase, 'appRespondentLName') :
+ getValueByPropertyName(selectCase, 'appRespondentLName') ? getValueByPropertyName(selectCase, 'appRespondentLName') : EMPTY_SPACE;
+ if (!respondentName) {
+ respondentName = getValueByPropertyName(selectCase, 'respondentFMName') && getValueByPropertyName(selectCase, 'respondentLName') ?
+ getValueByPropertyName(selectCase, 'respondentFMName') + BLANK_SPACE + getValueByPropertyName(selectCase, 'respondentLName') :
+ getValueByPropertyName(selectCase, 'respondentLName') ? getValueByPropertyName(selectCase, 'respondentLName') : EMPTY_SPACE;
+ }
+ return respondentName;
+}
+
+function showVersus(v1, v2) {
+ if (v1 && v2) {
+ return VERSUS_SPACE;
+ }
+ return EMPTY_SPACE;
+}
diff --git a/src/cases/converters/case-converters.spec.ts b/src/cases/converters/case-converters.spec.ts
new file mode 100644
index 000000000..6db5a8c32
--- /dev/null
+++ b/src/cases/converters/case-converters.spec.ts
@@ -0,0 +1,104 @@
+import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
+import * as converts from './case-converter';
+
+describe('case-converter', () => {
+ describe('toShareCaseConverter()', () => {
+ it('should convert FinancialRemedy to share case - single case with title', () => {
+ const selectedCases = [{
+ case_id: '1',
+ case_title: 'OJ VS the people',
+ applicantFMName: 'James',
+ applicantLName: 'Priest',
+ appRespondentFMName: 'Charlotte',
+ appRespondentLName: 'Godard'
+ }];
+
+ const expectedShareCases = [
+ { caseId: '1', caseTitle: 'OJ VS the people', caseTypeId: 'FinancialRemedyContested' }
+ ];
+
+ const shareCases: SharedCase[] = converts.toShareCaseConverter(selectedCases, 'FinancialRemedyContested');
+ expect(shareCases).toEqual(expectedShareCases);
+ });
+
+ it('should convert FinancialRemedy to share case - single case without title', () => {
+ const selectedCases = [{
+ case_id: '1',
+ caseType: 'FinancialRemedyContested',
+ applicantFMName: 'James',
+ applicantLName: 'Priest',
+ appRespondentFMName: 'Charlotte',
+ appRespondentLName: 'Godard'
+ }];
+
+ const expectedShareCases = [
+ { caseId: '1', caseTitle: 'James Priest Vs Charlotte Godard', caseTypeId: 'FinancialRemedyContested' }
+ ];
+
+ const shareCases: SharedCase[] = converts.toShareCaseConverter(selectedCases, 'FinancialRemedyContested');
+ expect(shareCases).toEqual(expectedShareCases);
+ });
+
+ it('should convert Divorce to share case - single case without title', () => {
+ const selectedCases = [{
+ case_id: '1',
+ caseType: 'DIVORCEContested',
+ D8PetitionerFirstName: 'James',
+ D8PetitionerLastName: 'Priest',
+ D8RespondentFirstName: 'Charlotte',
+ D8RespondentLastName: 'Godard'
+ }];
+
+ const expectedShareCases = [
+ { caseId: '1', caseTitle: 'James Priest Vs Charlotte Godard', caseTypeId: 'DIVORCEContested' }
+ ];
+
+ const shareCases: SharedCase[] = converts.toShareCaseConverter(selectedCases, 'DIVORCEContested');
+ expect(shareCases).toEqual(expectedShareCases);
+ });
+
+ it('should convert OTHER to share case - single case without title', () => {
+ const selectedCases = [{
+ case_id: '1',
+ caseType: 'Contested'
+ }];
+
+ const expectedShareCases = [
+ { caseId: '1', caseTitle: '1', caseTypeId: 'Contested' }
+ ];
+
+ const shareCases: SharedCase[] = converts.toShareCaseConverter(selectedCases, 'DIVORCEContested');
+ expect(shareCases).toEqual(expectedShareCases);
+ });
+ });
+
+ describe('toSearchResultViewItemConverter()', () => {
+ it('should convert to search result view item', () => {
+ const sharedCases = [
+ { caseId: '1', caseTitle: '', caseTypeId: 'FinancialRemedyContested' },
+ { caseId: '2', caseTitle: '', caseTypeId: 'FinancialRemedyContested' }
+ ];
+
+ const expectedSearchResultViewItem = [{
+ case_id: '1',
+ caseType: 'FinancialRemedyContested',
+ case_title: ''
+ },
+ {
+ case_id: '2',
+ caseType: 'FinancialRemedyContested',
+ case_title: ''
+ }];
+
+ const searchResultViewItem = converts.toSearchResultViewItemConverter(sharedCases);
+
+ expect(searchResultViewItem).toEqual(expectedSearchResultViewItem);
+ });
+
+ it('should return empty if no items are passed', () => {
+ const searchResultViewItem = converts.toSearchResultViewItemConverter([]);
+
+ expect(searchResultViewItem).toEqual([]);
+ });
+ });
+});
diff --git a/src/cases/guards/feature-toggle.guard.ts b/src/cases/guards/feature-toggle.guard.ts
new file mode 100644
index 000000000..cae69a7f0
--- /dev/null
+++ b/src/cases/guards/feature-toggle.guard.ts
@@ -0,0 +1,14 @@
+import { Injectable } from '@angular/core';
+import { CanActivate } from '@angular/router';
+import { select, Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+import * as fromRoot from '../../app/store';
+
+@Injectable()
+export class FeatureToggleAccountGuard implements CanActivate {
+ constructor(private readonly appStore: Store) {}
+
+ public canActivate(): Observable {
+ return this.appStore.pipe(select(fromRoot.getCaaNewCasesMenuItemsFeatureIsEnabled));
+ }
+}
diff --git a/src/cases/guards/user-role.guard.ts b/src/cases/guards/user-role.guard.ts
new file mode 100644
index 000000000..729a9bdde
--- /dev/null
+++ b/src/cases/guards/user-role.guard.ts
@@ -0,0 +1,15 @@
+import { Injectable } from '@angular/core';
+import { CanActivate } from '@angular/router';
+import { select, Store } from '@ngrx/store';
+import { Observable } from 'rxjs';
+import * as fromStore from '../../organisation/store';
+import * as fromUserProfile from '../../user-profile/store';
+
+@Injectable()
+export class RoleGuard implements CanActivate {
+ constructor(private readonly store: Store) {}
+
+ public canActivate(): Observable {
+ return this.store.pipe(select(fromUserProfile.getIsUserCaaAdmin));
+ }
+}
diff --git a/src/cases/models/caa-cases.enum.ts b/src/cases/models/caa-cases.enum.ts
new file mode 100644
index 000000000..edd89f7ad
--- /dev/null
+++ b/src/cases/models/caa-cases.enum.ts
@@ -0,0 +1,42 @@
+export enum CaaCasesPageType {
+ AssignedCases = 'assigned-cases',
+ UnassignedCases = 'unassigned-cases'
+}
+
+export enum CaaCasesShowHideFilterButtonText {
+ AssignedCasesShow = 'Show assigned cases filter',
+ AssignedCasesHide = 'Hide assigned cases filter',
+ UnassignedCasesShow = 'Show unassigned cases filter',
+ UnassignedCasesHide = 'Hide unassigned cases filter'
+}
+
+export enum CaaCasesFilterType {
+ AllAssignedCases = 'all-assignees',
+ CasesAssignedToAUser = 'assignee-name',
+ CaseReferenceNumber = 'case-reference-number',
+ NewCasesToAccept = 'new-cases-to-accept', // new enum
+ UnassignedCases = 'unassigned-cases', // new enum
+ None = 'none',
+}
+
+export enum CaaCasesPageTitle {
+ AssignedCases = 'Assigned Cases',
+ UnassignedCases = 'Unassigned Cases'
+}
+
+export enum CaaCasesFilterHeading {
+ AssignedCases = 'Filter assigned cases',
+ UnassignedCases = 'Search for an unassigned case'
+}
+
+export enum CaaCasesFilterErrorMessage {
+ InvalidCaseReference = 'Enter a valid HMCTS case reference number',
+ InvalidAssigneeName = 'Enter a valid assignee name'
+}
+
+export enum CaaCasesNoDataMessage {
+ NoAssignedCases = 'There are no assigned cases available to be shared.',
+ NoUnassignedCases = 'There are no unassigned cases available to be shared.',
+ AssignedCasesFilterMessage = 'Try again using a different case reference or assignee.',
+ UnassignedCasesFilterMessage = 'Try again using a different case reference.'
+}
diff --git a/src/cases/models/caa-cases.model.ts b/src/cases/models/caa-cases.model.ts
new file mode 100644
index 000000000..c35509430
--- /dev/null
+++ b/src/cases/models/caa-cases.model.ts
@@ -0,0 +1,37 @@
+export interface CaaCasesColumnConfig {
+ header: string;
+ key: string;
+ type: string;
+}
+
+export interface CaaCases {
+ idField: string;
+ columnConfigs: CaaCasesColumnConfig [];
+ data: any[];
+}
+
+export interface CaseTypesResultsResponse {
+ total: number;
+ cases: any[];
+ case_types_results?: CaseTypesResults [];
+}
+
+export interface CaseTypesResults {
+ total: number;
+ case_type_id: string;
+}
+
+export interface SelectedCases {
+ [key: string]: string [];
+}
+
+export interface CaaCasesSessionStateValue {
+ filterType: string;
+ caseReferenceNumber?: string;
+ assigneeName?: string;
+}
+
+export interface CaaCasesSessionState {
+ key: string;
+ value: CaaCasesSessionStateValue;
+}
diff --git a/src/cases/models/selected-case-filter.model.ts b/src/cases/models/selected-case-filter.model.ts
new file mode 100644
index 000000000..77a3e7548
--- /dev/null
+++ b/src/cases/models/selected-case-filter.model.ts
@@ -0,0 +1,6 @@
+import { CaaCasesFilterType } from './caa-cases.enum';
+
+export interface SelectedCaseFilter {
+ filterType: CaaCasesFilterType;
+ filterValue: string;
+}
diff --git a/src/cases/services/caa-cases.service.spec.ts b/src/cases/services/caa-cases.service.spec.ts
new file mode 100644
index 000000000..89a0f1ab7
--- /dev/null
+++ b/src/cases/services/caa-cases.service.spec.ts
@@ -0,0 +1,101 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { TestBed } from '@angular/core/testing';
+import { of } from 'rxjs';
+import { CaaCasesFilterType, CaaCasesPageType } from '../models/caa-cases.enum';
+import { CaaCasesSessionState, CaaCasesSessionStateValue } from '../models/caa-cases.model';
+import { CaaCasesService } from './caa-cases.service';
+
+describe('CaaCasesService', () => {
+ let service: CaaCasesService;
+ let mockSessionStorage: any;
+ let mockHttp: any;
+ const sessionStateValue: CaaCasesSessionStateValue = {
+ filterType: CaaCasesFilterType.CasesAssignedToAUser,
+ caseReferenceNumber: null,
+ assigneeName: 'assignee123'
+ };
+ const sessionState: CaaCasesSessionState = {
+ key: 'assigned-cases',
+ value: sessionStateValue
+ };
+
+ beforeEach(() => {
+ const store = {};
+ mockSessionStorage = {
+ getItem: (key: string): string => {
+ return key in store ? store[key] : null;
+ },
+ setItem: (key: string, value: string) => {
+ store[key] = `${value}`;
+ }
+ };
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [CaaCasesService]
+ });
+ mockHttp = jasmine.createSpyObj('http', ['post']);
+ mockHttp.post.and.returnValue(of({}));
+ service = new CaaCasesService(mockHttp);
+ });
+
+ it('should getCaaAssignedCases', () => {
+ service.getCaaCases('caseTypeId1', 1, 10, CaaCasesPageType.AssignedCases, null, null);
+ expect(mockHttp.post).toHaveBeenCalledWith(`${CaaCasesService.caaCasesUrl}?caseTypeId=caseTypeId1&pageNo=1&pageSize=10&caaCasesPageType=assigned-cases`, null);
+ });
+
+ it('should getCaaAssignedCases with filter value', () => {
+ service.getCaaCases('caseTypeId1', 1, 10, CaaCasesPageType.AssignedCases, CaaCasesFilterType.CaseReferenceNumber, '1111222233334444');
+ expect(mockHttp.post).toHaveBeenCalledWith(`${CaaCasesService.caaCasesUrl}?caseTypeId=caseTypeId1&pageNo=1&pageSize=10&caaCasesPageType=assigned-cases&caaCasesFilterType=case-reference-number&caaCasesFilterValue=1111222233334444`, null);
+ });
+
+ it('should getCaaUnassignedCases', () => {
+ service.getCaaCases('caseTypeId1', 1, 10, CaaCasesPageType.UnassignedCases, null, null);
+ expect(mockHttp.post).toHaveBeenCalledWith(`${CaaCasesService.caaCasesUrl}?caseTypeId=caseTypeId1&pageNo=1&pageSize=10&caaCasesPageType=unassigned-cases`, null);
+ });
+
+ it('should getCaaUnassignedCases with filter value', () => {
+ service.getCaaCases('caseTypeId1', 1, 10, CaaCasesPageType.UnassignedCases, CaaCasesFilterType.CaseReferenceNumber, '1111222233334444');
+ expect(mockHttp.post).toHaveBeenCalledWith(`${CaaCasesService.caaCasesUrl}?caseTypeId=caseTypeId1&pageNo=1&pageSize=10&caaCasesPageType=unassigned-cases&caaCasesFilterType=case-reference-number&caaCasesFilterValue=1111222233334444`, null);
+ });
+
+ it('should getCaaCaseTypes for assigned cases', () => {
+ service.getCaaCaseTypes(CaaCasesPageType.AssignedCases, null, null);
+ expect(mockHttp.post).toHaveBeenCalledWith(`${CaaCasesService.caaCaseTypesUrl}?caaCasesPageType=assigned-cases`, null);
+ });
+
+ it('should getCaaCaseTypes for assigned cases with filter value', () => {
+ service.getCaaCaseTypes(CaaCasesPageType.AssignedCases, CaaCasesFilterType.CaseReferenceNumber, '1111222233334444');
+ expect(mockHttp.post).toHaveBeenCalledWith(`${CaaCasesService.caaCaseTypesUrl}?caaCasesPageType=assigned-cases&caaCasesFilterType=case-reference-number&caaCasesFilterValue=1111222233334444`, null);
+ });
+
+ it('should getCaaCaseTypes for unassigned cases', () => {
+ service.getCaaCaseTypes(CaaCasesPageType.UnassignedCases, null, null);
+ expect(mockHttp.post).toHaveBeenCalledWith(`${CaaCasesService.caaCaseTypesUrl}?caaCasesPageType=unassigned-cases`, null);
+ });
+
+ it('should getCaaCaseTypes for unassigned cases with filter value', () => {
+ service.getCaaCaseTypes(CaaCasesPageType.UnassignedCases, CaaCasesFilterType.CaseReferenceNumber, '1111222233334444');
+ expect(mockHttp.post).toHaveBeenCalledWith(`${CaaCasesService.caaCaseTypesUrl}?caaCasesPageType=unassigned-cases&caaCasesFilterType=case-reference-number&caaCasesFilterValue=1111222233334444`, null);
+ });
+
+ it('should store session state', () => {
+ spyOn(window.sessionStorage, 'setItem');
+ service.storeSessionState(sessionState);
+ expect(window.sessionStorage.setItem).toHaveBeenCalledWith('assigned-cases', JSON.stringify(sessionState.value));
+ });
+
+ it('should retrieve session state', () => {
+ mockSessionStorage.setItem('assigned-cases', JSON.stringify(sessionState.value));
+ spyOn(window.sessionStorage, 'getItem').and.callFake(mockSessionStorage.getItem);
+ const assignedCasesSessionStateValue = service.retrieveSessionState('assigned-cases');
+ expect(assignedCasesSessionStateValue).toEqual(sessionState.value);
+ expect(window.sessionStorage.getItem).toHaveBeenCalledWith('assigned-cases');
+ });
+
+ it('should remove session state', () => {
+ spyOn(window.sessionStorage, 'removeItem');
+ mockSessionStorage.setItem(sessionState.key, sessionState.value);
+ service.removeSessionState('assigned-cases');
+ expect(window.sessionStorage.removeItem).toHaveBeenCalledWith('assigned-cases');
+ });
+});
diff --git a/src/cases/services/caa-cases.service.ts b/src/cases/services/caa-cases.service.ts
new file mode 100644
index 000000000..3eb4b9fde
--- /dev/null
+++ b/src/cases/services/caa-cases.service.ts
@@ -0,0 +1,54 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { CaaCases, CaaCasesSessionState, CaaCasesSessionStateValue } from '../models/caa-cases.model';
+
+@Injectable()
+export class CaaCasesService {
+ public static caaCasesUrl: string = '/api/caaCases';
+ public static caaCaseTypesUrl: string = '/api/caaCaseTypes';
+
+ constructor(private readonly http: HttpClient) {
+ }
+
+ public getCaaCases(
+ caseTypeId: string, pageNo: number, pageSize: number, caaCasesPageType: string, caaCasesFilterType: string | null, caaCasesFilterValue: string | null): Observable {
+ let url = `${CaaCasesService.caaCasesUrl}?caseTypeId=${caseTypeId}&pageNo=${pageNo}&pageSize=${pageSize}&caaCasesPageType=${caaCasesPageType}`;
+ url += this.getFilterType(caaCasesFilterType);
+ url += this.getFilterValue(caaCasesFilterValue);
+ return this.http.post(url, null);
+ }
+
+ public getCaaCaseTypes(caaCasesPageType: string, caaCasesFilterType: string | null, caaCasesFilterValue: string | null): Observable {
+ let url = `${CaaCasesService.caaCaseTypesUrl}?caaCasesPageType=${caaCasesPageType}`;
+ url += this.getFilterType(caaCasesFilterType);
+ url += this.getFilterValue(caaCasesFilterValue);
+ return this.http.post(url, null);
+ }
+
+ public storeSessionState(sessionState: CaaCasesSessionState): void {
+ window.sessionStorage.setItem(sessionState.key, JSON.stringify(sessionState.value));
+ }
+
+ public retrieveSessionState(key: string): CaaCasesSessionStateValue {
+ return window.sessionStorage.getItem(key) ? JSON.parse(window.sessionStorage.getItem(key)) : null;
+ }
+
+ public removeSessionState(key: string): void {
+ window.sessionStorage.removeItem(key);
+ }
+
+ private getFilterType(caaCasesFilterType: string | null): string {
+ if (caaCasesFilterType) {
+ return `&caaCasesFilterType=${caaCasesFilterType}`;
+ }
+ return '';
+ }
+
+ private getFilterValue(caaCasesFilterValue: string | null): string {
+ if (caaCasesFilterValue) {
+ return `&caaCasesFilterValue=${caaCasesFilterValue}`;
+ }
+ return '';
+ }
+}
diff --git a/src/cases/services/index.ts b/src/cases/services/index.ts
new file mode 100644
index 000000000..77925f021
--- /dev/null
+++ b/src/cases/services/index.ts
@@ -0,0 +1,10 @@
+import { CaaCasesService } from './caa-cases.service';
+import { CaseShareService } from './share-case.service';
+
+export const services: any[] = [
+ CaaCasesService,
+ CaseShareService
+];
+
+export * from './caa-cases.service';
+export * from './share-case.service';
diff --git a/src/cases/services/share-case.service.spec.ts b/src/cases/services/share-case.service.spec.ts
new file mode 100644
index 000000000..8ac638b09
--- /dev/null
+++ b/src/cases/services/share-case.service.spec.ts
@@ -0,0 +1,54 @@
+import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
+import { of } from 'rxjs';
+import { CaseShareService } from './share-case.service';
+
+describe('CaseShareService', () => {
+ describe('getUsersFromOrg()', () => {
+ it('should make a get request to the user details end-point', () => {
+ const mockHttp = jasmine.createSpyObj('http', ['get']);
+ mockHttp.get.and.returnValue(of({}));
+ const service = new CaseShareService(mockHttp);
+ service.getUsersFromOrg();
+ expect(mockHttp.get).toHaveBeenCalledWith('api/caseshare/users');
+ });
+ });
+
+ describe('getShareCases()', () => {
+ it('should get share cases with correct params', () => {
+ const cases: SharedCase[] = [
+ { caseId: '1', caseTitle: '1' },
+ { caseId: '2', caseTitle: '2' }
+ ];
+
+ const mockHttp = jasmine.createSpyObj('http', ['get']);
+ mockHttp.get.and.returnValue(of({}));
+ const service = new CaseShareService(mockHttp);
+ service.getShareCases(cases);
+
+ const expectedOptions = {
+ params: {
+ case_ids: '1,2'
+ }
+ };
+ expect(mockHttp.get).toHaveBeenCalledWith('api/caseshare/cases', expectedOptions);
+ });
+
+ it('should get share case with correct params', () => {
+ const cases = [
+ { caseId: '1' }
+ ] as SharedCase[];
+
+ const mockHttp = jasmine.createSpyObj('http', ['get']);
+ mockHttp.get.and.returnValue(of({}));
+ const service = new CaseShareService(mockHttp);
+ service.getShareCases(cases);
+
+ const expectedOptions = {
+ params: {
+ case_ids: '1'
+ }
+ };
+ expect(mockHttp.get).toHaveBeenCalledWith('api/caseshare/cases', expectedOptions);
+ });
+ });
+});
diff --git a/src/cases/services/share-case.service.ts b/src/cases/services/share-case.service.ts
new file mode 100644
index 000000000..82183bd43
--- /dev/null
+++ b/src/cases/services/share-case.service.ts
@@ -0,0 +1,28 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
+import { UserDetails } from '@hmcts/rpx-xui-common-lib/lib/models/user-details.model';
+import { Observable } from 'rxjs';
+
+@Injectable()
+export class CaseShareService {
+ constructor(private readonly http: HttpClient) {}
+
+ public getUsersFromOrg(): Observable {
+ return this.http.get('api/caseshare/users');
+ }
+
+ public getShareCases(shareCases: SharedCase[]): Observable {
+ const caseIds = shareCases.map((aCase) => aCase.caseId).join(',');
+ const options = {
+ params: {
+ case_ids: caseIds
+ }
+ };
+ return this.http.get('api/caseshare/cases', options);
+ }
+
+ public assignUsersWithCases(sharedCases: SharedCase[]): Observable {
+ return this.http.post('api/caseshare/case-assignments', { sharedCases });
+ }
+}
diff --git a/src/cases/store/actions/caa-cases.actions.spec.ts b/src/cases/store/actions/caa-cases.actions.spec.ts
new file mode 100644
index 000000000..ef002b0c7
--- /dev/null
+++ b/src/cases/store/actions/caa-cases.actions.spec.ts
@@ -0,0 +1,99 @@
+import { HttpErrorResponse } from '@angular/common/http';
+import { CaaCasesPageType } from '../../models/caa-cases.enum';
+import { CaaCases } from '../../models/caa-cases.model';
+import * as fromActions from './caa-cases.actions';
+
+describe('Caa actions', () => {
+ it('load assigned cases action', () => {
+ const caseType = 'caseTypeId1';
+ const pageNo = 1;
+ const pageSize = 10;
+ const caaCasesFilterType = null;
+ const caaCasesFilterValue = null;
+ const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
+ const action = new fromActions.LoadAssignedCases(payload);
+ expect({ ...action }).toEqual({
+ payload,
+ type: fromActions.LOAD_ASSIGNED_CASES
+ });
+ });
+
+ it('load assigned cases success action', () => {
+ const payload = {} as CaaCases;
+ const action = new fromActions.LoadAssignedCasesSuccess(payload);
+ expect({ ...action }).toEqual({
+ payload,
+ type: fromActions.LOAD_ASSIGNED_CASES_SUCCESS
+ });
+ });
+
+ it('load assigned cases failure action', () => {
+ const payload = new HttpErrorResponse({ error: 'assigned cases error' });
+ const action = new fromActions.LoadAssignedCasesFailure(payload);
+ expect({ ...action }).toEqual({
+ payload,
+ type: fromActions.LOAD_ASSIGNED_CASES_FAILURE
+ });
+ });
+
+ it('load unassigned cases action', () => {
+ const caseType = 'caseTypeId1';
+ const pageNo = 1;
+ const pageSize = 10;
+ const caaCasesFilterType = null;
+ const caaCasesFilterValue = null;
+ const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
+ const action = new fromActions.LoadUnassignedCases(payload);
+ expect({ ...action }).toEqual({
+ payload,
+ type: fromActions.LOAD_UNASSIGNED_CASES
+ });
+ });
+
+ it('load unassigned cases success action', () => {
+ const payload = {} as CaaCases;
+ const action = new fromActions.LoadUnassignedCasesSuccess(payload);
+ expect({ ...action }).toEqual({
+ payload,
+ type: fromActions.LOAD_UNASSIGNED_CASES_SUCCESS
+ });
+ });
+
+ it('load unassigned cases failure action', () => {
+ const payload = new HttpErrorResponse({ error: 'unassigned cases error' });
+ const action = new fromActions.LoadUnassignedCasesFailure(payload);
+ expect({ ...action }).toEqual({
+ payload,
+ type: fromActions.LOAD_UNASSIGNED_CASES_FAILURE
+ });
+ });
+
+ it('load case types action', () => {
+ const caaCasesFilterType = null;
+ const caaCasesFilterValue = null;
+ const payload = { caaCasesPageType: CaaCasesPageType.AssignedCases, caaCasesFilterType, caaCasesFilterValue };
+ const action = new fromActions.LoadCaseTypes(payload);
+ expect({ ...action }).toEqual({
+ payload,
+ type: fromActions.LOAD_CASE_TYPES
+ });
+ });
+
+ it('load case types success action', () => {
+ const payload = [];
+ const action = new fromActions.LoadCaseTypesSuccess(payload);
+ expect({ ...action }).toEqual({
+ payload,
+ type: fromActions.LOAD_CASE_TYPES_SUCCESS
+ });
+ });
+
+ it('load case types failure action', () => {
+ const payload = {};
+ const action = new fromActions.LoadCaseTypesFailure(payload);
+ expect({ ...action }).toEqual({
+ payload,
+ type: fromActions.LOAD_CASE_TYPES_FAILURE
+ });
+ });
+});
diff --git a/src/cases/store/actions/caa-cases.actions.ts b/src/cases/store/actions/caa-cases.actions.ts
new file mode 100644
index 000000000..3731eb040
--- /dev/null
+++ b/src/cases/store/actions/caa-cases.actions.ts
@@ -0,0 +1,76 @@
+import { HttpErrorResponse } from '@angular/common/http';
+import { Action } from '@ngrx/store';
+import { CaaCases } from '../../models/caa-cases.model';
+
+export const LOAD_ASSIGNED_CASES = '[CAA CASES] Load Assigned Cases';
+export const LOAD_ASSIGNED_CASES_SUCCESS = '[CAA CASES] Load Assigned Cases Success';
+export const LOAD_ASSIGNED_CASES_FAILURE = '[CAA CASES] Load Assigned Cases Failure';
+export const LOAD_UNASSIGNED_CASES = '[CAA CASES] Load Unassigned Cases';
+export const LOAD_UNASSIGNED_CASES_SUCCESS = '[CAA CASES] Load Unassigned Cases Success';
+export const LOAD_UNASSIGNED_CASES_FAILURE = '[CAA CASES] Load Unassigned Cases Failure';
+export const LOAD_CASE_TYPES = '[CAA CASES] Load Case Types';
+export const LOAD_CASE_TYPES_SUCCESS = '[CAA CASES] Load Case Types Success';
+export const LOAD_CASE_TYPES_FAILURE = '[CAA CASES] Load Case Types Failure';
+export const UPDATE_SELECTION_FOR_CASE_TYPE = '[CAA CASES] Update Selection For Case Types';
+
+export class LoadAssignedCases implements Action {
+ public readonly type = LOAD_ASSIGNED_CASES;
+ constructor(public payload: {caseType: string, pageNo: number, pageSize: number, caaCasesFilterType: string | null, caaCasesFilterValue: string | null}) {}
+}
+
+export class LoadAssignedCasesSuccess implements Action {
+ public readonly type = LOAD_ASSIGNED_CASES_SUCCESS;
+ constructor(public payload: CaaCases) {}
+}
+
+export class LoadAssignedCasesFailure implements Action {
+ public readonly type = LOAD_ASSIGNED_CASES_FAILURE;
+ constructor(public payload: HttpErrorResponse) {}
+}
+
+export class LoadUnassignedCases implements Action {
+ public readonly type = LOAD_UNASSIGNED_CASES;
+ constructor(public payload: {caseType: string, pageNo: number, pageSize: number, caaCasesFilterType: string | null, caaCasesFilterValue: string | null}) {}
+}
+
+export class LoadUnassignedCasesSuccess implements Action {
+ public readonly type = LOAD_UNASSIGNED_CASES_SUCCESS;
+ constructor(public payload: CaaCases) {}
+}
+
+export class LoadUnassignedCasesFailure implements Action {
+ public readonly type = LOAD_UNASSIGNED_CASES_FAILURE;
+ constructor(public payload: HttpErrorResponse) {}
+}
+
+export class LoadCaseTypes implements Action {
+ public readonly type = LOAD_CASE_TYPES;
+ constructor(public payload: {caaCasesPageType: string, caaCasesFilterType: string | null, caaCasesFilterValue: string | null}) {}
+}
+
+export class LoadCaseTypesSuccess implements Action {
+ public readonly type = LOAD_CASE_TYPES_SUCCESS;
+ constructor(public payload: any[]) {}
+}
+
+export class LoadCaseTypesFailure implements Action {
+ public readonly type = LOAD_CASE_TYPES_FAILURE;
+ constructor(public payload: any) {}
+}
+
+export class UpdateSelectionForCaseType implements Action {
+ public readonly type = UPDATE_SELECTION_FOR_CASE_TYPE;
+ constructor(public payload: {casetype: string; cases: any [] }) {}
+}
+
+export type CaaCasesActions =
+ LoadAssignedCases
+ | LoadAssignedCasesSuccess
+ | LoadAssignedCasesFailure
+ | LoadUnassignedCases
+ | LoadUnassignedCasesSuccess
+ | LoadUnassignedCasesFailure
+ | LoadCaseTypes
+ | LoadCaseTypesSuccess
+ | LoadCaseTypesFailure
+ | UpdateSelectionForCaseType;
diff --git a/src/cases/store/actions/index.ts b/src/cases/store/actions/index.ts
new file mode 100644
index 000000000..55c8e9243
--- /dev/null
+++ b/src/cases/store/actions/index.ts
@@ -0,0 +1,20 @@
+import {
+ LoadAssignedCases,
+ LoadAssignedCasesFailure,
+ LoadAssignedCasesSuccess,
+ LoadUnassignedCases,
+ LoadUnassignedCasesFailure,
+ LoadUnassignedCasesSuccess
+} from './caa-cases.actions';
+
+export const actions: any[] = [
+ LoadAssignedCases,
+ LoadAssignedCasesSuccess,
+ LoadAssignedCasesFailure,
+ LoadUnassignedCases,
+ LoadUnassignedCasesSuccess,
+ LoadUnassignedCasesFailure
+];
+
+export * from './caa-cases.actions';
+export * from './share-case.action';
diff --git a/src/cases/store/actions/share-case.action.spec.ts b/src/cases/store/actions/share-case.action.spec.ts
new file mode 100644
index 000000000..3775c8238
--- /dev/null
+++ b/src/cases/store/actions/share-case.action.spec.ts
@@ -0,0 +1,195 @@
+import * as fromCaseShare from './share-case.action';
+
+describe('Case Share Actions', () => {
+ it('NavigateToShareAssignedCases', () => {
+ const payload = [];
+ const action = new fromCaseShare.NavigateToShareAssignedCases(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.NAVIGATE_TO_SHARE_ASSIGNED_CASES,
+ payload
+ });
+ });
+
+ it('NavigateToShareUnassignedCases', () => {
+ const payload = [];
+ const action = new fromCaseShare.NavigateToShareUnassignedCases(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.NAVIGATE_TO_SHARE_UNASSIGNED_CASES,
+ payload
+ });
+ });
+
+ it('SynchronizeStateToStoreAssignedCases', () => {
+ const payload = [];
+ const action = new fromCaseShare.SynchronizeStateToStoreAssignedCases(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.SYNCHRONIZE_STATE_TO_STORE_ASSIGNED_CASES,
+ payload
+ });
+ });
+
+ it('SynchronizeStateToStoreUnassignedCases', () => {
+ const payload = [];
+ const action = new fromCaseShare.SynchronizeStateToStoreUnassignedCases(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.SYNCHRONIZE_STATE_TO_STORE_UNASSIGNED_CASES,
+ payload
+ });
+ });
+
+ it('LoadShareAssignedCases', () => {
+ const payload = [];
+ const action = new fromCaseShare.LoadShareAssignedCases(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.LOAD_SHARE_ASSIGNED_CASES,
+ payload
+ });
+ });
+
+ it('LoadShareAssignedCasesSuccess', () => {
+ const payload = [];
+ const action = new fromCaseShare.LoadShareAssignedCasesSuccess(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.LOAD_SHARE_ASSIGNED_CASES_SUCCESS,
+ payload
+ });
+ });
+
+ it('LoadShareAssignedCaseFailure', () => {
+ const payload: Error = new Error();
+ const action = new fromCaseShare.LoadShareAssignedCaseFailure(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.LOAD_SHARE_ASSIGNED_CASES_FAILURE,
+ payload
+ });
+ });
+
+ it('LoadShareUnassignedCases', () => {
+ const payload = [];
+ const action = new fromCaseShare.LoadShareUnassignedCases(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.LOAD_SHARE_UNASSIGNED_CASES,
+ payload
+ });
+ });
+
+ it('LoadShareUnassignedAssignedCasesSuccess', () => {
+ const payload = [];
+ const action = new fromCaseShare.LoadShareUnassignedCasesSuccess(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.LOAD_SHARE_UNASSIGNED_CASES_SUCCESS,
+ payload
+ });
+ });
+
+ it('LoadShareUnassignedCaseFailure', () => {
+ const payload: Error = new Error();
+ const action = new fromCaseShare.LoadShareUnassignedCaseFailure(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.LOAD_SHARE_UNASSIGNED_CASES_FAILURE,
+ payload
+ });
+ });
+
+ it('LoadUserFromOrgForCase', () => {
+ const action = new fromCaseShare.LoadUserFromOrgForCase();
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.LOAD_USERS_FROM_ORG_FOR_CASE
+ });
+ });
+
+ it('AddShareAssignedCases', () => {
+ const payload = {
+ sharedCases: []
+ };
+ const action = new fromCaseShare.AddShareAssignedCases(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.ADD_SHARE_ASSIGNED_CASES,
+ payload
+ });
+ });
+
+ it('AddShareAssignedCaseGo', () => {
+ const payload = {
+ path: [],
+ sharedCases: []
+ };
+ const action = new fromCaseShare.AddShareAssignedCaseGo(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.ADD_SHARE_ASSIGNED_CASES_GO,
+ payload
+ });
+ });
+
+ it('AddShareUnassignedCases', () => {
+ const payload = {
+ sharedCases: []
+ };
+ const action = new fromCaseShare.AddShareUnassignedCases(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.ADD_SHARE_UNASSIGNED_CASES,
+ payload
+ });
+ });
+
+ it('AddShareUnassignedCaseGo', () => {
+ const payload = {
+ path: [],
+ sharedCases: []
+ };
+ const action = new fromCaseShare.AddShareUnassignedCaseGo(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.ADD_SHARE_UNASSIGNED_CASES_GO,
+ payload
+ });
+ });
+
+ it('DeleteAShareAssignedCase', () => {
+ const payload = {
+ caseId: '1'
+ };
+ const action = new fromCaseShare.DeleteAShareAssignedCase(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.DELETE_A_SHARE_ASSIGNED_CASE,
+ payload
+ });
+ });
+
+ it('DeleteAShareUnassignedCase', () => {
+ const payload = {
+ caseId: '1'
+ };
+ const action = new fromCaseShare.DeleteAShareUnassignedCase(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.DELETE_A_SHARE_UNASSIGNED_CASE,
+ payload
+ });
+ });
+
+ it('AssignUsersToAssignedCase', () => {
+ const payload = [];
+ const action = new fromCaseShare.AssignUsersToAssignedCase(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.ASSIGN_USERS_TO_ASSIGNED_CASE,
+ payload
+ });
+ });
+
+ it('AssignUsersToUnassignedCase', () => {
+ const payload = [];
+ const action = new fromCaseShare.AssignUsersToUnassignedCase(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.ASSIGN_USERS_TO_UNASSIGNED_CASE,
+ payload
+ });
+ });
+
+ it('LoadUserFromOrgForCaseSuccess', () => {
+ const payload = [];
+ const action = new fromCaseShare.LoadUserFromOrgForCaseSuccess(payload);
+ expect({ ...action }).toEqual({
+ type: fromCaseShare.LOAD_USERS_FROM_ORG_FOR_CASE_SUCCESS,
+ payload
+ });
+ });
+});
diff --git a/src/cases/store/actions/share-case.action.ts b/src/cases/store/actions/share-case.action.ts
new file mode 100644
index 000000000..4cd394632
--- /dev/null
+++ b/src/cases/store/actions/share-case.action.ts
@@ -0,0 +1,208 @@
+import { NavigationExtras } from '@angular/router';
+import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
+import { UserDetails } from '@hmcts/rpx-xui-common-lib/lib/models/user-details.model';
+import { Action } from '@ngrx/store';
+
+// Assigned cases actions
+export const NAVIGATE_TO_SHARE_ASSIGNED_CASES = '[ShareCase] Navigate To Share Assigned Cases';
+export const LOAD_SHARE_ASSIGNED_CASES = '[ShareCase] Load Share Assigned Cases';
+export const LOAD_SHARE_ASSIGNED_CASES_SUCCESS = '[ShareCase] Load Share Assigned Cases Success';
+export const LOAD_SHARE_ASSIGNED_CASES_FAILURE = '[ShareCase] Load Share Assigned Cases Failure';
+export const ADD_SHARE_ASSIGNED_CASES = '[ShareCase] Add Share Assigned Cases';
+export const ADD_SHARE_ASSIGNED_CASES_GO = '[Router] Add Share Assigned Case Go';
+export const DELETE_A_SHARE_ASSIGNED_CASE = '[ShareCase] Delete A Share Assigned Case';
+export const ASSIGN_USERS_TO_ASSIGNED_CASE = '[ShareCase] Assign Users to Assigned Case';
+export const ASSIGN_USERS_TO_ASSIGNED_CASE_SUCCESS = '[ShareCase] Assign Users to Assigned Case Success';
+export const RESET_ASSIGNED_CASE_SELECTION = '[ShareCase] Reset Assigned Case Selection';
+
+// Unassigned cases actions
+export const NAVIGATE_TO_SHARE_UNASSIGNED_CASES = '[ShareCase] Navigate To Share Unassigned Cases';
+export const LOAD_SHARE_UNASSIGNED_CASES = '[ShareCase] Load Share Unassigned Cases';
+export const LOAD_SHARE_UNASSIGNED_CASES_SUCCESS = '[ShareCase] Load Share Unassigned Cases Success';
+export const LOAD_SHARE_UNASSIGNED_CASES_FAILURE = '[ShareCase] Load Share Unassigned Cases Failure';
+export const ADD_SHARE_UNASSIGNED_CASES = '[ShareCase] Add Share Unassigned Cases';
+export const ADD_SHARE_UNASSIGNED_CASES_GO = '[Router] Add Share Unassigned Case Go';
+export const DELETE_A_SHARE_UNASSIGNED_CASE = '[ShareCase] Delete A Share Unassigned Case';
+export const ASSIGN_USERS_TO_UNASSIGNED_CASE = '[ShareCase] Assign Users to Unassigned Case';
+export const ASSIGN_USERS_TO_UNASSIGNED_CASE_SUCCESS = '[ShareCase] Assign Users to Unassigned Case Success';
+export const RESET_UNASSIGNED_CASE_SELECTION = '[ShareCase] Reset Unassigned Case Selection';
+
+export const LOAD_USERS_FROM_ORG_FOR_CASE = '[LoadUsers] From ORG For A Case';
+export const LOAD_USERS_FROM_ORG_FOR_CASE_SUCCESS = '[LoadUsers] From ORG For A Case Success';
+export const SYNCHRONIZE_STATE_TO_STORE_ASSIGNED_CASES = '[ShareCase] Synchronize State To Store Assigned Cases';
+export const SYNCHRONIZE_STATE_TO_STORE_UNASSIGNED_CASES = '[ShareCase] Synchronize State To Store Unassigned Cases';
+
+export class NavigateToShareAssignedCases implements Action {
+ public readonly type = NAVIGATE_TO_SHARE_ASSIGNED_CASES;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class NavigateToShareUnassignedCases implements Action {
+ public readonly type = NAVIGATE_TO_SHARE_UNASSIGNED_CASES;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class SynchronizeStateToStoreAssignedCases implements Action {
+ public readonly type = SYNCHRONIZE_STATE_TO_STORE_ASSIGNED_CASES;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class SynchronizeStateToStoreUnassignedCases implements Action {
+ public readonly type = SYNCHRONIZE_STATE_TO_STORE_UNASSIGNED_CASES;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class LoadShareAssignedCases implements Action {
+ public readonly type = LOAD_SHARE_ASSIGNED_CASES;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class LoadShareAssignedCasesSuccess implements Action {
+ public readonly type = LOAD_SHARE_ASSIGNED_CASES_SUCCESS;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class LoadShareAssignedCaseFailure implements Action {
+ public readonly type = LOAD_SHARE_ASSIGNED_CASES_FAILURE;
+ constructor(public payload: Error) {}
+}
+
+export class LoadShareUnassignedCases implements Action {
+ public readonly type = LOAD_SHARE_UNASSIGNED_CASES;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class LoadShareUnassignedCasesSuccess implements Action {
+ public readonly type = LOAD_SHARE_UNASSIGNED_CASES_SUCCESS;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class LoadShareUnassignedCaseFailure implements Action {
+ public readonly type = LOAD_SHARE_UNASSIGNED_CASES_FAILURE;
+ constructor(public payload: Error) {}
+}
+
+export class AddShareAssignedCases implements Action {
+ public readonly type = ADD_SHARE_ASSIGNED_CASES;
+ constructor(public payload: {
+ path?: any[];
+ query?: object;
+ extras?: NavigationExtras;
+ sharedCases: SharedCase[]
+ }) {}
+}
+
+export class AddShareAssignedCaseGo implements Action {
+ public readonly type = ADD_SHARE_ASSIGNED_CASES_GO;
+ constructor(
+ public payload: {
+ path: any[];
+ query?: object;
+ extras?: NavigationExtras;
+ sharedCases: SharedCase[]
+ }
+ ) {}
+}
+
+export class AddShareUnassignedCases implements Action {
+ public readonly type = ADD_SHARE_UNASSIGNED_CASES;
+ constructor(public payload: {
+ path?: any[];
+ query?: object;
+ extras?: NavigationExtras;
+ sharedCases: SharedCase[]
+ }) {}
+}
+
+export class AddShareUnassignedCaseGo implements Action {
+ public readonly type = ADD_SHARE_UNASSIGNED_CASES_GO;
+ constructor(
+ public payload: {
+ path: any[];
+ query?: object;
+ extras?: NavigationExtras;
+ sharedCases: SharedCase[]
+ }
+ ) {}
+}
+
+export class DeleteAShareAssignedCase implements Action {
+ public readonly type = DELETE_A_SHARE_ASSIGNED_CASE;
+ constructor(
+ public payload: {
+ caseId: string;
+ }
+ ) {}
+}
+
+export class DeleteAShareUnassignedCase implements Action {
+ public readonly type = DELETE_A_SHARE_UNASSIGNED_CASE;
+ constructor(
+ public payload: {
+ caseId: string;
+ }
+ ) {}
+}
+
+export class AssignUsersToAssignedCase implements Action {
+ public readonly type = ASSIGN_USERS_TO_ASSIGNED_CASE;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class AssignUsersToAssignedCaseSuccess implements Action {
+ public readonly type = ASSIGN_USERS_TO_ASSIGNED_CASE_SUCCESS;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class AssignUsersToUnassignedCase implements Action {
+ public readonly type = ASSIGN_USERS_TO_UNASSIGNED_CASE;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class AssignUsersToUnassignedCaseSuccess implements Action {
+ public readonly type = ASSIGN_USERS_TO_UNASSIGNED_CASE_SUCCESS;
+ constructor(public payload: SharedCase[]) {}
+}
+
+export class ResetAssignedCaseSelection implements Action {
+ public readonly type = RESET_ASSIGNED_CASE_SELECTION;
+}
+
+export class ResetUnassignedCaseSelection implements Action {
+ public readonly type = RESET_UNASSIGNED_CASE_SELECTION;
+}
+
+export class LoadUserFromOrgForCase implements Action {
+ public readonly type = LOAD_USERS_FROM_ORG_FOR_CASE;
+}
+
+export class LoadUserFromOrgForCaseSuccess implements Action {
+ public readonly type = LOAD_USERS_FROM_ORG_FOR_CASE_SUCCESS;
+ constructor(public payload: UserDetails[]) {}
+}
+
+export type Actions =
+ NavigateToShareAssignedCases
+ | NavigateToShareUnassignedCases
+ | SynchronizeStateToStoreAssignedCases
+ | SynchronizeStateToStoreUnassignedCases
+ | LoadShareAssignedCases
+ | LoadShareAssignedCasesSuccess
+ | LoadShareAssignedCaseFailure
+ | LoadShareUnassignedCases
+ | LoadShareUnassignedCasesSuccess
+ | LoadShareUnassignedCaseFailure
+ | AddShareAssignedCases
+ | AddShareAssignedCaseGo
+ | AddShareUnassignedCases
+ | AddShareUnassignedCaseGo
+ | DeleteAShareAssignedCase
+ | DeleteAShareUnassignedCase
+ | AssignUsersToAssignedCase
+ | AssignUsersToAssignedCaseSuccess
+ | AssignUsersToUnassignedCase
+ | AssignUsersToUnassignedCaseSuccess
+ | ResetAssignedCaseSelection
+ | ResetUnassignedCaseSelection
+ | LoadUserFromOrgForCase
+ | LoadUserFromOrgForCaseSuccess;
diff --git a/src/cases/store/effects/caa-cases.effects.spec.ts b/src/cases/store/effects/caa-cases.effects.spec.ts
new file mode 100644
index 000000000..55e320545
--- /dev/null
+++ b/src/cases/store/effects/caa-cases.effects.spec.ts
@@ -0,0 +1,160 @@
+import { HttpErrorResponse } from '@angular/common/http';
+import { TestBed } from '@angular/core/testing';
+import { provideMockActions } from '@ngrx/effects/testing';
+import { addMatchers, cold, hot, initTestScheduler } from 'jasmine-marbles';
+import { of, throwError } from 'rxjs';
+import { NavItemModel } from '../../../app/models/nav-items.model';
+import { LoggerService } from '../../../shared/services/logger.service';
+import { CaaCasesPageType } from '../../models/caa-cases.enum';
+import { CaaCases } from '../../models/caa-cases.model';
+import { CaaCasesService } from '../../services';
+import * as caaCasesActions from '../actions/caa-cases.actions';
+import { CaaCasesEffects } from './caa-cases.effects';
+
+describe('CaaCasesEffects', () => {
+ let actions$;
+ let effects: CaaCasesEffects;
+ const caaCasesServiceMock = jasmine.createSpyObj('CaaCasesService', ['getCaaCases', 'getCaaCaseTypes']);
+ const loggerServiceMock = jasmine.createSpyObj('LoggerService', ['error']);
+ const assignedCases = {} as CaaCases;
+ const unassignedCases = {} as CaaCases;
+ const navItems = [] as NavItemModel[];
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [],
+ providers: [
+ { provide: CaaCasesService, useValue: caaCasesServiceMock },
+ { provide: LoggerService, useValue: loggerServiceMock },
+ CaaCasesEffects,
+ provideMockActions(() => actions$)
+ ]
+ });
+ effects = TestBed.inject(CaaCasesEffects);
+ initTestScheduler();
+ addMatchers();
+ });
+
+ describe('loadAssignedCases$', () => {
+ it('loadAssignedCases successful', () => {
+ caaCasesServiceMock.getCaaCases.and.returnValue(of(assignedCases));
+ const caseType = '';
+ const pageNo = 1;
+ const pageSize = 10;
+ const caaCasesFilterType = null;
+ const caaCasesFilterValue = null;
+ const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
+ const action = new caaCasesActions.LoadAssignedCases(payload);
+ const completion = new caaCasesActions.LoadAssignedCasesSuccess(assignedCases);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.loadAssignedCases$).toBeObservable(expected);
+ });
+
+ it('loadAssignedCases error', () => {
+ const error: HttpErrorResponse = {
+ error: 'Error',
+ status: 400,
+ message: 'Error',
+ headers: null,
+ statusText: null,
+ name: null,
+ ok: false,
+ type: null,
+ url: null
+ };
+ caaCasesServiceMock.getCaaCases.and.returnValue(throwError(error));
+ const caseType = '';
+ const pageNo = 1;
+ const pageSize = 10;
+ const caaCasesFilterType = null;
+ const caaCasesFilterValue = null;
+ const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
+ const action = new caaCasesActions.LoadAssignedCases(payload);
+ const completion = new caaCasesActions.LoadAssignedCasesFailure(error);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.loadAssignedCases$).toBeObservable(expected);
+ });
+ });
+
+ describe('loadUnassignedCases$', () => {
+ it('loadUnassignedCases successful', () => {
+ caaCasesServiceMock.getCaaCases.and.returnValue(of(unassignedCases));
+ const caseType = '';
+ const pageNo = 1;
+ const pageSize = 10;
+ const caaCasesFilterType = null;
+ const caaCasesFilterValue = null;
+ const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
+ const action = new caaCasesActions.LoadUnassignedCases(payload);
+ const completion = new caaCasesActions.LoadUnassignedCasesSuccess(unassignedCases);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.loadUnassignedCases$).toBeObservable(expected);
+ });
+
+ it('loadUnassignedCases error', () => {
+ const error: HttpErrorResponse = {
+ error: 'Error',
+ status: 400,
+ message: 'Error',
+ headers: null,
+ statusText: null,
+ name: null,
+ ok: false,
+ type: null,
+ url: null
+ };
+ caaCasesServiceMock.getCaaCases.and.returnValue(throwError(error));
+ const caseType = '';
+ const pageNo = 1;
+ const pageSize = 10;
+ const caaCasesFilterType = null;
+ const caaCasesFilterValue = null;
+ const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
+ const action = new caaCasesActions.LoadUnassignedCases(payload);
+ const completion = new caaCasesActions.LoadUnassignedCasesFailure(error);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.loadUnassignedCases$).toBeObservable(expected);
+ });
+ });
+
+ describe('loadCaseTypes$', () => {
+ it('loadCaseTypes successful', () => {
+ caaCasesServiceMock.getCaaCaseTypes.and.returnValue(of(navItems));
+ const caaCasesFilterType = null;
+ const caaCasesFilterValue = null;
+ const payload = { caaCasesPageType: CaaCasesPageType.AssignedCases, caaCasesFilterType, caaCasesFilterValue };
+ const action = new caaCasesActions.LoadCaseTypes(payload);
+ const completion = new caaCasesActions.LoadCaseTypesSuccess(navItems);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.loadCaseTypes$).toBeObservable(expected);
+ });
+
+ it('loadCaseTypes error', () => {
+ const error: HttpErrorResponse = {
+ error: 'Error',
+ status: 400,
+ message: 'Error',
+ headers: null,
+ statusText: null,
+ name: null,
+ ok: false,
+ type: null,
+ url: null
+ };
+ caaCasesServiceMock.getCaaCaseTypes.and.returnValue(throwError(error));
+ const caaCasesFilterType = null;
+ const caaCasesFilterValue = null;
+ const payload = { caaCasesPageType: CaaCasesPageType.AssignedCases, caaCasesFilterType, caaCasesFilterValue };
+ const action = new caaCasesActions.LoadCaseTypes(payload);
+ const completion = new caaCasesActions.LoadCaseTypesFailure(error);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.loadCaseTypes$).toBeObservable(expected);
+ });
+ });
+});
diff --git a/src/cases/store/effects/caa-cases.effects.ts b/src/cases/store/effects/caa-cases.effects.ts
new file mode 100644
index 000000000..337104295
--- /dev/null
+++ b/src/cases/store/effects/caa-cases.effects.ts
@@ -0,0 +1,74 @@
+import { HttpErrorResponse } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Actions, createEffect, ofType } from '@ngrx/effects';
+import { Action } from '@ngrx/store';
+import { Observable, of } from 'rxjs';
+import { catchError, map, switchMap } from 'rxjs/operators';
+import * as fromRoot from '../../../app/store/index';
+import { LoggerService } from '../../../shared/services/logger.service';
+import { CaaCasesPageType } from '../../models/caa-cases.enum';
+import { CaaCasesService } from '../../services/caa-cases.service';
+import { CaaCasesUtil } from '../../util/caa-cases.util';
+import * as fromCaaActions from '../actions/caa-cases.actions';
+
+@Injectable()
+export class CaaCasesEffects {
+ constructor(private readonly actions$: Actions,
+ private readonly caaCasesService: CaaCasesService,
+ private readonly loggerService: LoggerService) {
+ }
+
+ public loadAssignedCases$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(fromCaaActions.LOAD_ASSIGNED_CASES),
+ switchMap((action: fromCaaActions.LoadAssignedCases) => {
+ const payload = action.payload;
+ return this.caaCasesService.getCaaCases(payload.caseType, payload.pageNo, payload.pageSize, CaaCasesPageType.AssignedCases, payload.caaCasesFilterType, payload.caaCasesFilterValue).pipe(
+ map((caaCases) => new fromCaaActions.LoadAssignedCasesSuccess(caaCases)),
+ catchError((error) => CaaCasesEffects.handleError(error, this.loggerService, CaaCasesPageType.AssignedCases))
+ );
+ })
+ )
+ );
+
+ public loadUnassignedCases$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(fromCaaActions.LOAD_UNASSIGNED_CASES),
+ switchMap((action: fromCaaActions.LoadUnassignedCases) => {
+ const payload = action.payload;
+ return this.caaCasesService.getCaaCases(payload.caseType, payload.pageNo, payload.pageSize, CaaCasesPageType.UnassignedCases, payload.caaCasesFilterType, payload.caaCasesFilterValue).pipe(
+ map((caaCases) => new fromCaaActions.LoadUnassignedCasesSuccess(caaCases)),
+ catchError((error) => CaaCasesEffects.handleError(error, this.loggerService, CaaCasesPageType.UnassignedCases))
+ );
+ })
+ )
+ );
+
+ public loadCaseTypes$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(fromCaaActions.LOAD_CASE_TYPES),
+ switchMap((action: fromCaaActions.LoadCaseTypes) => {
+ const payload = action.payload;
+ return this.caaCasesService.getCaaCaseTypes(payload.caaCasesPageType, payload.caaCasesFilterType, payload.caaCasesFilterValue).pipe(
+ map((caaCaseTypes) => {
+ const navItems = CaaCasesUtil.getCaaNavItems(caaCaseTypes);
+ return new fromCaaActions.LoadCaseTypesSuccess(navItems);
+ }),
+ catchError((error) => {
+ this.loggerService.error(error);
+ return of(new fromCaaActions.LoadCaseTypesFailure(error));
+ })
+ );
+ })
+ )
+ );
+
+ public static handleError(error: HttpErrorResponse, loggerService: LoggerService, caaCasesPageType: string): Observable {
+ loggerService.error(error);
+ return error.status === 400
+ ? caaCasesPageType === CaaCasesPageType.UnassignedCases
+ ? of(new fromCaaActions.LoadUnassignedCasesFailure(error))
+ : of(new fromCaaActions.LoadAssignedCasesFailure(error))
+ : of(new fromRoot.Go({ path: ['/service-down'] }));
+ }
+}
diff --git a/src/cases/store/effects/index.ts b/src/cases/store/effects/index.ts
new file mode 100644
index 000000000..fa409d976
--- /dev/null
+++ b/src/cases/store/effects/index.ts
@@ -0,0 +1,11 @@
+import { CaaCasesEffects } from './caa-cases.effects';
+import { ShareCaseEffects } from './share-case.effects';
+
+export const effects: any[] = [
+ CaaCasesEffects,
+ ShareCaseEffects
+];
+
+export * from './caa-cases.effects';
+export * from './share-case.effects';
+
diff --git a/src/cases/store/effects/share-case.effects.spec.ts b/src/cases/store/effects/share-case.effects.spec.ts
new file mode 100644
index 000000000..80f45974f
--- /dev/null
+++ b/src/cases/store/effects/share-case.effects.spec.ts
@@ -0,0 +1,265 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { TestBed, waitForAsync } from '@angular/core/testing';
+import { Router } from '@angular/router';
+import { RouterTestingModule } from '@angular/router/testing';
+import { provideMockActions } from '@ngrx/effects/testing';
+import { Store, StoreModule } from '@ngrx/store';
+import { addMatchers, cold, hot, initTestScheduler } from 'jasmine-marbles';
+import { of } from 'rxjs';
+import { CaseShareService } from '../../services';
+import {
+ AddShareAssignedCaseGo,
+ AddShareAssignedCases,
+ AddShareUnassignedCaseGo,
+ AddShareUnassignedCases,
+ AssignUsersToAssignedCase,
+ AssignUsersToAssignedCaseSuccess,
+ AssignUsersToUnassignedCase,
+ AssignUsersToUnassignedCaseSuccess,
+ LoadShareAssignedCases,
+ LoadShareAssignedCasesSuccess,
+ LoadShareUnassignedCases,
+ LoadShareUnassignedCasesSuccess,
+ LoadUserFromOrgForCase,
+ LoadUserFromOrgForCaseSuccess
+} from '../actions';
+import * as shareCases from '../reducers/share-case.reducer';
+import * as fromShareCaseEffects from './share-case.effects';
+
+describe('Share Case Effects', () => {
+ let actions$;
+ let effects: fromShareCaseEffects.ShareCaseEffects;
+ let store: Store;
+ const routerMock = jasmine.createSpyObj('Router', [
+ 'navigate'
+ ]);
+ routerMock.url = '/unassigned-cases';
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ let spyOnDispatchToStore = jasmine.createSpy();
+ const caseShareServiceMock = jasmine.createSpyObj('CaseShareService', ['getShareCases', 'getUsersFromOrg', 'assignUsersWithCases']);
+
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ StoreModule.forRoot({}),
+ HttpClientTestingModule,
+ RouterTestingModule],
+ providers: [
+ {
+ provide: CaseShareService,
+ useValue: caseShareServiceMock
+ },
+ {
+ provide: Router,
+ useValue: routerMock
+ },
+ fromShareCaseEffects.ShareCaseEffects,
+ provideMockActions(() => actions$)
+ ]
+ });
+
+ store = TestBed.inject(Store);
+
+ spyOnDispatchToStore = spyOn(store, 'dispatch').and.callThrough();
+ effects = TestBed.inject(fromShareCaseEffects.ShareCaseEffects);
+
+ initTestScheduler();
+ addMatchers();
+ }));
+
+ describe('addShareAssignedCases$', () => {
+ it('should add share assigned case action', () => {
+ const action = new AddShareAssignedCases({
+ sharedCases: [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
+ });
+ const completion = new AddShareAssignedCaseGo({
+ path: ['/unassigned-cases/case-share'],
+ sharedCases: [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
+ });
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.addShareAssignedCases$).toBeObservable(expected);
+ });
+ });
+
+ describe('addShareUnassignedCases$', () => {
+ it('should add share unassigned case action', () => {
+ const action = new AddShareUnassignedCases({
+ sharedCases: [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
+ });
+ const completion = new AddShareUnassignedCaseGo({
+ path: ['/unassigned-cases/case-share'],
+ sharedCases: [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
+ });
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.addShareUnassignedCases$).toBeObservable(expected);
+ });
+ });
+
+ describe('navigateToAddShareAssignedCase$', () => {
+ it('should add share assigned case go', () => {
+ const payload = {
+ path: ['/unassigned-cases/case-share'],
+ sharedCases: [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
+ };
+ routerMock.navigate.and.returnValue(Promise.resolve(true));
+ const action = new AddShareAssignedCaseGo(payload);
+ actions$ = hot('-a', { a: action });
+ effects.navigateToAddShareAssignedCase$.subscribe(() => {
+ expect(routerMock.navigate).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('navigateToAddShareUnassignedCase$', () => {
+ it('should add share unassigned case go', () => {
+ const payload = {
+ path: ['/unassigned-cases/case-share'],
+ sharedCases: [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
+ };
+ routerMock.navigate.and.returnValue(Promise.resolve(true));
+ const action = new AddShareUnassignedCaseGo(payload);
+ actions$ = hot('-a', { a: action });
+ effects.navigateToAddShareUnassignedCase$.subscribe(() => {
+ expect(routerMock.navigate).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('loadShareAssignedCases$', () => {
+ it('should load share assigned cases', () => {
+ const requestPayload = [
+ { caseId: '1', caseTitle: 'James123' },
+ { caseId: '2', caseTitle: 'Steve321' }];
+ const returnPayload = [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }];
+ caseShareServiceMock.getShareCases.and.returnValue(of(returnPayload));
+ const action = new LoadShareAssignedCases(requestPayload);
+ const completion = new LoadShareAssignedCasesSuccess(returnPayload);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.loadShareAssignedCases$).toBeObservable(expected);
+ });
+ });
+
+ describe('loadShareUnassignedCases$', () => {
+ it('should load share unassigned cases', () => {
+ const requestPayload = [
+ { caseId: '1', caseTitle: 'James123' },
+ { caseId: '2', caseTitle: 'Steve321' }];
+ const returnPayload = [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }];
+ caseShareServiceMock.getShareCases.and.returnValue(of(returnPayload));
+ const action = new LoadShareUnassignedCases(requestPayload);
+ const completion = new LoadShareUnassignedCasesSuccess(returnPayload);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.loadShareUnassignedCases$).toBeObservable(expected);
+ });
+ });
+
+ describe('loadOrgUsers$', () => {
+ it('should load organisation users', () => {
+ const returnPayload = [
+ {
+ idamId: 'U111111',
+ firstName: 'James',
+ lastName: 'Priest',
+ email: 'james.priest@test.com'
+ },
+ {
+ idamId: 'U222222',
+ firstName: 'Shaun',
+ lastName: 'Godard',
+ email: 'shaun.godard@test.com'
+ }];
+ caseShareServiceMock.getUsersFromOrg.and.returnValue(of(returnPayload));
+ const action = new LoadUserFromOrgForCase();
+ const completion = new LoadUserFromOrgForCaseSuccess(returnPayload);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.loadOrgUsers$).toBeObservable(expected);
+ });
+ });
+
+ describe('assignUsersToAssignedCases$', () => {
+ it('should assign users with assigned cases', () => {
+ const requestPayload = [
+ {
+ caseId: '1', caseTitle: 'James123', caseTypeId: 'type1', sharedWith: [
+ {
+ idamId: 'U111111',
+ firstName: 'James',
+ lastName: 'Priest',
+ email: 'james.priest@test.com'
+ }]
+ },
+ {
+ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2', sharedWith: [
+ {
+ idamId: 'U222222',
+ firstName: 'Shaun',
+ lastName: 'Godard',
+ email: 'shaun.godard@test.com'
+ }]
+ }];
+ const returnPayload = [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }];
+ caseShareServiceMock.assignUsersWithCases.and.returnValue(of(returnPayload));
+ const action = new AssignUsersToAssignedCase(requestPayload);
+ const completion = new AssignUsersToAssignedCaseSuccess(returnPayload);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.assignUsersToAssignedCases$).toBeObservable(expected);
+ });
+ });
+
+ describe('assignUsersToUnassignedCases$', () => {
+ it('should assign users with unassigned cases', () => {
+ const requestPayload = [
+ {
+ caseId: '1', caseTitle: 'James123', caseTypeId: 'type1', sharedWith: [
+ {
+ idamId: 'U111111',
+ firstName: 'James',
+ lastName: 'Priest',
+ email: 'james.priest@test.com'
+ }]
+ },
+ {
+ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2', sharedWith: [
+ {
+ idamId: 'U222222',
+ firstName: 'Shaun',
+ lastName: 'Godard',
+ email: 'shaun.godard@test.com'
+ }]
+ }];
+ const returnPayload = [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }];
+ caseShareServiceMock.assignUsersWithCases.and.returnValue(of(returnPayload));
+ const action = new AssignUsersToUnassignedCase(requestPayload);
+ const completion = new AssignUsersToUnassignedCaseSuccess(returnPayload);
+ actions$ = hot('-a', { a: action });
+ const expected = cold('-b', { b: completion });
+ expect(effects.assignUsersToUnassignedCases$).toBeObservable(expected);
+ });
+ });
+});
diff --git a/src/cases/store/effects/share-case.effects.ts b/src/cases/store/effects/share-case.effects.ts
new file mode 100644
index 000000000..b5e3c6e68
--- /dev/null
+++ b/src/cases/store/effects/share-case.effects.ts
@@ -0,0 +1,148 @@
+import { Injectable } from '@angular/core';
+import { Router } from '@angular/router';
+import { Actions, createEffect, ofType } from '@ngrx/effects';
+import { Store } from '@ngrx/store';
+import { of } from 'rxjs';
+import { catchError, map, switchMap, tap } from 'rxjs/operators';
+import * as fromRoot from '../../../app/store/index';
+import { CaaCasesPageType } from '../../models/caa-cases.enum';
+import { CaseShareService } from '../../services';
+import * as shareCaseActions from '../actions/share-case.action';
+import * as shareCases from '../reducers/share-case.reducer';
+
+@Injectable()
+export class ShareCaseEffects {
+ public payload: any;
+
+ constructor(
+ private readonly actions$: Actions,
+ private readonly caseShareService: CaseShareService,
+ private readonly router: Router,
+ private readonly store: Store
+ ) {
+ }
+
+ public addShareAssignedCases$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(shareCaseActions.ADD_SHARE_ASSIGNED_CASES),
+ map((action: shareCaseActions.AddShareAssignedCases) => action.payload),
+ map((newCases) => {
+ return new shareCaseActions.AddShareAssignedCaseGo({
+ path: [`${this.router.url}/case-share`],
+ sharedCases: newCases.sharedCases
+ });
+ })
+ )
+ );
+
+ public addShareUnassignedCases$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(shareCaseActions.ADD_SHARE_UNASSIGNED_CASES),
+ map((action: shareCaseActions.AddShareUnassignedCases) => action.payload),
+ map((newCases) => {
+ return new shareCaseActions.AddShareUnassignedCaseGo({
+ path: [`${this.router.url}/case-share`],
+ sharedCases: newCases.sharedCases
+ });
+ })
+ )
+ );
+
+ public navigateToAddShareAssignedCase$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(shareCaseActions.ADD_SHARE_ASSIGNED_CASES_GO),
+ map((action: shareCaseActions.AddShareAssignedCaseGo) => action.payload),
+ tap(({ path, query: queryParams, extras, sharedCases }) => {
+ const thatSharedCases = sharedCases;
+ queryParams = { init: true, pageType: CaaCasesPageType.AssignedCases };
+ return this.router.navigate(path, { queryParams, ...extras }).then(() => {
+ this.store.dispatch(new shareCaseActions.NavigateToShareAssignedCases(thatSharedCases));
+ });
+ })
+ ),
+ { dispatch: false }
+ );
+
+ public navigateToAddShareUnassignedCase$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(shareCaseActions.ADD_SHARE_UNASSIGNED_CASES_GO),
+ map((action: shareCaseActions.AddShareUnassignedCaseGo) => action.payload),
+ tap(({ path, query: queryParams, extras, sharedCases }) => {
+ const thatSharedCases = sharedCases;
+ queryParams = { init: true, pageType: CaaCasesPageType.UnassignedCases };
+ return this.router.navigate(path, { queryParams, ...extras }).then(() => {
+ this.store.dispatch(new shareCaseActions.NavigateToShareUnassignedCases(thatSharedCases));
+ });
+ })
+ ),
+ { dispatch: false }
+ );
+
+ public loadShareAssignedCases$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(shareCaseActions.LOAD_SHARE_ASSIGNED_CASES),
+ map((action: shareCaseActions.LoadShareAssignedCases) => action.payload),
+ switchMap((payload) => {
+ this.payload = payload;
+ return this.caseShareService.getShareCases(payload).pipe(
+ map((response) => new shareCaseActions.LoadShareAssignedCasesSuccess(response)),
+ catchError(() => of(new fromRoot.Go({ path: ['/service-down'] })))
+ );
+ })
+ )
+ );
+
+ public loadShareUnassignedCases$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(shareCaseActions.LOAD_SHARE_UNASSIGNED_CASES),
+ map((action: shareCaseActions.LoadShareUnassignedCases) => action.payload),
+ switchMap((payload) => {
+ this.payload = payload;
+ return this.caseShareService.getShareCases(payload).pipe(
+ map((response) => new shareCaseActions.LoadShareUnassignedCasesSuccess(response)),
+ catchError(() => of(new fromRoot.Go({ path: ['/service-down'] })))
+ );
+ })
+ )
+ );
+
+ public loadOrgUsers$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(shareCaseActions.LOAD_USERS_FROM_ORG_FOR_CASE),
+ switchMap(() => {
+ return this.caseShareService.getUsersFromOrg().pipe(
+ map((response) => new shareCaseActions.LoadUserFromOrgForCaseSuccess(response)),
+ catchError(() => of(new fromRoot.Go({ path: ['/service-down'] })))
+ );
+ })
+ )
+ );
+
+ public assignUsersToAssignedCases$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(shareCaseActions.ASSIGN_USERS_TO_ASSIGNED_CASE),
+ map((action: shareCaseActions.AssignUsersToAssignedCase) => action.payload),
+ switchMap((payload) => {
+ this.payload = payload;
+ return this.caseShareService.assignUsersWithCases(payload).pipe(
+ map((response) => new shareCaseActions.AssignUsersToAssignedCaseSuccess(response)),
+ catchError(() => of(new fromRoot.Go({ path: ['/service-down'] })))
+ );
+ })
+ )
+ );
+
+ public assignUsersToUnassignedCases$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(shareCaseActions.ASSIGN_USERS_TO_UNASSIGNED_CASE),
+ map((action: shareCaseActions.AssignUsersToUnassignedCase) => action.payload),
+ switchMap((payload) => {
+ this.payload = payload;
+ return this.caseShareService.assignUsersWithCases(payload).pipe(
+ map((response) => new shareCaseActions.AssignUsersToUnassignedCaseSuccess(response)),
+ catchError(() => of(new fromRoot.Go({ path: ['/service-down'] })))
+ );
+ })
+ )
+ );
+}
diff --git a/src/cases/store/index.ts b/src/cases/store/index.ts
new file mode 100644
index 000000000..772e0e89d
--- /dev/null
+++ b/src/cases/store/index.ts
@@ -0,0 +1,4 @@
+export * from './reducers';
+export * from './effects';
+export * from './actions';
+export * from './selectors';
diff --git a/src/cases/store/reducers/caa-cases.reducer.spec.ts b/src/cases/store/reducers/caa-cases.reducer.spec.ts
new file mode 100644
index 000000000..41ec429b7
--- /dev/null
+++ b/src/cases/store/reducers/caa-cases.reducer.spec.ts
@@ -0,0 +1,61 @@
+import { HttpErrorResponse } from '@angular/common/http';
+import * as fromActions from '../actions/caa-cases.actions';
+import * as fromCaaCasesReducer from './caa-cases.reducer';
+
+describe('CaaCases Reducer', () => {
+ const initialState: fromCaaCasesReducer.CaaCasesState = {
+ assignedCases: {
+ idField: 'id1',
+ columnConfigs: null,
+ data: null
+ },
+ unassignedCases: {
+ idField: 'id2',
+ columnConfigs: null,
+ data: null
+ },
+ caseTypes: [],
+ selectedCases: {},
+ assignedCasesLastError: new HttpErrorResponse({ error: 'assigned cases error' }),
+ unassignedCasesLastError: new HttpErrorResponse({ error: 'unassigned cases error' })
+ };
+
+ it('should undefined action return default state', () => {
+ const caaCasesState = fromCaaCasesReducer.initialState;
+ const action = {} as any;
+ const state = fromCaaCasesReducer.caaCasesReducer(undefined, action);
+ expect(state).toBe(caaCasesState);
+ });
+
+ it('should loadAssignedCasesSuccess action set correct state', () => {
+ const action = new fromActions.LoadAssignedCasesSuccess(initialState.assignedCases);
+ const state = fromCaaCasesReducer.caaCasesReducer(initialState, action);
+ expect(state.assignedCases).toBe(initialState.assignedCases);
+ });
+
+ it('should LoadAssignedCasesFailure action set error', () => {
+ const error = new HttpErrorResponse({ error: 'assigned cases error' });
+ const action = new fromActions.LoadAssignedCasesFailure(initialState.assignedCasesLastError);
+ const state = fromCaaCasesReducer.caaCasesReducer(initialState, action);
+ expect(state.assignedCasesLastError).toEqual(error);
+ });
+
+ it('should loadUnassignedCasesSuccess action set correct state', () => {
+ const action = new fromActions.LoadUnassignedCasesSuccess(initialState.unassignedCases);
+ const state = fromCaaCasesReducer.caaCasesReducer(initialState, action);
+ expect(state.unassignedCases).toBe(initialState.unassignedCases);
+ });
+
+ it('should LoadUnassignedCasesFailure action set error', () => {
+ const error = new HttpErrorResponse({ error: 'unassigned cases error' });
+ const action = new fromActions.LoadUnassignedCasesFailure(initialState.unassignedCasesLastError);
+ const state = fromCaaCasesReducer.caaCasesReducer(initialState, action);
+ expect(state.unassignedCasesLastError).toEqual(error);
+ });
+
+ it('should loadCaseTypesSuccess action set correct state', () => {
+ const action = new fromActions.LoadCaseTypesSuccess(initialState.caseTypes);
+ const state = fromCaaCasesReducer.caaCasesReducer(initialState, action);
+ expect(state.caseTypes).toBe(initialState.caseTypes);
+ });
+});
diff --git a/src/cases/store/reducers/caa-cases.reducer.ts b/src/cases/store/reducers/caa-cases.reducer.ts
new file mode 100644
index 000000000..785943aee
--- /dev/null
+++ b/src/cases/store/reducers/caa-cases.reducer.ts
@@ -0,0 +1,49 @@
+import { HttpErrorResponse } from '@angular/common/http';
+import { SubNavigation } from '@hmcts/rpx-xui-common-lib/lib/gov-ui/components/hmcts-sub-navigation/hmcts-sub-navigation.component';
+import { CaaCases, SelectedCases } from '../../models/caa-cases.model';
+import * as fromCaaActions from '../actions/caa-cases.actions';
+
+export interface CaaCasesState {
+ assignedCases: CaaCases;
+ unassignedCases: CaaCases;
+ caseTypes: SubNavigation[];
+ selectedCases: SelectedCases;
+ assignedCasesLastError: HttpErrorResponse;
+ unassignedCasesLastError: HttpErrorResponse;
+}
+
+export const initialState: CaaCasesState = {
+ assignedCases: null,
+ unassignedCases: null,
+ caseTypes: [],
+ selectedCases: {},
+ assignedCasesLastError: null,
+ unassignedCasesLastError: null
+};
+
+export function caaCasesReducer(state = initialState, action: fromCaaActions.CaaCasesActions): CaaCasesState {
+ switch (action.type) {
+ case fromCaaActions.LOAD_ASSIGNED_CASES_SUCCESS:
+ return { ...state, assignedCases: action.payload, assignedCasesLastError: null };
+ case fromCaaActions.LOAD_ASSIGNED_CASES_FAILURE:
+ return { ...state, assignedCases: { idField: '', columnConfigs: [], data: [] }, assignedCasesLastError: action.payload };
+ case fromCaaActions.LOAD_UNASSIGNED_CASES_SUCCESS:
+ return { ...state, unassignedCases: action.payload, unassignedCasesLastError: null };
+ case fromCaaActions.LOAD_UNASSIGNED_CASES_FAILURE:
+ return { ...state, unassignedCases: { idField: '', columnConfigs: [], data: [] }, unassignedCasesLastError: action.payload };
+ case fromCaaActions.LOAD_CASE_TYPES_SUCCESS:
+ return { ...state, caseTypes: action.payload };
+ case fromCaaActions.UPDATE_SELECTION_FOR_CASE_TYPE:
+ const selectedCases: SelectedCases = { ...state.selectedCases };
+ selectedCases[action.payload.casetype] = action.payload.cases;
+ return { ...state, selectedCases };
+ default:
+ return state;
+ }
+}
+
+export const getAssignedCases = (state: CaaCasesState) => state.assignedCases;
+export const getAssignedCasesError = (state: CaaCasesState) => state.assignedCasesLastError;
+export const getUnassignedCases = (state: CaaCasesState) => state.unassignedCases;
+export const getUnassignedCasesError = (state: CaaCasesState) => state.unassignedCasesLastError;
+export const getCaseTypes = (state: CaaCasesState) => state.caseTypes;
diff --git a/src/cases/store/reducers/index.ts b/src/cases/store/reducers/index.ts
new file mode 100644
index 000000000..8963c3c70
--- /dev/null
+++ b/src/cases/store/reducers/index.ts
@@ -0,0 +1,21 @@
+import { ActionReducerMap, createFeatureSelector } from '@ngrx/store';
+import * as fromCaaCases from './caa-cases.reducer';
+import * as fromCaseShare from './share-case.reducer';
+
+export interface CaaCasesState {
+ caaCases: fromCaaCases.CaaCasesState;
+ caseShare: fromCaseShare.ShareCasesState;
+}
+
+export const reducers: ActionReducerMap = {
+ caaCases: fromCaaCases.caaCasesReducer,
+ caseShare: fromCaseShare.shareCasesReducer
+};
+
+export const getRootCaaCases = createFeatureSelector(
+ 'caaCases'
+);
+
+export * from './caa-cases.reducer';
+export * from './share-case.reducer';
+
diff --git a/src/cases/store/reducers/share-case.reducer.spec.ts b/src/cases/store/reducers/share-case.reducer.spec.ts
new file mode 100644
index 000000000..d7e17ee4e
--- /dev/null
+++ b/src/cases/store/reducers/share-case.reducer.spec.ts
@@ -0,0 +1,273 @@
+import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
+import * as fromActions from '../actions/share-case.action';
+import * as fromReducer from './share-case.reducer';
+
+describe('Share case reducer', () => {
+ describe('Actions', () => {
+ let initialState;
+
+ beforeEach(() => {
+ initialState = fromReducer.initialSharedCasesState;
+ });
+
+ it('should set correct object', () => {
+ const payload = {
+ sharedCases: []
+ };
+ const action = new fromActions.AddShareAssignedCases(payload);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ const mockState = { shareAssignedCases: [], shareUnassignedCases: [], loading: false, error: undefined, users: [] };
+ expect(state).toEqual(mockState);
+ });
+
+ it('should load state when navigate to share assigned case', () => {
+ const selectedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
+ const action = new fromActions.NavigateToShareAssignedCases(selectedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(state.shareAssignedCases.length).toEqual(2);
+ });
+
+ it('should load state when navigate to share unassigned case', () => {
+ const selectedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
+ const action = new fromActions.NavigateToShareUnassignedCases(selectedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(state.shareUnassignedCases.length).toEqual(2);
+ });
+
+ it('should load share assigned case', () => {
+ const selectedCases = [];
+ const action = new fromActions.LoadShareAssignedCases(selectedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(state.shareAssignedCases.length).toEqual(0);
+ expect(state.loading).toBeTruthy();
+ });
+
+ it('should load share unassigned case', () => {
+ const selectedCases = [];
+ const action = new fromActions.LoadShareUnassignedCases(selectedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(state.shareUnassignedCases.length).toEqual(0);
+ expect(state.loading).toBeTruthy();
+ });
+
+ it('should load share assigned case', () => {
+ const payload = {
+ path: [],
+ sharedCases: [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }
+ ]
+ };
+ const action = new fromActions.AddShareAssignedCaseGo(payload);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(state.shareAssignedCases.length).toEqual(2);
+ });
+
+ it('should load share unassigned case', () => {
+ const payload = {
+ path: [],
+ sharedCases: [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }
+ ]
+ };
+ const action = new fromActions.AddShareUnassignedCaseGo(payload);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(state.shareUnassignedCases.length).toEqual(2);
+ });
+
+ it('should load share assigned case with case type', () => {
+ initialState = {
+ shareAssignedCases: [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }
+ ]
+ };
+ const caseFromNode = [{ caseId: '1', caseTitle: '' }, { caseId: '2', caseTitle: '' }];
+ const action = new fromActions.LoadShareAssignedCasesSuccess(caseFromNode);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(state.shareAssignedCases.length).toEqual(2);
+ expect(state.shareAssignedCases[0].caseTypeId).toEqual('type1');
+ expect(state.shareAssignedCases[0].caseTitle).toEqual('James123');
+ });
+
+ it('should load share unassigned case with case type', () => {
+ initialState = {
+ shareUnassignedCases: [
+ { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
+ { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }
+ ]
+ };
+ const caseFromNode = [{ caseId: '1', caseTitle: '' }, { caseId: '2', caseTitle: '' }];
+ const action = new fromActions.LoadShareUnassignedCasesSuccess(caseFromNode);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(state.shareUnassignedCases.length).toEqual(2);
+ expect(state.shareUnassignedCases[0].caseTypeId).toEqual('type1');
+ expect(state.shareUnassignedCases[0].caseTitle).toEqual('James123');
+ });
+
+ it('should save selected share assigned cases into store', () => {
+ const selectedCases = {
+ sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
+ };
+ const action = new fromActions.AddShareAssignedCases(selectedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(state.shareAssignedCases.length).toEqual(2);
+ });
+
+ it('should save selected share unassigned cases into store', () => {
+ const selectedCases = {
+ sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
+ };
+ const action = new fromActions.AddShareUnassignedCases(selectedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(state.shareUnassignedCases.length).toEqual(2);
+ });
+
+ it('should save selected share cases without duplication', () => {
+ const selectedCases = {
+ sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
+ };
+ const addedSelectedCases = {
+ sharedCases: [{ caseId: '2', caseTitle: 'Steve321' }, { caseId: '3', caseTitle: 'Kenny456' }]
+ };
+ const oldAction = new fromActions.AddShareAssignedCases(selectedCases);
+ const oldState = fromReducer.shareCasesReducer(initialState, oldAction);
+ const newAction = new fromActions.AddShareAssignedCases(addedSelectedCases);
+ const newState = fromReducer.shareCasesReducer(oldState, newAction);
+ expect(newState.shareAssignedCases.length).toEqual(3);
+ });
+
+ it('should delete an assigned case from store', () => {
+ const selectedCases = {
+ sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
+ };
+ const oldAction = new fromActions.AddShareAssignedCases(selectedCases);
+ const oldState = fromReducer.shareCasesReducer(initialState, oldAction);
+ const payload = {
+ caseId: '1'
+ };
+ const newAction = new fromActions.DeleteAShareAssignedCase(payload);
+ const newState = fromReducer.shareCasesReducer(oldState, newAction);
+ expect(newState.shareAssignedCases.length).toEqual(1);
+ });
+
+ it('should delete an unassigned case from store', () => {
+ const selectedCases = {
+ sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
+ };
+ const oldAction = new fromActions.AddShareUnassignedCases(selectedCases);
+ const oldState = fromReducer.shareCasesReducer(initialState, oldAction);
+ const payload = {
+ caseId: '1'
+ };
+ const newAction = new fromActions.DeleteAShareUnassignedCase(payload);
+ const newState = fromReducer.shareCasesReducer(oldState, newAction);
+ expect(newState.shareUnassignedCases.length).toEqual(1);
+ });
+
+ it('should get state properties for assigned cases', () => {
+ const selectedCases = {
+ sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
+ };
+ const action = new fromActions.AddShareAssignedCases(selectedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(fromReducer.getShareAssignedCases(state).length).toEqual(2);
+ });
+
+ it('should get state properties for unassigned cases', () => {
+ const selectedCases = {
+ sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
+ };
+ const action = new fromActions.AddShareUnassignedCases(selectedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(fromReducer.getShareUnassignedCases(state).length).toEqual(2);
+ });
+
+ it('should load user from org for case success', () => {
+ const sharedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
+ const action = new fromActions.LoadShareAssignedCasesSuccess(sharedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(fromReducer.getOrganisationUsers(state)).toBeTruthy();
+ });
+
+ it('should synchronize state to store for assigned cases', () => {
+ const sharedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
+ const action = new fromActions.SynchronizeStateToStoreAssignedCases(sharedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(fromReducer.getShareAssignedCases(state).length).toEqual(2);
+ });
+
+ it('should synchronize state to store for unassigned cases', () => {
+ const sharedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
+ const action = new fromActions.SynchronizeStateToStoreUnassignedCases(sharedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(fromReducer.getShareUnassignedCases(state).length).toEqual(2);
+ });
+
+ it('should assign user to case success', () => {
+ const sharedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
+ const action = new fromActions.AssignUsersToAssignedCaseSuccess(sharedCases);
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(fromReducer.getShareAssignedCases(state).length).toEqual(2);
+ });
+
+ it('should reset state if share case completed', () => {
+ const action = new fromActions.ResetAssignedCaseSelection();
+ const state = fromReducer.shareCasesReducer(initialState, action);
+ expect(fromReducer.getShareAssignedCases(state).length).toEqual(0);
+ });
+
+ it('should sort users', () => {
+ const sharedCases = [
+ {
+ caseId: '9417373995765131',
+ caseTitle: 'Neha Vs Sanjet',
+ sharedWith: [
+ {
+ idamId: 'u444444',
+ firstName: 'Shaun',
+ lastName: 'Coldwell',
+ email: 'shaun.coldwell@woodford.com'
+ },
+ {
+ idamId: 'u333333',
+ firstName: 'James',
+ lastName: 'Priest',
+ email: 'james.priest@woodford.com'
+ }
+ ]
+ },
+ {
+ caseId: '9417373995765133',
+ caseTitle: 'Sam Green Vs Williams Lee',
+ sharedWith: [
+ {
+ idamId: 'u666666',
+ firstName: 'Kate',
+ lastName: 'Grant',
+ email: 'kate.grant@lambbrooks.com'
+ },
+ {
+ idamId: 'u888888',
+ firstName: 'Joel',
+ lastName: 'Molloy',
+ email: 'joel.molloy@lambbrooks.com'
+ }
+ ]
+ }
+ ];
+ const sortedCases: SharedCase[] = fromReducer.sortedUserInCases(sharedCases);
+ expect(sortedCases[0].caseId).toEqual('9417373995765131');
+ expect(sortedCases[0].sharedWith[0].firstName).toEqual('James');
+ expect(sortedCases[0].sharedWith[1].firstName).toEqual('Shaun');
+ expect(sortedCases[1].caseId).toEqual('9417373995765133');
+ expect(sortedCases[1].sharedWith[0].firstName).toEqual('Joel');
+ expect(sortedCases[1].sharedWith[1].firstName).toEqual('Kate');
+ });
+
+ afterEach(() => {
+ initialState = {};
+ });
+ });
+});
diff --git a/src/cases/store/reducers/share-case.reducer.ts b/src/cases/store/reducers/share-case.reducer.ts
new file mode 100644
index 000000000..abcc1391e
--- /dev/null
+++ b/src/cases/store/reducers/share-case.reducer.ts
@@ -0,0 +1,250 @@
+import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
+import { UserDetails } from '@hmcts/rpx-xui-common-lib/lib/models/user-details.model';
+import * as ShareCasesActions from '../actions/share-case.action';
+
+export interface ShareCasesState {
+ shareAssignedCases: SharedCase[];
+ shareUnassignedCases: SharedCase[];
+ loading: boolean;
+ error: Error;
+ users: UserDetails[];
+}
+
+export const initialSharedCasesState: ShareCasesState = {
+ shareAssignedCases: [],
+ shareUnassignedCases: [],
+ loading: false,
+ error: undefined,
+ users: []
+};
+
+export function shareCasesReducer(
+ state: ShareCasesState = initialSharedCasesState,
+ action: ShareCasesActions.Actions): ShareCasesState {
+ switch (action.type) {
+ case ShareCasesActions.NAVIGATE_TO_SHARE_ASSIGNED_CASES:
+ const navigateToShareAssignedCases = state.shareAssignedCases.slice();
+ for (const aCase of action.payload) {
+ if (!navigateToShareAssignedCases.some((hasACase) => hasACase.caseId === aCase.caseId)) {
+ navigateToShareAssignedCases.push(aCase);
+ }
+ }
+ return {
+ ...state,
+ shareAssignedCases: navigateToShareAssignedCases
+ };
+ case ShareCasesActions.LOAD_SHARE_ASSIGNED_CASES:
+ return {
+ ...state,
+ loading: true
+ };
+ case ShareCasesActions.LOAD_SHARE_ASSIGNED_CASES_SUCCESS:
+ const casesInStore = state.shareAssignedCases.slice();
+ const casesFromNode: SharedCase[] = sortedUserInCases(action.payload);
+ const casesWithTypes = [];
+ for (const aCase of casesInStore) {
+ const intersectionCase = casesFromNode.find((nodeCase) => nodeCase.caseId === aCase.caseId);
+ if (intersectionCase && intersectionCase.caseId) {
+ const caseTypeId = aCase.caseTypeId ? aCase.caseTypeId : null;
+ const caseTitle = aCase.caseTitle ? aCase.caseTitle : null;
+ const newCase: SharedCase = {
+ ...intersectionCase,
+ caseTypeId,
+ caseTitle
+ };
+ casesWithTypes.push(newCase);
+ } else {
+ casesWithTypes.push(aCase);
+ }
+ }
+ return {
+ ...state,
+ shareAssignedCases: casesWithTypes,
+ loading: false
+ };
+ case ShareCasesActions.LOAD_SHARE_ASSIGNED_CASES_FAILURE:
+ return {
+ ...state,
+ error: action.payload,
+ loading: false
+ };
+ case ShareCasesActions.ADD_SHARE_ASSIGNED_CASES:
+ const addShareAssignedCases = state.shareAssignedCases.slice();
+ for (const aCase of action.payload.sharedCases) {
+ if (!addShareAssignedCases.some((hasACase) => hasACase.caseId === aCase.caseId)) {
+ addShareAssignedCases.push(aCase);
+ }
+ }
+ return {
+ ...state,
+ shareAssignedCases: addShareAssignedCases
+ };
+ case ShareCasesActions.ADD_SHARE_ASSIGNED_CASES_GO:
+ const addShareAssignedCasesGo = state.shareAssignedCases.slice();
+ for (const aCase of action.payload.sharedCases) {
+ if (!addShareAssignedCasesGo.some((hasACase) => hasACase.caseId === aCase.caseId)) {
+ addShareAssignedCasesGo.push(aCase);
+ }
+ }
+ return {
+ ...state,
+ shareAssignedCases: addShareAssignedCasesGo
+ };
+ case ShareCasesActions.DELETE_A_SHARE_ASSIGNED_CASE:
+ const caseInStore4Delete = state.shareAssignedCases.slice();
+ for (let i = 0, l = caseInStore4Delete.length; i < l; i++) {
+ if (caseInStore4Delete[i].caseId === action.payload.caseId) {
+ caseInStore4Delete.splice(i, 1);
+ break;
+ }
+ }
+ return {
+ ...state,
+ shareAssignedCases: caseInStore4Delete
+ };
+ case ShareCasesActions.SYNCHRONIZE_STATE_TO_STORE_ASSIGNED_CASES:
+ return {
+ ...state,
+ shareAssignedCases: action.payload
+ };
+ case ShareCasesActions.ASSIGN_USERS_TO_ASSIGNED_CASE_SUCCESS:
+ return {
+ ...state,
+ shareAssignedCases: action.payload,
+ loading: true
+ };
+ case ShareCasesActions.RESET_ASSIGNED_CASE_SELECTION:
+ return {
+ ...state,
+ shareAssignedCases: [],
+ loading: false
+ };
+ case ShareCasesActions.NAVIGATE_TO_SHARE_UNASSIGNED_CASES:
+ const navigateToShareUnassignedCases = state.shareUnassignedCases.slice();
+ for (const aCase of action.payload) {
+ if (!navigateToShareUnassignedCases.some((hasACase) => hasACase.caseId === aCase.caseId)) {
+ navigateToShareUnassignedCases.push(aCase);
+ }
+ }
+ return {
+ ...state,
+ shareUnassignedCases: navigateToShareUnassignedCases
+ };
+ case ShareCasesActions.LOAD_SHARE_UNASSIGNED_CASES:
+ return {
+ ...state,
+ loading: true
+ };
+ case ShareCasesActions.LOAD_SHARE_UNASSIGNED_CASES_SUCCESS:
+ const unassignedCasesInStore = state.shareUnassignedCases.slice();
+ const unassignedCasesFromNode: SharedCase[] = sortedUserInCases(action.payload);
+ const unassignedCasesWithTypes = [];
+ for (const aCase of unassignedCasesInStore) {
+ const intersectionCase = unassignedCasesFromNode.find((nodeCase) => nodeCase.caseId === aCase.caseId);
+ if (intersectionCase && intersectionCase.caseId) {
+ const caseTypeId = aCase.caseTypeId ? aCase.caseTypeId : null;
+ const caseTitle = aCase.caseTitle ? aCase.caseTitle : null;
+ const newCase: SharedCase = {
+ ...intersectionCase,
+ caseTypeId,
+ caseTitle
+ };
+ unassignedCasesWithTypes.push(newCase);
+ } else {
+ unassignedCasesWithTypes.push(aCase);
+ }
+ }
+ return {
+ ...state,
+ shareUnassignedCases: unassignedCasesWithTypes,
+ loading: false
+ };
+ case ShareCasesActions.LOAD_SHARE_UNASSIGNED_CASES_FAILURE:
+ return {
+ ...state,
+ error: action.payload,
+ loading: false
+ };
+ case ShareCasesActions.ADD_SHARE_UNASSIGNED_CASES:
+ const addShareUnassignedCases = state.shareUnassignedCases.slice();
+ for (const aCase of action.payload.sharedCases) {
+ if (!addShareUnassignedCases.some((hasACase) => hasACase.caseId === aCase.caseId)) {
+ addShareUnassignedCases.push(aCase);
+ }
+ }
+ return {
+ ...state,
+ shareUnassignedCases: addShareUnassignedCases
+ };
+ case ShareCasesActions.ADD_SHARE_UNASSIGNED_CASES_GO:
+ const addShareUnassignedCasesGo = state.shareUnassignedCases.slice();
+ for (const aCase of action.payload.sharedCases) {
+ if (!addShareUnassignedCasesGo.some((hasACase) => hasACase.caseId === aCase.caseId)) {
+ addShareUnassignedCasesGo.push(aCase);
+ }
+ }
+ return {
+ ...state,
+ shareUnassignedCases: addShareUnassignedCasesGo
+ };
+ case ShareCasesActions.DELETE_A_SHARE_UNASSIGNED_CASE:
+ const unassignedCaseInStore4Delete = state.shareUnassignedCases.slice();
+ for (let i = 0, l = unassignedCaseInStore4Delete.length; i < l; i++) {
+ if (unassignedCaseInStore4Delete[i].caseId === action.payload.caseId) {
+ unassignedCaseInStore4Delete.splice(i, 1);
+ break;
+ }
+ }
+ return {
+ ...state,
+ shareUnassignedCases: unassignedCaseInStore4Delete
+ };
+ case ShareCasesActions.LOAD_USERS_FROM_ORG_FOR_CASE_SUCCESS:
+ return {
+ ...state,
+ users: action.payload
+ };
+ case ShareCasesActions.SYNCHRONIZE_STATE_TO_STORE_UNASSIGNED_CASES:
+ return {
+ ...state,
+ shareUnassignedCases: action.payload
+ };
+ case ShareCasesActions.ASSIGN_USERS_TO_UNASSIGNED_CASE_SUCCESS:
+ return {
+ ...state,
+ shareUnassignedCases: action.payload,
+ loading: true
+ };
+ case ShareCasesActions.RESET_UNASSIGNED_CASE_SELECTION:
+ return {
+ ...state,
+ shareUnassignedCases: [],
+ loading: false
+ };
+ default:
+ return state;
+ }
+}
+
+export function sortedUserInCases(pendingSortedCases: SharedCase[]): SharedCase[] {
+ const cases: SharedCase[] = [];
+ for (const aCase of pendingSortedCases) {
+ if (aCase.sharedWith) {
+ const sortedUsers: UserDetails[] = aCase.sharedWith.slice().sort((user1, user2) => {
+ return user1.firstName > user2.firstName ? 1 : (user2.firstName > user1.firstName ? -1 : 0);
+ });
+ const caseWithSortedUser = {
+ ...aCase,
+ sharedWith: sortedUsers
+ };
+ cases.push(caseWithSortedUser);
+ } else {
+ cases.push(aCase);
+ }
+ }
+ return cases;
+}
+
+export const getShareAssignedCases = (state: ShareCasesState) => state.shareAssignedCases;
+export const getShareUnassignedCases = (state: ShareCasesState) => state.shareUnassignedCases;
+export const getOrganisationUsers = (state: ShareCasesState) => state.users;
diff --git a/src/cases/store/selectors/caa-cases.selector.spec.ts b/src/cases/store/selectors/caa-cases.selector.spec.ts
new file mode 100644
index 000000000..6bdb53907
--- /dev/null
+++ b/src/cases/store/selectors/caa-cases.selector.spec.ts
@@ -0,0 +1,75 @@
+import { TestBed } from '@angular/core/testing';
+import { select, Store, StoreModule } from '@ngrx/store';
+import { reducers } from '../reducers';
+import { CaaCasesState, initialState } from '../reducers/caa-cases.reducer';
+import {
+ getAllAssignedCases,
+ getAllAssignedCasesError,
+ getAllCaseTypes,
+ getAllUnassignedCases,
+ getAllUnassignedCasesError,
+ getSelectedCases
+} from './caa-cases.selector';
+
+describe('CaaCases selectors', () => {
+ let store: Store;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ StoreModule.forRoot({}),
+ StoreModule.forFeature('caaCases', reducers)
+ ]
+ });
+ store = TestBed.inject(Store);
+ spyOn(store, 'dispatch').and.callThrough();
+ });
+
+ it('should return all assigned cases', () => {
+ let result;
+ store.pipe(select(getAllAssignedCases)).subscribe((value) => {
+ result = value;
+ });
+ expect(result).toEqual(initialState.assignedCases);
+ });
+
+ it('should return all assigned cases error', () => {
+ let result;
+ store.pipe(select(getAllAssignedCasesError)).subscribe((value) => {
+ result = value;
+ });
+ expect(result).toEqual(initialState.assignedCasesLastError);
+ });
+
+ it('should return all unassigned cases', () => {
+ let result;
+ store.pipe(select(getAllUnassignedCases)).subscribe((value) => {
+ result = value;
+ });
+ expect(result).toEqual(initialState.unassignedCases);
+ });
+
+ it('should return all unassigned cases error', () => {
+ let result;
+ store.pipe(select(getAllUnassignedCasesError)).subscribe((value) => {
+ result = value;
+ });
+ expect(result).toEqual(initialState.assignedCasesLastError);
+ });
+
+ it('should return all case types', () => {
+ let result;
+ store.pipe(select(getAllCaseTypes)).subscribe((value) => {
+ result = value;
+ });
+ expect(result).toEqual(initialState.caseTypes);
+ });
+
+ it('should return selected cases', () => {
+ let result;
+ store.pipe(select(getSelectedCases)).subscribe((value) => {
+ result = value;
+ });
+ expect(result).toEqual(initialState.selectedCases);
+ });
+});
diff --git a/src/cases/store/selectors/caa-cases.selector.ts b/src/cases/store/selectors/caa-cases.selector.ts
new file mode 100644
index 000000000..83966be27
--- /dev/null
+++ b/src/cases/store/selectors/caa-cases.selector.ts
@@ -0,0 +1,58 @@
+import { createSelector } from '@ngrx/store';
+import { AppUtils } from '../../../app/utils/app-utils';
+import * as fromFeature from '../reducers';
+
+export const getCaaCasesState = createSelector(
+ fromFeature.getRootCaaCases,
+ (state: fromFeature.CaaCasesState) => state.caaCases
+);
+
+export const getAllAssignedCases = createSelector(
+ getCaaCasesState,
+ (caaCases) => caaCases.assignedCases
+);
+
+export const getAllAssignedCasesError = createSelector(
+ getCaaCasesState,
+ fromFeature.getAssignedCasesError
+);
+
+export const getAllAssignedCaseData = createSelector(
+ getAllAssignedCases,
+ (caaCases) => caaCases ? caaCases.data : null
+);
+
+export const getAllUnassignedCases = createSelector(
+ getCaaCasesState,
+ (caaCases) => caaCases.unassignedCases
+);
+
+export const getAllUnassignedCasesError = createSelector(
+ getCaaCasesState,
+ fromFeature.getUnassignedCasesError
+);
+
+export const getAllUnassignedCaseData = createSelector(
+ getAllUnassignedCases,
+ (caaCases) => caaCases ? caaCases.data : null
+);
+
+export const getAllCaseTypes = createSelector(
+ getCaaCasesState,
+ (caaCases) => caaCases.caseTypes
+);
+
+export const getSelectedCases = createSelector(
+ getCaaCasesState,
+ (caaCases) => caaCases.selectedCases
+);
+
+export const anySelectedCases = createSelector(
+ getSelectedCases,
+ (selectedCases) => AppUtils.atLeastOneCase(selectedCases)
+);
+
+export const getSelectedCasesList = createSelector(
+ getSelectedCases,
+ (selectedCases) => AppUtils.getSelectedItemsList(selectedCases)
+);
diff --git a/src/cases/store/selectors/index.ts b/src/cases/store/selectors/index.ts
new file mode 100644
index 000000000..bcdc699d1
--- /dev/null
+++ b/src/cases/store/selectors/index.ts
@@ -0,0 +1,2 @@
+export * from './caa-cases.selector';
+export * from './share-case.selector';
diff --git a/src/cases/store/selectors/share-case.selector.ts b/src/cases/store/selectors/share-case.selector.ts
new file mode 100644
index 000000000..289872492
--- /dev/null
+++ b/src/cases/store/selectors/share-case.selector.ts
@@ -0,0 +1,23 @@
+import { createSelector } from '@ngrx/store';
+
+import * as fromFeature from '../reducers';
+
+export const getCaseShareState = createSelector(
+ fromFeature.getRootCaaCases,
+ (state: fromFeature.CaaCasesState) => state.caseShare
+);
+
+export const getShareAssignedCaseListState = createSelector(
+ getCaseShareState,
+ fromFeature.getShareAssignedCases
+);
+
+export const getShareUnassignedCaseListState = createSelector(
+ getCaseShareState,
+ fromFeature.getShareUnassignedCases
+);
+
+export const getOrganisationUsersState = createSelector(
+ getCaseShareState,
+ fromFeature.getOrganisationUsers
+);
diff --git a/src/cases/store/selectors/share-case.selectors.spec.ts b/src/cases/store/selectors/share-case.selectors.spec.ts
new file mode 100644
index 000000000..b11b194d7
--- /dev/null
+++ b/src/cases/store/selectors/share-case.selectors.spec.ts
@@ -0,0 +1,68 @@
+import { TestBed } from '@angular/core/testing';
+import { Router } from '@angular/router';
+import { RouterTestingModule } from '@angular/router/testing';
+import { select, Store, StoreModule } from '@ngrx/store';
+import { OrganisationState } from '../../../organisation/store';
+import { UserState } from '../../../users/store';
+import { CaaCasesComponent } from '../../containers';
+import { CaaCasesService } from '../../services';
+import { CaaCasesState, getShareAssignedCaseListState, reducers } from '../index';
+
+describe('Share case selectors', () => {
+ let store: Store;
+ let organisationStore: Store;
+ let userStore: Store;
+ let caaCasesService: jasmine.SpyObj;
+ const router: any = {};
+
+ beforeEach(() => {
+ caaCasesService = jasmine.createSpyObj(
+ 'caaCasesService',
+ [
+ 'getCaaCases',
+ 'getCaaCaseTypes',
+ 'storeSessionState',
+ 'retrieveSessionState',
+ 'removeSessionState'
+ ]
+ );
+ TestBed.configureTestingModule({
+ imports: [
+ StoreModule.forRoot({}),
+ StoreModule.forFeature('cases', reducers),
+ RouterTestingModule
+ ],
+ providers: [
+ { provide: Router, useValue: router },
+ { provide: CaaCasesService, useValue: caaCasesService }
+ ]
+ });
+ store = TestBed.inject(Store);
+ organisationStore = TestBed.inject(Store);
+ userStore = TestBed.inject(Store);
+ spyOn(store, 'dispatch').and.callThrough();
+ });
+
+ describe('get share case state', () => {
+ xit('should return search state', () => {
+ const caseListComponent = new CaaCasesComponent(store, organisationStore, userStore, router, caaCasesService);
+ caseListComponent.selectedCases = [{
+ case_id: '1',
+ case_fields: {
+ solsSolicitorAppReference: 'James123'
+ }
+ }, {
+ case_id: '2',
+ case_fields: {
+ solsSolicitorAppReference: 'Steve321'
+ }
+ }];
+ caseListComponent.shareAssignedCaseSubmit();
+ let result = [];
+ store.pipe(select(getShareAssignedCaseListState)).subscribe((value) => {
+ result = value;
+ });
+ expect(result.length).toEqual(2);
+ });
+ });
+});
diff --git a/src/cases/util/caa-cases.util.spec.ts b/src/cases/util/caa-cases.util.spec.ts
new file mode 100644
index 000000000..bbd348a21
--- /dev/null
+++ b/src/cases/util/caa-cases.util.spec.ts
@@ -0,0 +1,115 @@
+import { FormControl } from '@angular/forms';
+import { User } from '@hmcts/rpx-xui-common-lib';
+import { CaaCasesUtil } from './caa-cases.util';
+
+describe('CaaCasesUtil', () => {
+ let control: FormControl;
+
+ beforeEach(() => {
+ control = new FormControl({});
+ });
+
+ it('getCaaNavItems', () => {
+ const response = {
+ total: 11,
+ cases: [],
+ case_types_results: [
+ {
+ total: 1,
+ case_type_id: 'FT_MasterCaseType'
+ },
+ {
+ total: 1,
+ case_type_id: 'FT_ComplexCollectionComplex'
+ },
+ {
+ total: 5,
+ case_type_id: 'FT_Conditionals'
+ },
+ {
+ total: 4,
+ case_type_id: 'FT_ComplexOrganisation'
+ }
+ ]
+ };
+ const results = CaaCasesUtil.getCaaNavItems(response);
+ expect(results.length).toEqual(4);
+ expect(results[0].text).toEqual('FT_MasterCaseType');
+ expect(results[1].text).toEqual('FT_ComplexCollectionComplex');
+ expect(results[2].text).toEqual('FT_Conditionals');
+ expect(results[3].text).toEqual('FT_ComplexOrganisation');
+ expect(results[3].total).toEqual(4);
+ });
+
+ it('should fail caseReference validation if input is less than 16 digits after removing separators', () => {
+ control.setValue('1234 12-- -34-1234 123-');
+ const caseReferenceValidator = CaaCasesUtil.caseReferenceValidator();
+ expect(caseReferenceValidator(control)).toEqual({ caseReference: true });
+ });
+
+ it('should fail caseReference validation if input is more than 16 digits after removing separators', () => {
+ control.setValue('1234 12-- -34-1234 12345');
+ const caseReferenceValidator = CaaCasesUtil.caseReferenceValidator();
+ expect(caseReferenceValidator(control)).toEqual({ caseReference: true });
+ });
+
+ it('should pass caseReference validation if input is exactly 16 digits after removing separators', () => {
+ control.setValue('1234 12-- -34-1234 1234-');
+ const caseReferenceValidator = CaaCasesUtil.caseReferenceValidator();
+ expect(caseReferenceValidator(control)).toBeNull();
+ });
+
+ it('should fail caseReference validation if input is null', () => {
+ control.setValue(null);
+ const caseReferenceValidator = CaaCasesUtil.caseReferenceValidator();
+ expect(caseReferenceValidator(control)).toEqual({ caseReference: true });
+ });
+
+ it('should fail caseReference validation if input is the empty string', () => {
+ control.setValue('');
+ const caseReferenceValidator = CaaCasesUtil.caseReferenceValidator();
+ expect(caseReferenceValidator(control)).toEqual({ caseReference: true });
+ });
+
+ it('should fail caseReference validation if input contains one or more letters', () => {
+ control.setValue('1234-1234 1234123A');
+ const caseReferenceValidator = CaaCasesUtil.caseReferenceValidator();
+ expect(caseReferenceValidator(control)).toEqual({ caseReference: true });
+ });
+
+ it('should fail caseReference validation if input contains one or more symbols (except for "-")', () => {
+ control.setValue('1234-1234 1234_1234');
+ const caseReferenceValidator = CaaCasesUtil.caseReferenceValidator();
+ expect(caseReferenceValidator(control)).toEqual({ caseReference: true });
+ });
+
+ it('should pass assigneeName validation if input contains one or more characters', () => {
+ const user: User = {
+ userIdentifier: 'user123',
+ fullName: 'Lindsey Johnson',
+ email: 'user@test.com',
+ status: 'pending'
+ };
+ control.setValue(user);
+ const assigneeNameValidator = CaaCasesUtil.assigneeNameValidator();
+ expect(assigneeNameValidator(control)).toBeNull();
+ });
+
+ it('should fail assigneeName validation if input is empty', () => {
+ control.setValue('');
+ const assigneeNameValidator = CaaCasesUtil.assigneeNameValidator();
+ expect(assigneeNameValidator(control)).toEqual({ assigneeName: true });
+ });
+
+ it('should pass assigneeName validation if input string is in correct format', () => {
+ control.setValue('Lindsey Johnson - user@test.com');
+ const assigneeNameValidator = CaaCasesUtil.assigneeNameValidator();
+ expect(assigneeNameValidator(control)).toBeNull();
+ });
+
+ it('should fail assigneeName validation if input is not in expected format string', () => {
+ control.setValue('test string');
+ const assigneeNameValidator = CaaCasesUtil.assigneeNameValidator();
+ expect(assigneeNameValidator(control)).toEqual({ assigneeName: true });
+ });
+});
diff --git a/src/cases/util/caa-cases.util.ts b/src/cases/util/caa-cases.util.ts
new file mode 100644
index 000000000..c8ef2a00e
--- /dev/null
+++ b/src/cases/util/caa-cases.util.ts
@@ -0,0 +1,62 @@
+import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
+import { SubNavigation } from '@hmcts/rpx-xui-common-lib/lib/gov-ui/components/hmcts-sub-navigation/hmcts-sub-navigation.component';
+import { CaseTypesResultsResponse } from '../models/caa-cases.model';
+
+export class CaaCasesUtil {
+ public static getCaaNavItems(response: CaseTypesResultsResponse): SubNavigation[] {
+ const result = new Array();
+ if (response.case_types_results) {
+ response.case_types_results.forEach((caseType) => {
+ if (caseType.total > 0) {
+ result.push({
+ text: caseType.case_type_id,
+ href: caseType.case_type_id,
+ active: false,
+ total: caseType.total
+ });
+ }
+ });
+ }
+ return result;
+ }
+
+ /**
+ * Validates case reference entry. Excluding spaces and '-' characters, it accepts exactly 16 digits only. All other
+ * characters are invalid. (Taken from
+ * https://github.com/hmcts/rpx-xui-webapp/blob/feature/global-search/src/search/utils/search-validators.ts)
+ * @returns `ValidationErrors` object if validation fails; `null` if it passes
+ */
+ public static caseReferenceValidator(): ValidatorFn {
+ return (control: AbstractControl): ValidationErrors | null => {
+ // Use template literal to coerce control.value to a string in case it is null
+ if (!(`${control.value}`).replace(/[\s-]/g, '').match(/^\d{16}$/)) {
+ return { caseReference: true };
+ }
+ return null;
+ };
+ }
+
+ public static assigneeNameValidator(): ValidatorFn {
+ return (control: AbstractControl): ValidationErrors | null => {
+ if (!control.value) {
+ return { assigneeName: true };
+ }
+ if (typeof control.value === 'string' && (!control.value.includes('@') || !control.value.includes('-'))) {
+ return { assigneeName: true };
+ }
+ return null;
+ };
+ }
+
+ public static assigneeNameValidator2(): ValidatorFn {
+ return (control: AbstractControl): ValidationErrors | null => {
+ if (!control.value) {
+ return { assigneeName: true };
+ }
+ if (typeof control.value !== 'string' || control.value.includes('@') || control.value.includes('-')) {
+ return { assigneeName: true };
+ }
+ return null;
+ };
+ }
+}
From 01cfeca9898b56994e577deada1de6f3c54a499f Mon Sep 17 00:00:00 2001
From: Shaed Parkar
Date: Wed, 27 Mar 2024 12:36:48 +0000
Subject: [PATCH 09/44] Update nodejs version to 3.1.0 in Chart.yaml
---
charts/xui-mo-webapp/Chart.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/charts/xui-mo-webapp/Chart.yaml b/charts/xui-mo-webapp/Chart.yaml
index 64b24f350..b28d5f121 100644
--- a/charts/xui-mo-webapp/Chart.yaml
+++ b/charts/xui-mo-webapp/Chart.yaml
@@ -7,7 +7,7 @@ maintainers:
- name: HMCTS RPX XUI
dependencies:
- name: nodejs
- version: 3.0.0
+ version: 3.1.0
repository: 'https://hmctspublic.azurecr.io/helm/v1/repo/'
- name: redis
version: 16.13.0
From 66a16635b15c9d853d6f188c057dc7b564a3dfd6 Mon Sep 17 00:00:00 2001
From: Shaed Parkar
Date: Thu, 28 Mar 2024 13:38:33 +0000
Subject: [PATCH 10/44] Refactor case sharing component and filter component
---
.../cases-filter/cases-filter.component.ts | 1 +
.../case-share-confirm.component.ts | 18 +++++----------
.../case-share/case-share.component.ts | 22 ++++++-------------
3 files changed, 13 insertions(+), 28 deletions(-)
diff --git a/src/cases/components/cases-filter/cases-filter.component.ts b/src/cases/components/cases-filter/cases-filter.component.ts
index 0531f8ade..f25814ad7 100644
--- a/src/cases/components/cases-filter/cases-filter.component.ts
+++ b/src/cases/components/cases-filter/cases-filter.component.ts
@@ -63,6 +63,7 @@ export class CasesFilterComponent implements OnInit, OnChanges{
});
this.form.controls.filterOption.valueChanges.subscribe((value: CaaCasesFilterType) => {
+ this.filterApplied = false;
this.selectFilterOption(value);
this.handleOnFilterOptionChange(value);
});
diff --git a/src/cases/containers/case-share-confirm/case-share-confirm.component.ts b/src/cases/containers/case-share-confirm/case-share-confirm.component.ts
index 85aed976f..8feae1f13 100644
--- a/src/cases/containers/case-share-confirm/case-share-confirm.component.ts
+++ b/src/cases/containers/case-share-confirm/case-share-confirm.component.ts
@@ -30,19 +30,11 @@ export class CaseShareConfirmComponent implements OnInit {
}
public ngOnInit(): void {
- // Set fnTitle, backLink, changeLink (these two links are the same as each other) and confirmLink depending on
- // whether navigation is via the Unassigned Cases or Assigned Cases page
- if (this.url.startsWith('/unassigned-cases')) {
- this.fnTitle = 'Share a case';
- this.backLink = '/unassigned-cases/case-share';
- this.changeLink = '/unassigned-cases/case-share';
- this.completeLink = `/unassigned-cases/case-share-complete/${this.pageType}`;
- } else {
- this.fnTitle = 'Manage case sharing';
- this.backLink = '/assigned-cases/case-share';
- this.changeLink = '/assigned-cases/case-share';
- this.completeLink = `/assigned-cases/case-share-complete/${this.pageType}`;
- }
+ this.fnTitle = 'Manage case assignments';
+ this.backLink = '/cases/case-share';
+ this.changeLink = '/cases/case-share';
+ this.completeLink = `/cases/case-share-complete/${this.pageType}`;
+
this.shareCases$ = this.pageType === CaaCasesPageType.UnassignedCases
? this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState))
: this.store.pipe(select(fromCasesFeature.getShareAssignedCaseListState));
diff --git a/src/cases/containers/case-share/case-share.component.ts b/src/cases/containers/case-share/case-share.component.ts
index 2217c1d83..0b8ad0acb 100644
--- a/src/cases/containers/case-share/case-share.component.ts
+++ b/src/cases/containers/case-share/case-share.component.ts
@@ -46,21 +46,13 @@ export class CaseShareComponent implements OnInit {
// is via the Unassigned Cases or Assigned Cases page
const url = router.state.url.substring(0, router.state.url.indexOf('/', 1));
// Set backLink and confirmLink only if the URL is either "/unassigned-cases" or "/assigned-cases"
- if (url === '/unassigned-cases' || url === '/assigned-cases') {
- this.backLink = `${url}`;
- this.confirmLink = `${url}/case-share-confirm/${this.pageType}`;
- }
- if (url === '/unassigned-cases') {
- this.fnTitle = 'Share a case';
- this.title = 'Add recipient';
- this.addUserLabel = 'Enter email address';
- this.showRemoveUsers = false;
- } else if (url === '/assigned-cases') {
- this.fnTitle = 'Manage case sharing';
- this.title = 'Manage shared access to a case';
- this.addUserLabel = 'Add people to share access to the selected cases';
- this.showRemoveUsers = true;
- }
+ this.backLink = '/cases';
+ this.confirmLink = `${url}/case-share-confirm/${this.pageType}`;
+
+ this.fnTitle = 'Action a case';
+ this.title = 'Manage case assignments';
+ this.addUserLabel = 'Add people to share cases to the selected cases';
+ this.showRemoveUsers = true;
this.shareCases$ = this.pageType === CaaCasesPageType.UnassignedCases
? this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState))
From 45d877e026699c5753f1c45ed423700bee5b2726 Mon Sep 17 00:00:00 2001
From: Josh
Date: Fri, 8 Nov 2024 11:13:08 +0000
Subject: [PATCH 11/44] unassigned cases flow
---
api/caaCaseTypes/caaCaseTypes.util.ts | 13 +++++
api/caaCaseTypes/index.ts | 3 +-
api/configuration/references.ts | 1 +
.../case-share/case-share.component.ts | 1 +
src/cases/cases.routing.ts | 10 ++++
.../cases-filter/cases-filter.component.html | 16 ------
.../cases-filter/cases-filter.component.ts | 1 +
.../cases-results-table.component.html | 4 ++
.../cases-results-table.component.ts | 35 ++++++++++--
.../accept-cases/accept-cases.component.html | 55 +++++++++++++++++++
.../accept-cases/accept-cases.component.scss | 0
.../accept-cases.component.spec.ts | 0
.../accept-cases/accept-cases.component.ts | 45 +++++++++++++++
.../case-share/case-share.component.ts | 17 ++++--
.../containers/cases/cases.component.html | 17 +++++-
src/cases/containers/cases/cases.component.ts | 48 +++++++++++++---
src/cases/containers/index.ts | 4 +-
src/cases/models/caa-cases.enum.ts | 8 ++-
src/cases/models/caa-cases.model.ts | 4 ++
src/cases/store/actions/share-case.action.ts | 4 +-
src/cases/store/effects/caa-cases.effects.ts | 1 +
src/cases/store/effects/share-case.effects.ts | 9 ++-
src/cases/util/caa-cases.util.ts | 3 +-
23 files changed, 257 insertions(+), 42 deletions(-)
create mode 100644 src/cases/containers/accept-cases/accept-cases.component.html
create mode 100644 src/cases/containers/accept-cases/accept-cases.component.scss
create mode 100644 src/cases/containers/accept-cases/accept-cases.component.spec.ts
create mode 100644 src/cases/containers/accept-cases/accept-cases.component.ts
diff --git a/api/caaCaseTypes/caaCaseTypes.util.ts b/api/caaCaseTypes/caaCaseTypes.util.ts
index a840833ab..94366e605 100644
--- a/api/caaCaseTypes/caaCaseTypes.util.ts
+++ b/api/caaCaseTypes/caaCaseTypes.util.ts
@@ -1,5 +1,7 @@
import { CaaCasesPageType } from '../caaCases/enums';
import { searchCasesString } from './caaCaseTypes.constants';
+import { getConfigValue } from '../configuration';
+import { UNASSIGNED_CASE_TYPES } from '../configuration/references';
export function getRequestBody(organisationID: string, caaCasesPageType: string, caaCasesFilterValue?: string | string[]) {
const organisationAssignedUsersKey = `supplementary_data.orgs_assigned_users.${organisationID}`;
@@ -68,3 +70,14 @@ export function getRequestBody(organisationID: string, caaCasesPageType: string,
export function getApiPath(ccdPath: string, caseTypes: string) {
return `${ccdPath}${searchCasesString}${caseTypes}`;
}
+
+export function addCaseConfiguration(response) {
+ const resData = response.data;
+ const unassignedCaseConfig = getConfigValue(UNASSIGNED_CASE_TYPES);
+ resData.case_types_results.forEach((caseTypeResult) => {
+ const { case_type_id } = caseTypeResult;
+ if (unassignedCaseConfig[case_type_id]) {
+ caseTypeResult.caseConfig = unassignedCaseConfig[case_type_id];
+ }
+ });
+}
diff --git a/api/caaCaseTypes/index.ts b/api/caaCaseTypes/index.ts
index c2cbcd4ad..33bd287be 100644
--- a/api/caaCaseTypes/index.ts
+++ b/api/caaCaseTypes/index.ts
@@ -5,7 +5,7 @@ import { RoleAssignmentResponse } from '../caaCases/models/roleAssignmentRespons
import { getConfigValue } from '../configuration';
import { CASE_TYPES, SERVICES_MCA_PROXY_API_PATH } from '../configuration/references';
import { EnhancedRequest } from '../models/enhanced-request.interface';
-import { getApiPath, getRequestBody } from './caaCaseTypes.util';
+import { getApiPath, getRequestBody, addCaseConfiguration } from './caaCaseTypes.util';
export async function handleCaaCaseTypes(req: EnhancedRequest, res: Response, next: NextFunction) {
const caaCasesPageType = req.query.caaCasesPageType as string;
@@ -31,6 +31,7 @@ export async function handleCaaCaseTypes(req: EnhancedRequest, res: Response, ne
const payload = getRequestBody(orgId, caaCasesPageType, caaCasesFilterValue);
const response = await req.http.post(path, payload);
+ addCaseConfiguration(response);
res.send(response.data);
} catch (error) {
res.status(500).send({
diff --git a/api/configuration/references.ts b/api/configuration/references.ts
index d43307a35..d17234c00 100644
--- a/api/configuration/references.ts
+++ b/api/configuration/references.ts
@@ -77,6 +77,7 @@ export const REDIS_KEY_PREFIX = 'redis.prefix';
export const SESSION_TIMEOUTS = 'sessionTimeouts';
export const CASE_TYPES = 'caseTypes';
+export const UNASSIGNED_CASE_TYPES = 'unassignedCaseTypes';
// PACT
export const PACT_BROKER_URL = 'pact.brokerUrl';
diff --git a/src/caa-cases/containers/case-share/case-share.component.ts b/src/caa-cases/containers/case-share/case-share.component.ts
index 2217c1d83..17ab796fa 100644
--- a/src/caa-cases/containers/case-share/case-share.component.ts
+++ b/src/caa-cases/containers/case-share/case-share.component.ts
@@ -40,6 +40,7 @@ export class CaseShareComponent implements OnInit {
public ngOnInit(): void {
this.routerState$ = this.store.pipe(select(getRouterState));
this.routerState$.subscribe((router) => {
+ console.log(router.state);
this.init = router.state.queryParams.init;
this.pageType = router.state.queryParams.pageType;
// Set backLink, fnTitle, title, confirmLink, addUserLabel, and showRemoveUsers depending on whether navigation
diff --git a/src/cases/cases.routing.ts b/src/cases/cases.routing.ts
index a42866983..b076dc455 100644
--- a/src/cases/cases.routing.ts
+++ b/src/cases/cases.routing.ts
@@ -5,6 +5,7 @@ import { CaaCasesModule } from './cases.module';
import { CaseShareCompleteComponent, CaseShareComponent, CaseShareConfirmComponent, CasesComponent } from './containers';
import { FeatureToggleAccountGuard } from './guards/feature-toggle.guard';
import { RoleGuard } from './guards/user-role.guard';
+import { AcceptCasesComponent } from './containers/accept-cases/accept-cases.component';
export const ROUTES: Routes = [
{
@@ -42,6 +43,15 @@ export const ROUTES: Routes = [
FeatureToggleAccountGuard,
RoleGuard
]
+ },
+ {
+ path: 'accept-cases',
+ component: AcceptCasesComponent,
+ canActivate: [
+ AuthGuard,
+ FeatureToggleAccountGuard,
+ RoleGuard
+ ]
}
];
diff --git a/src/cases/components/cases-filter/cases-filter.component.html b/src/cases/components/cases-filter/cases-filter.component.html
index c203d4047..ba9cf3a7b 100644
--- a/src/cases/components/cases-filter/cases-filter.component.html
+++ b/src/cases/components/cases-filter/cases-filter.component.html
@@ -252,22 +252,6 @@ Filter cases
-
-
-
- !
-
- Warning
- The tabs below list all of your organisation's cases which are not assigned to any users. You can assign
- cases to users by selecting 'Manage cases'.
-
- You do not need to assigned cases to users if they have 'Access all cases in the organisation' enabled for
- that case type.
-
-
-
-
diff --git a/src/cases/components/cases-filter/cases-filter.component.ts b/src/cases/components/cases-filter/cases-filter.component.ts
index f25814ad7..84221990f 100644
--- a/src/cases/components/cases-filter/cases-filter.component.ts
+++ b/src/cases/components/cases-filter/cases-filter.component.ts
@@ -107,6 +107,7 @@ export class CasesFilterComponent implements OnInit, OnChanges{
}
public filterSelectedOrganisationUsers(searchTerm?: string | User): Observable> {
+ console.log('1232112321');
const filteredUsers = searchTerm && searchTerm.length > 0
? typeof(searchTerm) === 'string'
? this.selectedOrganisationUsers.filter((user) => this.getDisplayName(user).toLowerCase().includes(searchTerm.toLowerCase()))
diff --git a/src/cases/components/cases-results-table/cases-results-table.component.html b/src/cases/components/cases-results-table/cases-results-table.component.html
index 8342c913d..80bbc3f0d 100644
--- a/src/cases/components/cases-results-table/cases-results-table.component.html
+++ b/src/cases/components/cases-results-table/cases-results-table.component.html
@@ -59,3 +59,7 @@
+{{navItems}}
+
+ {{noCasesFoundMessage}}
+
diff --git a/src/cases/components/cases-results-table/cases-results-table.component.ts b/src/cases/components/cases-results-table/cases-results-table.component.ts
index 5c857f2d9..9b2d7c8b8 100644
--- a/src/cases/components/cases-results-table/cases-results-table.component.ts
+++ b/src/cases/components/cases-results-table/cases-results-table.component.ts
@@ -8,6 +8,7 @@ import { Observable } from 'rxjs';
import * as fromStore from '../../store';
import { CaaCases } from 'api/caaCases/interfaces';
+import { CaaCasesNoDataMessage } from 'src/cases/models/caa-cases.enum';
@Component({
selector: 'app-cases-results-table',
@@ -41,11 +42,12 @@ export class CasesResultsTableComponent {
}
@Input() paginationPageSize: number = 25;
- @Input() shareButtonText = 'Share case';
+ @Input() shareButtonText;
+ @Input() selectedFilterType;
@Output() public caseSelected = new EventEmitter();
@Output() public pageChanged = new EventEmitter();
- @Output() public shareButtonClicked = new EventEmitter();
+ @Output() public shareButtonClicked = new EventEmitter();
// Needed for the tab group
public navItems: any[];
@@ -72,6 +74,7 @@ export class CasesResultsTableComponent {
}
public tabChanged(event: { tab: { textLabel: string }}): void {
+ console.log(event);
this.totalCases = this.navItems.find((data) => data.text === event.tab.textLabel)
? this.navItems.find((data) => data.text === event.tab.textLabel).total
: 0;
@@ -123,17 +126,22 @@ export class CasesResultsTableComponent {
// sharedCases: converters.toShareCaseConverter(this.selectedUnassignedCases, this.currentCaseType)
// }));
// TODO: emit this action
- this.shareButtonClicked.emit();
+ this.shareButtonClicked.emit(this.currentCaseType);
}
private fixCurrentTab(items: any): void {
+ // TESTING: Add another tab to test case specific navigation
+ console.log(`test items: ${items}`);
+ if (items.length > 0){
+ items = [...items, { text: 'Asylum', href: 'Asylum', active: false, total: 3 }];
+ }
this.navItems = items;
if (items && items.length > 0) {
this.totalCases = items[0].total ? items[0].total : 0;
this.setTabItems(items[0].text);
} else {
this.totalCases = 0;
- // this.noCasesFoundMessage = this.getNoCasesFoundMessage();
+ this.noCasesFoundMessage = this.getNoCasesFoundMessage();
}
}
@@ -152,4 +160,23 @@ export class CasesResultsTableComponent {
}
// this.loadDataFromStore();
}
+
+ public getNoCasesFoundMessage(): string {
+ console.log(this.navItems);
+ console.log(this.selectedFilterType);
+ switch (this.selectedFilterType){
+ case 'all-assignees':
+ return CaaCasesNoDataMessage.NoAssignedCases;
+ case 'unassigned-cases':
+ return CaaCasesNoDataMessage.NoUnassignedCases;
+ case 'assignee-name':
+ return CaaCasesNoDataMessage.CasesFilterMessage;
+ case 'new-cases-to-accept':
+ return CaaCasesNoDataMessage.NoNewCases;
+ case 'case-reference-number':
+ return CaaCasesNoDataMessage.NoCaseIdMatches;
+ default:
+ return '';
+ }
+ }
}
diff --git a/src/cases/containers/accept-cases/accept-cases.component.html b/src/cases/containers/accept-cases/accept-cases.component.html
new file mode 100644
index 000000000..bdd79cf1f
--- /dev/null
+++ b/src/cases/containers/accept-cases/accept-cases.component.html
@@ -0,0 +1,55 @@
+Back
+
+ {{
+ (selectedOrganisation$ | async)?.name
+ }}
+ {{ pageTitle }}
+
+
+
\ No newline at end of file
diff --git a/src/cases/containers/accept-cases/accept-cases.component.scss b/src/cases/containers/accept-cases/accept-cases.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/cases/containers/accept-cases/accept-cases.component.spec.ts b/src/cases/containers/accept-cases/accept-cases.component.spec.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/cases/containers/accept-cases/accept-cases.component.ts b/src/cases/containers/accept-cases/accept-cases.component.ts
new file mode 100644
index 000000000..aa317909f
--- /dev/null
+++ b/src/cases/containers/accept-cases/accept-cases.component.ts
@@ -0,0 +1,45 @@
+import { Component, OnInit } from '@angular/core';
+import { Store, select } from '@ngrx/store';
+
+import * as organisationStore from '../../../organisation/store';
+import { OrganisationDetails } from 'src/models/organisation.model';
+import { Observable } from 'rxjs';
+import { FormBuilder, FormControl } from '@angular/forms';
+import { Router } from '@angular/router';
+
+@Component({
+ selector: 'app-exui-case-share',
+ templateUrl: './accept-cases.component.html',
+ styleUrls: ['./accept-cases.component.scss']
+})
+export class AcceptCasesComponent implements OnInit {
+ permissionsForm: any;
+ public selectedOrganisation$: Observable;
+ pageTitle: string;
+
+ constructor(
+ private readonly organisationStore: Store,
+ private fb: FormBuilder,
+ private readonly router: Router){
+ }
+
+ public ngOnInit(): void {
+ // Load selected organisation details from store
+ this.organisationStore.dispatch(new organisationStore.LoadOrganisation());
+ this.selectedOrganisation$ = this.organisationStore.pipe(select(organisationStore.getOrganisationSel));
+ this.pageTitle = 'Accept cases';
+
+ this.permissionsForm = this.fb.group({
+ assignmentType: ['notAssigning']
+ });
+ }
+
+ public continue(){
+ console.log('testing 134');
+ console.log(this.permissionsForm);
+ }
+
+ public goBack(){
+ this.router.navigate(['/cases']);
+ }
+}
diff --git a/src/cases/containers/case-share/case-share.component.ts b/src/cases/containers/case-share/case-share.component.ts
index 0b8ad0acb..0291fb076 100644
--- a/src/cases/containers/case-share/case-share.component.ts
+++ b/src/cases/containers/case-share/case-share.component.ts
@@ -40,6 +40,8 @@ export class CaseShareComponent implements OnInit {
public ngOnInit(): void {
this.routerState$ = this.store.pipe(select(getRouterState));
this.routerState$.subscribe((router) => {
+ console.log('router.state');
+ console.log(router.state);
this.init = router.state.queryParams.init;
this.pageType = router.state.queryParams.pageType;
// Set backLink, fnTitle, title, confirmLink, addUserLabel, and showRemoveUsers depending on whether navigation
@@ -49,10 +51,17 @@ export class CaseShareComponent implements OnInit {
this.backLink = '/cases';
this.confirmLink = `${url}/case-share-confirm/${this.pageType}`;
- this.fnTitle = 'Action a case';
- this.title = 'Manage case assignments';
- this.addUserLabel = 'Add people to share cases to the selected cases';
- this.showRemoveUsers = true;
+ if (this.pageType === 'unassigned-cases') {
+ this.fnTitle = 'Share a case';
+ this.title = 'Add recipient';
+ this.addUserLabel = 'Enter email address';
+ this.showRemoveUsers = false;
+ } else if (this.pageType === 'assigned-cases') {
+ this.fnTitle = 'Manage case sharing';
+ this.title = 'Manage shared access to a case';
+ this.addUserLabel = 'Add people to share access to the selected cases';
+ this.showRemoveUsers = true;
+ }
this.shareCases$ = this.pageType === CaaCasesPageType.UnassignedCases
? this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState))
diff --git a/src/cases/containers/cases/cases.component.html b/src/cases/containers/cases/cases.component.html
index 8712d3cc6..d116fce3d 100644
--- a/src/cases/containers/cases/cases.component.html
+++ b/src/cases/containers/cases/cases.component.html
@@ -42,13 +42,28 @@
(emitErrorMessages)="onErrorMessages($event)"
>
+
+
+
+ !
+
+ Warning
+ The tabs below list all of your organisation's cases which are not assigned to any users. You can assign
+ cases to users by selecting 'Manage cases'.
+
+ You do not need to assigned cases to users if they have 'Access all cases in the organisation' enabled for
+ that case type.
+
+
+
+
{
+ caaCasesFilterValue: this.selectedFilterValue
+ }));
+
+ this.caaCasesStore.pipe(
+ select(caaCasesStore.getAllCaseTypes),
+ take(1)
+ ).subscribe((items) => {
+ console.log(items);
this.allCaseTypes = items;
if (this.allCaseTypes && this.allCaseTypes.length > 0) {
this.selectedCaseType = this.allCaseTypes[0].text;
@@ -120,6 +127,7 @@ export class CasesComponent implements OnInit {
public loadCaseData(){
if (this.allCaseTypes && this.allCaseTypes.length > 0) {
if (this.caaCasesPageType === CaaCasesPageType.AssignedCases) {
+ console.log('loadCaseData: loadAssignedCases');
this.caaCasesStore.dispatch(new caaCasesStore.LoadAssignedCases({
caseType: this.selectedCaseType,
pageNo: this.currentPageNo,
@@ -163,15 +171,18 @@ export class CasesComponent implements OnInit {
}
if (selectedFilter.filterType === CaaCasesFilterType.AllAssignedCases) {
// dispatch action to load all cases
- this.caseResultsTableShareButtonText = 'Manage cases';
+ this.caaCasesPageType = CaaCasesPageType.AssignedCases;
+ this.caseResultsTableShareButtonText = 'Manage case sharing';
}
if (selectedFilter.filterType === CaaCasesFilterType.NewCasesToAccept) {
// dispatch action to load new cases to accept
+ this.caaCasesPageType = CaaCasesPageType.UnassignedCases;
this.caseResultsTableShareButtonText = 'Accept cases';
}
if (selectedFilter.filterType === CaaCasesFilterType.UnassignedCases) {
// dispatch action to load unassigned cases
- this.caseResultsTableShareButtonText = 'Manage cases';
+ this.caaCasesPageType = CaaCasesPageType.UnassignedCases;
+ this.caseResultsTableShareButtonText = 'Share Case';
}
this.loadCaseTypes();
}
@@ -193,7 +204,7 @@ export class CasesComponent implements OnInit {
}
public retrieveSessionState(): void {
- this.sessionStateValue = this.service.retrieveSessionState(this.caaCasesPageType);
+ this.sessionStateValue = this.service.retrieveSessionState(this.sessionStateKey);
if (this.sessionStateValue) {
this.toggleFilterSection();
}
@@ -201,7 +212,7 @@ export class CasesComponent implements OnInit {
public storeSessionState(selectedFilter: SelectedCaseFilter): void {
const sessionStateToUpdate: CaaCasesSessionState = {
- key: this.caaCasesPageType,
+ key: this.sessionStateKey,
value: {
filterType: selectedFilter.filterType,
caseReferenceNumber: selectedFilter.filterType === CaaCasesFilterType.CaseReferenceNumber ? selectedFilter.filterValue : null,
@@ -230,11 +241,23 @@ export class CasesComponent implements OnInit {
}
public onPageChanged(pageNo: number): void {
+ console.log('is the page being changed somehow?');
this.currentPageNo = pageNo;
this.loadCaseData();
}
- onShareButtonClicked($event: void) {
+ onShareButtonClicked($event: string) {
+ console.log(this.selectedFilterType);
+ let newCasesEnabled = false;
+ let groupAccessEnabled = false;
+ //match the caseType ($event) to any in the allCaseTypes
+ this.allCaseTypes.forEach((caseType) => {
+ const { text, caseConfig } = caseType;
+ if (text === $event && caseConfig) {
+ newCasesEnabled = caseConfig.new_cases;
+ groupAccessEnabled = caseConfig.group_access;
+ }
+ });
// load cases types based on filter and value
if (this.selectedFilterType === CaaCasesFilterType.CaseReferenceNumber) {
// TODO: need to handle the `new_case` flag
@@ -261,6 +284,13 @@ export class CasesComponent implements OnInit {
// dispatch action to load new cases to accept
// if group_access is enabled then go to accept cases page
// else go to add recipient
+ if (groupAccessEnabled) {
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareUnassignedCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType),
+ group_access: true
+ }
+ ));
+ }
}
if (this.selectedFilterType === CaaCasesFilterType.UnassignedCases) {
this.caaCasesStore.dispatch(new caaCasesStore.AddShareUnassignedCases({
diff --git a/src/cases/containers/index.ts b/src/cases/containers/index.ts
index eb154eea7..868301a7b 100644
--- a/src/cases/containers/index.ts
+++ b/src/cases/containers/index.ts
@@ -1,3 +1,4 @@
+import { AcceptCasesComponent } from './accept-cases/accept-cases.component';
import { CaseShareCompleteComponent } from './case-share-complete/case-share-complete.component';
import { CaseShareConfirmComponent } from './case-share-confirm/case-share-confirm.component';
import { CaseShareComponent } from './case-share/case-share.component';
@@ -7,7 +8,8 @@ export const containers: any[] = [
CaseShareComponent,
CaseShareConfirmComponent,
CaseShareCompleteComponent,
- CasesComponent
+ CasesComponent,
+ AcceptCasesComponent
];
export * from './case-share-complete/case-share-complete.component';
diff --git a/src/cases/models/caa-cases.enum.ts b/src/cases/models/caa-cases.enum.ts
index edd89f7ad..91599da6b 100644
--- a/src/cases/models/caa-cases.enum.ts
+++ b/src/cases/models/caa-cases.enum.ts
@@ -1,6 +1,7 @@
export enum CaaCasesPageType {
AssignedCases = 'assigned-cases',
- UnassignedCases = 'unassigned-cases'
+ UnassignedCases = 'unassigned-cases',
+ NewCases = 'new-cases'
}
export enum CaaCasesShowHideFilterButtonText {
@@ -37,6 +38,7 @@ export enum CaaCasesFilterErrorMessage {
export enum CaaCasesNoDataMessage {
NoAssignedCases = 'There are no assigned cases available to be shared.',
NoUnassignedCases = 'There are no unassigned cases available to be shared.',
- AssignedCasesFilterMessage = 'Try again using a different case reference or assignee.',
- UnassignedCasesFilterMessage = 'Try again using a different case reference.'
+ CasesFilterMessage = 'There are no assigned cases associated with this user to be shared.',
+ NoNewCases = 'There are no new cases to be shared.',
+ NoCaseIdMatches = 'There are no cases with case reference to be shared.'
}
diff --git a/src/cases/models/caa-cases.model.ts b/src/cases/models/caa-cases.model.ts
index c35509430..a6389f5bd 100644
--- a/src/cases/models/caa-cases.model.ts
+++ b/src/cases/models/caa-cases.model.ts
@@ -19,6 +19,10 @@ export interface CaseTypesResultsResponse {
export interface CaseTypesResults {
total: number;
case_type_id: string;
+ caseConfig: {
+ new_cases: boolean;
+ group_access: boolean;
+ }
}
export interface SelectedCases {
diff --git a/src/cases/store/actions/share-case.action.ts b/src/cases/store/actions/share-case.action.ts
index 4cd394632..39938045c 100644
--- a/src/cases/store/actions/share-case.action.ts
+++ b/src/cases/store/actions/share-case.action.ts
@@ -110,7 +110,9 @@ export class AddShareUnassignedCases implements Action {
path?: any[];
query?: object;
extras?: NavigationExtras;
- sharedCases: SharedCase[]
+ sharedCases: SharedCase[],
+ group_access?: boolean,
+ new_cases?: boolean
}) {}
}
diff --git a/src/cases/store/effects/caa-cases.effects.ts b/src/cases/store/effects/caa-cases.effects.ts
index 337104295..6bc1e8f2d 100644
--- a/src/cases/store/effects/caa-cases.effects.ts
+++ b/src/cases/store/effects/caa-cases.effects.ts
@@ -23,6 +23,7 @@ export class CaaCasesEffects {
ofType(fromCaaActions.LOAD_ASSIGNED_CASES),
switchMap((action: fromCaaActions.LoadAssignedCases) => {
const payload = action.payload;
+ console.log('load assigned cases');
return this.caaCasesService.getCaaCases(payload.caseType, payload.pageNo, payload.pageSize, CaaCasesPageType.AssignedCases, payload.caaCasesFilterType, payload.caaCasesFilterValue).pipe(
map((caaCases) => new fromCaaActions.LoadAssignedCasesSuccess(caaCases)),
catchError((error) => CaaCasesEffects.handleError(error, this.loggerService, CaaCasesPageType.AssignedCases))
diff --git a/src/cases/store/effects/share-case.effects.ts b/src/cases/store/effects/share-case.effects.ts
index b5e3c6e68..e8aaa7bfe 100644
--- a/src/cases/store/effects/share-case.effects.ts
+++ b/src/cases/store/effects/share-case.effects.ts
@@ -41,7 +41,7 @@ export class ShareCaseEffects {
map((action: shareCaseActions.AddShareUnassignedCases) => action.payload),
map((newCases) => {
return new shareCaseActions.AddShareUnassignedCaseGo({
- path: [`${this.router.url}/case-share`],
+ path: this.getPathFromCaseConfig(newCases.group_access, newCases.new_cases),
sharedCases: newCases.sharedCases
});
})
@@ -145,4 +145,11 @@ export class ShareCaseEffects {
})
)
);
+
+ public getPathFromCaseConfig(groupAccess?: boolean, newCases?: boolean) {
+ if (groupAccess){
+ return [`${this.router.url}/accept-cases`];
+ }
+ return [`${this.router.url}/case-share`];
+ }
}
diff --git a/src/cases/util/caa-cases.util.ts b/src/cases/util/caa-cases.util.ts
index c8ef2a00e..921b1444b 100644
--- a/src/cases/util/caa-cases.util.ts
+++ b/src/cases/util/caa-cases.util.ts
@@ -12,7 +12,8 @@ export class CaaCasesUtil {
text: caseType.case_type_id,
href: caseType.case_type_id,
active: false,
- total: caseType.total
+ total: caseType.total,
+ caseConfig: caseType.caseConfig
});
}
});
From 898835d119efe8e3c9cdd04404d9e1726885a023 Mon Sep 17 00:00:00 2001
From: Josh
Date: Fri, 31 Jan 2025 11:26:44 +0000
Subject: [PATCH 12/44] fix loading spinner so it sticks to scrolled page
---
src/shared/modules/loader/components/loader.component.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/modules/loader/components/loader.component.scss b/src/shared/modules/loader/components/loader.component.scss
index 58469eb94..2cfe5d83f 100644
--- a/src/shared/modules/loader/components/loader.component.scss
+++ b/src/shared/modules/loader/components/loader.component.scss
@@ -4,7 +4,7 @@
}
.overlay {
- position: absolute;
+ position: fixed;
z-index: 1002;
background-color: rgba(255, 255, 255, 0.5);
width: 100%;
From b4813b8b3fd0d6b0c3b7d27ede74afa84a1da5be Mon Sep 17 00:00:00 2001
From: Josh
Date: Fri, 31 Jan 2025 11:39:04 +0000
Subject: [PATCH 13/44] Update store to support all types, optimise page load,
add dynamic path to accept cases page, update confirm screen to support
new-cases, add temp new endpoint for new-cases
---
api/caaCases/caaCases.util.ts | 13 +-
api/caaCases/enums/index.ts | 1 +
api/caaCases/index.ts | 4 +-
api/caseshare/index.ts | 7 +
api/caseshare/real-api.ts | 11 +
api/caseshare/routes.ts | 1 +
.../cases-results-table.component.html | 2 +-
.../cases-results-table.component.ts | 17 --
.../accept-cases/accept-cases.component.html | 2 +-
.../accept-cases/accept-cases.component.ts | 29 ++-
.../case-share-complete.component.html | 12 +-
.../case-share-complete.component.ts | 25 +--
.../case-share-confirm.component.html | 3 +-
.../case-share-confirm.component.ts | 14 +-
.../case-share/case-share.component.ts | 86 ++++----
src/cases/containers/cases/cases.component.ts | 184 +++++++++--------
src/cases/store/actions/caa-cases.actions.ts | 47 ++---
src/cases/store/actions/index.ts | 18 +-
src/cases/store/actions/share-case.action.ts | 191 +++++-------------
src/cases/store/effects/caa-cases.effects.ts | 31 +--
src/cases/store/effects/share-case.effects.ts | 103 +++-------
src/cases/store/reducers/caa-cases.reducer.ts | 30 +--
.../store/reducers/share-case.reducer.ts | 164 +++------------
.../store/selectors/caa-cases.selector.ts | 27 +--
.../store/selectors/share-case.selector.ts | 9 +-
25 files changed, 365 insertions(+), 666 deletions(-)
diff --git a/api/caaCases/caaCases.util.ts b/api/caaCases/caaCases.util.ts
index 816be06c0..e5499bfff 100644
--- a/api/caaCases/caaCases.util.ts
+++ b/api/caaCases/caaCases.util.ts
@@ -1,5 +1,5 @@
import { caseAssignment, caseId, caseTypeStr } from './caaCases.constants';
-import { CaaCasesPageType } from './enums';
+import { CaaCasesFilterType, CaaCasesPageType } from './enums';
import { CaaCases, CaseHeader, CcdCase, CcdCaseData, CcdColumnConfig } from './interfaces';
export function getApiPath(ccdPath: string, caseTypeId: string) {
@@ -17,11 +17,15 @@ export function mapCcdCases(caseType: string, ccdCase: CcdCase): CaaCases {
};
}
-export function getRequestBody(organisationID: string, pageNo: number, pageSize: number, caaCasesPageType: string, caaCasesFilterValue?: string | string[]) {
+export function getRequestBody(organisationID: string, pageNo: number, pageSize: number, caaCasesPageType: string, caseFilterType: string, caaCasesFilterValue?: string | string[]) {
const organisationAssignedUsersKey = `supplementary_data.orgs_assigned_users.${organisationID}`;
+ const newCasesKey = `supplementary_data.new_case.${organisationID}`;
const reference = 'reference.keyword';
const caseReferenceFilter: any[] = [];
+ if (caseFilterType === CaaCasesFilterType.NewCasesToAccept){
+ caaCasesPageType = CaaCasesPageType.NewCasesToAccept;
+ }
if (caaCasesFilterValue) {
if (Array.isArray(caaCasesFilterValue)) {
caaCasesFilterValue.forEach((caseReference) => {
@@ -56,6 +60,11 @@ export function getRequestBody(organisationID: string, pageNo: number, pageSize:
{ range: { [organisationAssignedUsersKey]: { gt: 0 } } }
]
})
+ // ...(caaCasesPageType === CaaCasesFilterType.NewCasesToAccept && {
+ // must: [
+ // { range: { [newCasesKey]: { gt: 0 } } }
+ // ]
+ // })
}
},
{
diff --git a/api/caaCases/enums/index.ts b/api/caaCases/enums/index.ts
index 63c22a790..80ff93562 100644
--- a/api/caaCases/enums/index.ts
+++ b/api/caaCases/enums/index.ts
@@ -1,6 +1,7 @@
export enum CaaCasesPageType {
AssignedCases = 'assigned-cases',
UnassignedCases = 'unassigned-cases',
+ NewCasesToAccept = 'new-cases-to-accept',
}
export enum CaaCasesFilterType {
diff --git a/api/caaCases/index.ts b/api/caaCases/index.ts
index b9127d45c..c498f62bc 100644
--- a/api/caaCases/index.ts
+++ b/api/caaCases/index.ts
@@ -16,7 +16,7 @@ export async function handleCaaCases(req: EnhancedRequest, res: Response, next:
const fromNo: number = page * size;
let caaCasesFilterValue: string | string[] = req.query.caaCasesFilterValue as string;
-
+ const caseFilterType = req.query.caaCasesFilterType as string;
try {
if (caaCasesFilterType === CaaCasesFilterType.AssigneeName) {
const roleAssignments = await handleRoleAssignments(req, next);
@@ -35,7 +35,7 @@ export async function handleCaaCases(req: EnhancedRequest, res: Response, next:
res.status(errReport.apiStatusCode).send(errReport);
}
- const payload = getRequestBody(orgId, fromNo, size, caaCasesPageType, caaCasesFilterValue);
+ const payload = getRequestBody(orgId, fromNo, size, caaCasesPageType, caseFilterType, caaCasesFilterValue);
const response = await req.http.post(path, payload);
const caaCases = mapCcdCases(caseTypeId, response.data);
diff --git a/api/caseshare/index.ts b/api/caseshare/index.ts
index da259eb68..3f095986d 100644
--- a/api/caseshare/index.ts
+++ b/api/caseshare/index.ts
@@ -35,3 +35,10 @@ export async function assignCasesToUsers(req: EnhancedRequest, res: Response) {
}
return realAPI.assignCases(req, res);
}
+
+export async function acceptNewCasesForOrg(req: EnhancedRequest, res: Response) {
+ // if (stub) {
+ // return stubAPI.acceptNewCases(req, res);
+ // }
+ return realAPI.acceptNewCases(req, res);
+}
diff --git a/api/caseshare/real-api.ts b/api/caseshare/real-api.ts
index 8a87d9ed2..ed7cc328b 100644
--- a/api/caseshare/real-api.ts
+++ b/api/caseshare/real-api.ts
@@ -47,6 +47,17 @@ export async function getCases(req: EnhancedRequest, res: Response, next: NextFu
}
}
+export async function acceptNewCases(req: EnhancedRequest, res: Response): Promise {
+ const path = `${ccdUrl}/case-users`;
+ try {
+ const casesToAccept = req.body.casesToAccept;
+ const { status, data }: {status: number, data: any} = await handlePost(path, casesToAccept, req);
+ return res.status(status).send(data);
+ } catch (err) {
+ res.status(500);
+ }
+}
+
export async function assignCases(req: EnhancedRequest, res: Response): Promise {
const shareCases: SharedCase[] = req.body.sharedCases.slice();
diff --git a/api/caseshare/routes.ts b/api/caseshare/routes.ts
index 0d0675f64..765947edd 100644
--- a/api/caseshare/routes.ts
+++ b/api/caseshare/routes.ts
@@ -6,3 +6,4 @@ router.get('/users', restAPI.getUsers);
router.get('/cases', restAPI.getCases);
router.post('/case-assignments', restAPI.assignCasesToUsers);
router.get('/case-assignments', restAPI.getCases);
+router.post('/case-users', restAPI.acceptNewCasesForOrg);
diff --git a/src/cases/components/cases-results-table/cases-results-table.component.html b/src/cases/components/cases-results-table/cases-results-table.component.html
index 80bbc3f0d..a64212401 100644
--- a/src/cases/components/cases-results-table/cases-results-table.component.html
+++ b/src/cases/components/cases-results-table/cases-results-table.component.html
@@ -59,7 +59,7 @@
-{{navItems}}
+
{{noCasesFoundMessage}}
diff --git a/src/cases/components/cases-results-table/cases-results-table.component.ts b/src/cases/components/cases-results-table/cases-results-table.component.ts
index 9b2d7c8b8..d52261f38 100644
--- a/src/cases/components/cases-results-table/cases-results-table.component.ts
+++ b/src/cases/components/cases-results-table/cases-results-table.component.ts
@@ -74,7 +74,6 @@ export class CasesResultsTableComponent {
}
public tabChanged(event: { tab: { textLabel: string }}): void {
- console.log(event);
this.totalCases = this.navItems.find((data) => data.text === event.tab.textLabel)
? this.navItems.find((data) => data.text === event.tab.textLabel).total
: 0;
@@ -122,19 +121,10 @@ export class CasesResultsTableComponent {
}
public onShareButtonClicked(): void {
- // this.store.dispatch(new fromStore.AddShareUnassignedCases({
- // sharedCases: converters.toShareCaseConverter(this.selectedUnassignedCases, this.currentCaseType)
- // }));
- // TODO: emit this action
this.shareButtonClicked.emit(this.currentCaseType);
}
private fixCurrentTab(items: any): void {
- // TESTING: Add another tab to test case specific navigation
- console.log(`test items: ${items}`);
- if (items.length > 0){
- items = [...items, { text: 'Asylum', href: 'Asylum', active: false, total: 3 }];
- }
this.navItems = items;
if (items && items.length > 0) {
this.totalCases = items[0].total ? items[0].total : 0;
@@ -147,13 +137,6 @@ export class CasesResultsTableComponent {
private setTabItems(tabName: string, fromTabChangedEvent?: boolean): void {
this.resetPaginationParameters();
- // if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases) {
- // this.store.pipe(select(fromStore.getAllUnassignedCases));
- // } else {
- // this.store.pipe(select(fromStore.getAllAssignedCases));
- // }
- // this.shareAssignedCases$ = this.store.pipe(select(fromStore.getShareAssignedCaseListState));
- // this.shareUnassignedCases$ = this.store.pipe(select(fromStore.getShareUnassignedCaseListState));
this.currentCaseType = tabName;
if (!fromTabChangedEvent && this.tabGroup) {
this.tabGroup.selectedIndex = 0;
diff --git a/src/cases/containers/accept-cases/accept-cases.component.html b/src/cases/containers/accept-cases/accept-cases.component.html
index bdd79cf1f..bff8be93e 100644
--- a/src/cases/containers/accept-cases/accept-cases.component.html
+++ b/src/cases/containers/accept-cases/accept-cases.component.html
@@ -1,4 +1,4 @@
-Back
+Back
{{
(selectedOrganisation$ | async)?.name
diff --git a/src/cases/containers/accept-cases/accept-cases.component.ts b/src/cases/containers/accept-cases/accept-cases.component.ts
index aa317909f..f271d6df6 100644
--- a/src/cases/containers/accept-cases/accept-cases.component.ts
+++ b/src/cases/containers/accept-cases/accept-cases.component.ts
@@ -1,11 +1,11 @@
import { Component, OnInit } from '@angular/core';
import { Store, select } from '@ngrx/store';
-
import * as organisationStore from '../../../organisation/store';
import { OrganisationDetails } from 'src/models/organisation.model';
import { Observable } from 'rxjs';
-import { FormBuilder, FormControl } from '@angular/forms';
-import { Router } from '@angular/router';
+import { FormBuilder } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+import { CaaCasesPageType } from '../../models/caa-cases.enum';
@Component({
selector: 'app-exui-case-share',
@@ -13,13 +13,17 @@ import { Router } from '@angular/router';
styleUrls: ['./accept-cases.component.scss']
})
export class AcceptCasesComponent implements OnInit {
- permissionsForm: any;
+ public permissionsForm: any;
public selectedOrganisation$: Observable;
- pageTitle: string;
+ public pageTitle: string;
+
+ private readonly caseShare = '/cases/case-share';
+ private readonly caseShareConfirmUrl = '/cases/case-share-confirm/new-cases';
constructor(
private readonly organisationStore: Store,
- private fb: FormBuilder,
+ private readonly route: ActivatedRoute,
+ private readonly fb: FormBuilder,
private readonly router: Router){
}
@@ -27,16 +31,21 @@ export class AcceptCasesComponent implements OnInit {
// Load selected organisation details from store
this.organisationStore.dispatch(new organisationStore.LoadOrganisation());
this.selectedOrganisation$ = this.organisationStore.pipe(select(organisationStore.getOrganisationSel));
- this.pageTitle = 'Accept cases';
-
+ const caseType = this.route.snapshot.queryParams.caseType;
+ this.pageTitle = `Accept ${caseType} cases`;
this.permissionsForm = this.fb.group({
assignmentType: ['notAssigning']
});
}
public continue(){
- console.log('testing 134');
- console.log(this.permissionsForm);
+ if (this.permissionsForm.value.assignmentType === 'assigning'){
+ const queryParams = { init: true, pageType: 'unassigned-cases', caseAccept: true };
+ this.router.navigate([this.caseShare], { queryParams });
+ } else {
+ const queryParams = { caseAccept: true, pageType: CaaCasesPageType.NewCases };
+ this.router.navigate([this.caseShareConfirmUrl], { queryParams });
+ }
}
public goBack(){
diff --git a/src/cases/containers/case-share-complete/case-share-complete.component.html b/src/cases/containers/case-share-complete/case-share-complete.component.html
index e31e795c2..f239d34f9 100644
--- a/src/cases/containers/case-share-complete/case-share-complete.component.html
+++ b/src/cases/containers/case-share-complete/case-share-complete.component.html
@@ -9,13 +9,15 @@ What happens next
- The people you added can now access and update the selected cases from their case list.
- If you removed someone from a case, they cannot access the case anymore.
- If you've shared one or more cases, your colleagues will now be able to access them from their case list.
+
+ The people you added can now access and update the selected cases from their case list.
+ If you removed someone from a case, they cannot access the case anymore.
+ If you've shared one or more cases, your colleagues will now be able to access them from their case list.
+ some text about new cases stuff.
+
To continue managing case sharing for other users or case types:
-
Go to assigned cases list
-
Go to unassigned cases list
+
Go to cases list
diff --git a/src/cases/containers/case-share-complete/case-share-complete.component.ts b/src/cases/containers/case-share-complete/case-share-complete.component.ts
index d70eca271..6a08083ae 100644
--- a/src/cases/containers/case-share-complete/case-share-complete.component.ts
+++ b/src/cases/containers/case-share-complete/case-share-complete.component.ts
@@ -4,7 +4,6 @@ import { FeatureToggleService } from '@hmcts/rpx-xui-common-lib';
import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
import { select, Store } from '@ngrx/store';
import { Observable } from 'rxjs';
-import { CaaCasesPageType } from '../../models/caa-cases.enum';
import * as fromCasesFeature from '../../store';
import * as fromCaseList from '../../store/reducers';
@@ -23,7 +22,7 @@ export class CaseShareCompleteComponent implements OnInit, OnDestroy {
public isLoading: boolean;
public completeScreenMode: string;
public removeUserFromCaseToggleOn$: Observable;
- public isFromAssignedCasesRoute: boolean = false;
+ public confirmPageType: string;
constructor(
private readonly store: Store,
@@ -38,18 +37,11 @@ export class CaseShareCompleteComponent implements OnInit, OnDestroy {
this.shareCaseState$ = this.store.pipe(select(fromCasesFeature.getCaseShareState));
this.shareCaseState$.subscribe((state) => this.isLoading = state.loading);
- this.shareCases$ = this.pageType === CaaCasesPageType.UnassignedCases
- ? this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState))
- : this.store.pipe(select(fromCasesFeature.getShareAssignedCaseListState));
+ this.shareCases$ = this.store.pipe(select(fromCasesFeature.getShareCaseListState));
this.shareCases$.subscribe((shareCases) => this.shareCases = shareCases);
- if (this.pageType === CaaCasesPageType.UnassignedCases) {
- this.store.dispatch(new fromCasesFeature.AssignUsersToUnassignedCase(this.shareCases));
- this.newShareCases$ = this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState));
- } else {
- this.store.dispatch(new fromCasesFeature.AssignUsersToAssignedCase(this.shareCases));
- this.newShareCases$ = this.store.pipe(select(fromCasesFeature.getShareAssignedCaseListState));
- }
+ // this.store.dispatch(new fromCasesFeature.AssignUsersToCase(this.shareCases));
+ this.newShareCases$ = this.store.pipe(select(fromCasesFeature.getShareCaseListState));
this.newShareCases$.subscribe((shareCases) => {
this.completeScreenMode = this.checkIfIncomplete(shareCases);
@@ -57,16 +49,13 @@ export class CaseShareCompleteComponent implements OnInit, OnDestroy {
});
this.removeUserFromCaseToggleOn$ = this.featureToggleService.getValue('remove-user-from-case-mo', false);
- this.isFromAssignedCasesRoute = this.router.url.startsWith('/assigned-cases');
+
+ this.completeScreenMode = 'COMPLETE';
}
public ngOnDestroy(): void {
if (this.completeScreenMode === 'COMPLETE') {
- if (this.pageType === CaaCasesPageType.UnassignedCases) {
- this.store.dispatch(new fromCasesFeature.ResetUnassignedCaseSelection());
- } else {
- this.store.dispatch(new fromCasesFeature.ResetAssignedCaseSelection());
- }
+ this.store.dispatch(new fromCasesFeature.ResetCaseSelection());
}
}
diff --git a/src/cases/containers/case-share-confirm/case-share-confirm.component.html b/src/cases/containers/case-share-confirm/case-share-confirm.component.html
index 16f0afca5..26fa87ef9 100644
--- a/src/cases/containers/case-share-confirm/case-share-confirm.component.html
+++ b/src/cases/containers/case-share-confirm/case-share-confirm.component.html
@@ -5,6 +5,7 @@
+ [completeLink]="completeLink"
+ [acceptCases]="acceptCases">
diff --git a/src/cases/containers/case-share-confirm/case-share-confirm.component.ts b/src/cases/containers/case-share-confirm/case-share-confirm.component.ts
index 8feae1f13..290f048d4 100644
--- a/src/cases/containers/case-share-confirm/case-share-confirm.component.ts
+++ b/src/cases/containers/case-share-confirm/case-share-confirm.component.ts
@@ -21,23 +21,27 @@ export class CaseShareConfirmComponent implements OnInit {
public backLink: string;
public changeLink: string;
public completeLink: string;
+ public acceptCases: boolean = false;
+ private readonly acceptLinks = '/cases/accept-cases';
+ private readonly caseShareLinks = '/cases/case-share';
constructor(private readonly store: Store,
private readonly route: ActivatedRoute,
private readonly router: Router) {
this.url = this.router?.url;
this.pageType = this.route.snapshot.params.pageType;
+ this.acceptCases = this.route.snapshot.queryParams.caseAccept;
}
public ngOnInit(): void {
this.fnTitle = 'Manage case assignments';
- this.backLink = '/cases/case-share';
- this.changeLink = '/cases/case-share';
+ console.log(this.route.snapshot.queryParams);
+ this.backLink = this.acceptCases ? this.acceptLinks : this.caseShareLinks;
+ this.changeLink = this.acceptCases ? this.acceptLinks : this.caseShareLinks;
this.completeLink = `/cases/case-share-complete/${this.pageType}`;
- this.shareCases$ = this.pageType === CaaCasesPageType.UnassignedCases
- ? this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState))
- : this.store.pipe(select(fromCasesFeature.getShareAssignedCaseListState));
+ this.shareCases$ = this.store.pipe(select(fromCasesFeature.getShareCaseListState));
this.shareCases$.subscribe((shareCases) => this.shareCases = shareCases);
+ console.log('shared csese', this.shareCases);
}
}
diff --git a/src/cases/containers/case-share/case-share.component.ts b/src/cases/containers/case-share/case-share.component.ts
index 0291fb076..e8e0c0beb 100644
--- a/src/cases/containers/case-share/case-share.component.ts
+++ b/src/cases/containers/case-share/case-share.component.ts
@@ -1,15 +1,14 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnDestroy, OnInit } from '@angular/core';
import { FeatureToggleService } from '@hmcts/rpx-xui-common-lib';
import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.model';
import { UserDetails } from '@hmcts/rpx-xui-common-lib/lib/models/user-details.model';
import { RouterReducerState } from '@ngrx/router-store';
import { select, Store } from '@ngrx/store';
import { initAll } from 'govuk-frontend';
-import { Observable } from 'rxjs';
+import { Observable, Subject, takeUntil } from 'rxjs';
import { getRouterState, RouterStateUrl } from '../../../app/store/reducers';
-import { CaaCasesPageType } from '../../models/caa-cases.enum';
import * as fromCasesFeature from '../../store';
-import { LoadShareAssignedCases, LoadShareUnassignedCases, LoadUserFromOrgForCase } from '../../store/actions';
+import { LoadShareCases, LoadUserFromOrgForCase } from '../../store/actions';
import * as fromCaseList from '../../store/reducers';
@Component({
@@ -17,7 +16,8 @@ import * as fromCaseList from '../../store/reducers';
templateUrl: './case-share.component.html',
styleUrls: ['./case-share.component.scss']
})
-export class CaseShareComponent implements OnInit {
+export class CaseShareComponent implements OnInit, OnDestroy {
+ private destroy$ = new Subject();
public routerState$: Observable>;
public init: boolean;
public pageType: string;
@@ -38,67 +38,63 @@ export class CaseShareComponent implements OnInit {
) {}
public ngOnInit(): void {
+ console.log('initid the case share comp');
this.routerState$ = this.store.pipe(select(getRouterState));
- this.routerState$.subscribe((router) => {
- console.log('router.state');
- console.log(router.state);
+ this.routerState$.pipe(takeUntil(this.destroy$)).subscribe((router) => {
this.init = router.state.queryParams.init;
this.pageType = router.state.queryParams.pageType;
- // Set backLink, fnTitle, title, confirmLink, addUserLabel, and showRemoveUsers depending on whether navigation
- // is via the Unassigned Cases or Assigned Cases page
+ const cameFromAcceptCases = router.state.queryParams.caseAccept;
const url = router.state.url.substring(0, router.state.url.indexOf('/', 1));
- // Set backLink and confirmLink only if the URL is either "/unassigned-cases" or "/assigned-cases"
- this.backLink = '/cases';
- this.confirmLink = `${url}/case-share-confirm/${this.pageType}`;
+ if (cameFromAcceptCases) {
+ this.backLink = '/cases/accept-cases';
+ } else {
+ this.backLink = '/cases';
+ }
+ this.confirmLink = `${url}/case-share-confirm/${cameFromAcceptCases ? 'new-cases' : this.pageType}`;
- if (this.pageType === 'unassigned-cases') {
- this.fnTitle = 'Share a case';
- this.title = 'Add recipient';
- this.addUserLabel = 'Enter email address';
- this.showRemoveUsers = false;
- } else if (this.pageType === 'assigned-cases') {
- this.fnTitle = 'Manage case sharing';
- this.title = 'Manage shared access to a case';
- this.addUserLabel = 'Add people to share access to the selected cases';
- this.showRemoveUsers = true;
+ switch (this.pageType) {
+ case 'unassigned-cases':
+ this.fnTitle = 'Share a case';
+ this.title = 'Add recipient';
+ this.addUserLabel = 'Enter email address';
+ this.showRemoveUsers = false;
+ break;
+ case 'assigned-cases':
+ this.fnTitle = 'Manage case sharing';
+ this.title = 'Manage shared access to a case';
+ this.addUserLabel = 'Add people to share access to the selected cases';
+ this.showRemoveUsers = true;
+ break;
}
- this.shareCases$ = this.pageType === CaaCasesPageType.UnassignedCases
- ? this.store.pipe(select(fromCasesFeature.getShareUnassignedCaseListState))
- : this.store.pipe(select(fromCasesFeature.getShareAssignedCaseListState));
- this.shareCases$.subscribe((shareCases) => this.shareCases = shareCases);
+ this.shareCases$ = this.store.pipe(select(fromCasesFeature.getShareCaseListState));
+ this.shareCases$.pipe(takeUntil(this.destroy$)).subscribe((shareCases) => this.shareCases = shareCases);
});
this.orgUsers$ = this.store.pipe(select(fromCasesFeature.getOrganisationUsersState));
+ this.orgUsers$.pipe(takeUntil(this.destroy$)).subscribe();
+
if (this.init) {
- // call api to retrieve case share users
- if (this.pageType === CaaCasesPageType.UnassignedCases) {
- this.store.dispatch(new LoadShareUnassignedCases(this.shareCases));
- } else {
- this.store.dispatch(new LoadShareAssignedCases(this.shareCases));
- }
- // call api to retrieve users in the same organisation
+ this.store.dispatch(new LoadShareCases(this.shareCases));
this.store.dispatch(new LoadUserFromOrgForCase());
}
+
this.removeUserFromCaseToggleOn$ = this.featureToggleService.getValue('remove-user-from-case-mo', false);
+ this.removeUserFromCaseToggleOn$.pipe(takeUntil(this.destroy$)).subscribe();
- // initialize javascript for accordion component to enable open/close button
setTimeout(() => initAll(), 1000);
}
+ public ngOnDestroy(): void {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
+
public deselect($event): void {
- if (this.pageType === CaaCasesPageType.UnassignedCases) {
- this.store.dispatch(new fromCasesFeature.DeleteAShareUnassignedCase($event));
- } else {
- this.store.dispatch(new fromCasesFeature.DeleteAShareAssignedCase($event));
- }
+ this.store.dispatch(new fromCasesFeature.DeleteAShareCase($event));
}
public synchronizeStore($event): void {
- if (this.pageType === CaaCasesPageType.UnassignedCases) {
- this.store.dispatch(new fromCasesFeature.SynchronizeStateToStoreUnassignedCases($event));
- } else {
- this.store.dispatch(new fromCasesFeature.SynchronizeStateToStoreAssignedCases($event));
- }
+ this.store.dispatch(new fromCasesFeature.SynchronizeStateToStoreCases($event));
}
}
diff --git a/src/cases/containers/cases/cases.component.ts b/src/cases/containers/cases/cases.component.ts
index b561d9761..eac5690f5 100644
--- a/src/cases/containers/cases/cases.component.ts
+++ b/src/cases/containers/cases/cases.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { CaaCasesService } from 'src/cases/services';
import * as organisationStore from '../../../organisation/store';
@@ -6,7 +6,7 @@ import * as userStore from '../../../users/store';
import * as caaCasesStore from '../../store';
import { Store, select } from '@ngrx/store';
import { OrganisationDetails } from 'src/models/organisation.model';
-import { Observable, take } from 'rxjs';
+import { Observable, skip, Subject, take, takeUntil } from 'rxjs';
import { Router } from '@angular/router';
import { ErrorMessage } from 'src/shared/models/error-message.model';
import { SubNavigation, User } from '@hmcts/rpx-xui-common-lib';
@@ -37,9 +37,10 @@ export class CasesComponent implements OnInit {
public selectedFilterType: CaaCasesFilterType = CaaCasesFilterType.None;
public selectedFilterValue: string = null;
public selectedCaseType: string;
+ private readonly destroy$ = new Subject();
// for the results table
- public allCaseTypes: SubNavigation[] = [];
+ public allCaseTypes = [];
public currentPageNo: number = 1;
public paginationPageSize: number = 25;
public casesConfig: CaaCases;
@@ -52,18 +53,11 @@ export class CasesComponent implements OnInit {
private readonly organisationStore: Store,
private readonly userStore: Store,
private readonly router: Router,
- private readonly service: CaaCasesService) {
+ private readonly service: CaaCasesService,
+ private cdr: ChangeDetectorRef) {
}
public ngOnInit(): void {
- console.log('oninit...');
- // Retrieve session state to check and pre-populate the previous state if any
- this.retrieveSessionState();
- // if session state is found, then filter component will emit filter values to avoid double query
- if (!this.sessionStateValue) {
- this.loadCaseTypes();
- }
-
// Load selected organisation details from store
this.organisationStore.dispatch(new organisationStore.LoadOrganisation());
this.selectedOrganisation$ = this.organisationStore.pipe(select(organisationStore.getOrganisationSel));
@@ -72,30 +66,54 @@ export class CasesComponent implements OnInit {
this.userStore.dispatch(new userStore.LoadAllUsersNoRoleData());
this.selectedOrganisationUsers$ = this.userStore.pipe(select(userStore.getGetUserList));
- // TODO: clean this up to get all cases
- this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCases)).subscribe((config: CaaCases) => {
- if (config){
+ this.caaCasesStore.pipe(
+ select(caaCasesStore.getAllCases),
+ takeUntil(this.destroy$)
+ ).subscribe((config: CaaCases) => {
+ if (config) {
this.casesConfig = config;
}
});
- this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCaseData)).subscribe((items) => {
- if (items){
+
+ this.caaCasesStore.pipe(
+ select(caaCasesStore.getAllCaseData),
+ takeUntil(this.destroy$)
+ ).subscribe((items) => {
+ if (items) {
this.cases = items;
+ if (this.selectedFilterType === CaaCasesFilterType.CaseReferenceNumber){
+ this.checkShareButtonText();
+ }
}
});
- this.caaCasesStore.pipe(select(caaCasesStore.getAllAssignedCases)).subscribe((config: CaaCases) => {
- if (config){
- this.casesConfig = config;
- }
- });
- this.caaCasesStore.pipe(select(caaCasesStore.getAllAssignedCaseData)).subscribe((items) => {
- if (items){
- this.cases = items;
+ // as this returns an [] as default first call and this could be possible for acutal load we should skip running
+ // the code inside as to not double load when user gets to page
+ this.caaCasesStore.pipe(
+ select(caaCasesStore.getAllCaseTypes),
+ skip(1),
+ takeUntil(this.destroy$)
+ ).subscribe((items) => {
+ this.allCaseTypes = items;
+ if (this.allCaseTypes && this.allCaseTypes.length > 0) {
+ this.selectedCaseType = this.allCaseTypes[0].text;
+ this.loadCaseData();
}
});
+ this.populateFirstLoad();
+ }
- this.casesError$ = this.caaCasesStore.pipe(select(caaCasesStore.getAllUnassignedCasesError));
- this.casesError$ = this.caaCasesStore.pipe(select(caaCasesStore.getAllAssignedCasesError));
+ public ngOnDestroy(): void {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
+
+ public populateFirstLoad() {
+ // Retrieve session state to check and pre-populate the previous state if any
+ this.retrieveSessionState();
+ // if session state is found, then filter component will emit filter values to avoid double query
+ if (!this.sessionStateValue) {
+ this.loadCaseTypes();
+ }
}
/**
@@ -107,18 +125,6 @@ export class CasesComponent implements OnInit {
caaCasesFilterType: this.selectedFilterType,
caaCasesFilterValue: this.selectedFilterValue
}));
-
- this.caaCasesStore.pipe(
- select(caaCasesStore.getAllCaseTypes),
- take(1)
- ).subscribe((items) => {
- console.log(items);
- this.allCaseTypes = items;
- if (this.allCaseTypes && this.allCaseTypes.length > 0) {
- this.selectedCaseType = this.allCaseTypes[0].text;
- this.loadCaseData();
- }
- });
}
/**
@@ -126,30 +132,37 @@ export class CasesComponent implements OnInit {
*/
public loadCaseData(){
if (this.allCaseTypes && this.allCaseTypes.length > 0) {
- if (this.caaCasesPageType === CaaCasesPageType.AssignedCases) {
- console.log('loadCaseData: loadAssignedCases');
- this.caaCasesStore.dispatch(new caaCasesStore.LoadAssignedCases({
- caseType: this.selectedCaseType,
- pageNo: this.currentPageNo,
- pageSize: this.paginationPageSize,
- caaCasesFilterType: this.selectedFilterType,
- caaCasesFilterValue: this.selectedFilterValue
- }));
+ this.caaCasesStore.dispatch(new caaCasesStore.LoadCases({
+ caseType: this.selectedCaseType,
+ pageNo: this.currentPageNo,
+ pageSize: this.paginationPageSize,
+ caaCasesFilterType: this.selectedFilterType,
+ caaCasesPage: this.caaCasesPageType,
+ caaCasesFilterValue: this.selectedFilterValue
+ }));
+ }
+ }
+
+ public checkShareButtonText(): void {
+ if (this.cases && this.allCaseTypes){
+ const caseType = this.cases[0].caseType;
+ let caseConfig;
+ for (const caseTypeItem of this.allCaseTypes) {
+ if (caseTypeItem.text === caseType) {
+ caseConfig = caseTypeItem;
+ break;
+ }
}
- if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases){
- this.caaCasesStore.dispatch(new caaCasesStore.LoadUnassignedCases({
- caseType: this.selectedCaseType,
- pageNo: this.currentPageNo,
- pageSize: this.paginationPageSize,
- caaCasesFilterType: this.selectedFilterType,
- caaCasesFilterValue: this.selectedFilterValue
- }));
+ if (caseConfig.caseConfig.group_access) {
+ this.caseResultsTableShareButtonText = 'Accept cases';
+ } else {
+ this.caseResultsTableShareButtonText = 'Manage case sharing';
}
+ this.cdr.detectChanges();
}
}
public onSelectedFilter(selectedFilter: SelectedCaseFilter): void {
- console.log('Selected filter:', selectedFilter);
this.selectedFilterType = selectedFilter.filterType;
this.selectedFilterValue = selectedFilter.filterValue;
@@ -158,32 +171,30 @@ export class CasesComponent implements OnInit {
} else {
this.storeSessionState(selectedFilter);
}
-
- // load cases types based on filter and value
- if (selectedFilter.filterType === CaaCasesFilterType.CaseReferenceNumber) {
- // dispatch action to load case by ref number
- this.caseResultsTableShareButtonText = 'Accept and assign cases';
+ if (this.selectedFilterType === CaaCasesFilterType.CaseReferenceNumber) {
+ this.caseResultsTableShareButtonText = 'Accept cases';
}
if (selectedFilter.filterType === CaaCasesFilterType.CasesAssignedToAUser) {
// dispatch action to load case by assignee name
- this.caaCasesPageType = CaaCasesPageType.AssignedCases;
this.caseResultsTableShareButtonText = 'Manage cases';
+ this.caaCasesPageType = CaaCasesPageType.AssignedCases;
}
if (selectedFilter.filterType === CaaCasesFilterType.AllAssignedCases) {
// dispatch action to load all cases
- this.caaCasesPageType = CaaCasesPageType.AssignedCases;
this.caseResultsTableShareButtonText = 'Manage case sharing';
+ this.caaCasesPageType = CaaCasesPageType.AssignedCases;
}
if (selectedFilter.filterType === CaaCasesFilterType.NewCasesToAccept) {
// dispatch action to load new cases to accept
- this.caaCasesPageType = CaaCasesPageType.UnassignedCases;
this.caseResultsTableShareButtonText = 'Accept cases';
+ this.caaCasesPageType = CaaCasesPageType.NewCases;
}
if (selectedFilter.filterType === CaaCasesFilterType.UnassignedCases) {
// dispatch action to load unassigned cases
- this.caaCasesPageType = CaaCasesPageType.UnassignedCases;
this.caseResultsTableShareButtonText = 'Share Case';
+ this.caaCasesPageType = CaaCasesPageType.UnassignedCases;
}
+ this.cdr.detectChanges();
this.loadCaseTypes();
}
@@ -226,28 +237,18 @@ export class CasesComponent implements OnInit {
public onCaseSelected(selectedCases: any[]): void {
// do i need the line below? and remove the selector in ngOnInit
// this.selectedUnassignedCases = selectedCases;
- if (this.caaCasesPageType === CaaCasesPageType.AssignedCases){
- this.caaCasesStore.dispatch(new caaCasesStore.SynchronizeStateToStoreAssignedCases(
- converters.toShareCaseConverter(selectedCases, CaaCasesPageType.AssignedCases)
- ));
- }
-
- if (this.caaCasesPageType === CaaCasesPageType.UnassignedCases){
- this.caaCasesStore.dispatch(new caaCasesStore.SynchronizeStateToStoreUnassignedCases(
- converters.toShareCaseConverter(selectedCases, CaaCasesPageType.UnassignedCases)
- ));
- }
+ this.caaCasesStore.dispatch(new caaCasesStore.SynchronizeStateToStoreCases(
+ converters.toShareCaseConverter(selectedCases, CaaCasesPageType.AssignedCases)
+ ));
this.selectedCases = selectedCases;
}
public onPageChanged(pageNo: number): void {
- console.log('is the page being changed somehow?');
this.currentPageNo = pageNo;
this.loadCaseData();
}
onShareButtonClicked($event: string) {
- console.log(this.selectedFilterType);
let newCasesEnabled = false;
let groupAccessEnabled = false;
//match the caseType ($event) to any in the allCaseTypes
@@ -263,20 +264,23 @@ export class CasesComponent implements OnInit {
// TODO: need to handle the `new_case` flag
// if returning new case then go to add recipient page
// else if returning non-new case then go to manage case assignments
- this.caaCasesStore.dispatch(new caaCasesStore.AddShareAssignedCases({
- sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType),
+ caaPageType: this.caaCasesPageType
}));
}
if (this.selectedFilterType === CaaCasesFilterType.CasesAssignedToAUser) {
// todo: go to manage case assignments
- this.caaCasesStore.dispatch(new caaCasesStore.AddShareAssignedCases({
- sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType),
+ caaPageType: this.caaCasesPageType
}
));
}
if (this.selectedFilterType === CaaCasesFilterType.AllAssignedCases) {
- this.caaCasesStore.dispatch(new caaCasesStore.AddShareAssignedCases({
- sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType),
+ caaPageType: this.caaCasesPageType
}
));
}
@@ -285,16 +289,18 @@ export class CasesComponent implements OnInit {
// if group_access is enabled then go to accept cases page
// else go to add recipient
if (groupAccessEnabled) {
- this.caaCasesStore.dispatch(new caaCasesStore.AddShareUnassignedCases({
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareCases({
sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType),
+ caaPageType: this.caaCasesPageType,
group_access: true
}
));
}
}
- if (this.selectedFilterType === CaaCasesFilterType.UnassignedCases) {
- this.caaCasesStore.dispatch(new caaCasesStore.AddShareUnassignedCases({
- sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType)
+ if (this.selectedFilterType === CaaCasesFilterType.UnassignedCases || this.selectedFilterType === 'none') {
+ this.caaCasesStore.dispatch(new caaCasesStore.AddShareCases({
+ sharedCases: converters.toShareCaseConverter(this.selectedCases, this.selectedCaseType),
+ caaPageType: this.caaCasesPageType
}));
}
}
diff --git a/src/cases/store/actions/caa-cases.actions.ts b/src/cases/store/actions/caa-cases.actions.ts
index 3731eb040..57157e691 100644
--- a/src/cases/store/actions/caa-cases.actions.ts
+++ b/src/cases/store/actions/caa-cases.actions.ts
@@ -2,44 +2,26 @@ import { HttpErrorResponse } from '@angular/common/http';
import { Action } from '@ngrx/store';
import { CaaCases } from '../../models/caa-cases.model';
-export const LOAD_ASSIGNED_CASES = '[CAA CASES] Load Assigned Cases';
-export const LOAD_ASSIGNED_CASES_SUCCESS = '[CAA CASES] Load Assigned Cases Success';
-export const LOAD_ASSIGNED_CASES_FAILURE = '[CAA CASES] Load Assigned Cases Failure';
-export const LOAD_UNASSIGNED_CASES = '[CAA CASES] Load Unassigned Cases';
-export const LOAD_UNASSIGNED_CASES_SUCCESS = '[CAA CASES] Load Unassigned Cases Success';
-export const LOAD_UNASSIGNED_CASES_FAILURE = '[CAA CASES] Load Unassigned Cases Failure';
+export const LOAD_CASES = '[CAA CASES] Load Cases';
+export const LOAD_CASES_SUCCESS = '[CAA CASES] Load Cases Success';
+export const LOAD_CASES_FAILURE = '[CAA CASES] Load Cases Failure';
export const LOAD_CASE_TYPES = '[CAA CASES] Load Case Types';
export const LOAD_CASE_TYPES_SUCCESS = '[CAA CASES] Load Case Types Success';
export const LOAD_CASE_TYPES_FAILURE = '[CAA CASES] Load Case Types Failure';
export const UPDATE_SELECTION_FOR_CASE_TYPE = '[CAA CASES] Update Selection For Case Types';
-export class LoadAssignedCases implements Action {
- public readonly type = LOAD_ASSIGNED_CASES;
- constructor(public payload: {caseType: string, pageNo: number, pageSize: number, caaCasesFilterType: string | null, caaCasesFilterValue: string | null}) {}
+export class LoadCases implements Action {
+ public readonly type = LOAD_CASES;
+ constructor(public payload: {caseType: string, pageNo: number, pageSize: number, caaCasesPage: string, caaCasesFilterType: string | null, caaCasesFilterValue: string | null}) {}
}
-export class LoadAssignedCasesSuccess implements Action {
- public readonly type = LOAD_ASSIGNED_CASES_SUCCESS;
+export class LoadCasesSuccess implements Action {
+ public readonly type = LOAD_CASES_SUCCESS;
constructor(public payload: CaaCases) {}
}
-export class LoadAssignedCasesFailure implements Action {
- public readonly type = LOAD_ASSIGNED_CASES_FAILURE;
- constructor(public payload: HttpErrorResponse) {}
-}
-
-export class LoadUnassignedCases implements Action {
- public readonly type = LOAD_UNASSIGNED_CASES;
- constructor(public payload: {caseType: string, pageNo: number, pageSize: number, caaCasesFilterType: string | null, caaCasesFilterValue: string | null}) {}
-}
-
-export class LoadUnassignedCasesSuccess implements Action {
- public readonly type = LOAD_UNASSIGNED_CASES_SUCCESS;
- constructor(public payload: CaaCases) {}
-}
-
-export class LoadUnassignedCasesFailure implements Action {
- public readonly type = LOAD_UNASSIGNED_CASES_FAILURE;
+export class LoadCasesFailure implements Action {
+ public readonly type = LOAD_CASES_FAILURE;
constructor(public payload: HttpErrorResponse) {}
}
@@ -64,12 +46,9 @@ export class UpdateSelectionForCaseType implements Action {
}
export type CaaCasesActions =
- LoadAssignedCases
- | LoadAssignedCasesSuccess
- | LoadAssignedCasesFailure
- | LoadUnassignedCases
- | LoadUnassignedCasesSuccess
- | LoadUnassignedCasesFailure
+ LoadCases
+ | LoadCasesSuccess
+ | LoadCasesFailure
| LoadCaseTypes
| LoadCaseTypesSuccess
| LoadCaseTypesFailure
diff --git a/src/cases/store/actions/index.ts b/src/cases/store/actions/index.ts
index 55c8e9243..e8d7f5fea 100644
--- a/src/cases/store/actions/index.ts
+++ b/src/cases/store/actions/index.ts
@@ -1,19 +1,13 @@
import {
- LoadAssignedCases,
- LoadAssignedCasesFailure,
- LoadAssignedCasesSuccess,
- LoadUnassignedCases,
- LoadUnassignedCasesFailure,
- LoadUnassignedCasesSuccess
+ LoadCases,
+ LoadCasesFailure,
+ LoadCasesSuccess
} from './caa-cases.actions';
export const actions: any[] = [
- LoadAssignedCases,
- LoadAssignedCasesSuccess,
- LoadAssignedCasesFailure,
- LoadUnassignedCases,
- LoadUnassignedCasesSuccess,
- LoadUnassignedCasesFailure
+ LoadCases,
+ LoadCasesSuccess,
+ LoadCasesFailure
];
export * from './caa-cases.actions';
diff --git a/src/cases/store/actions/share-case.action.ts b/src/cases/store/actions/share-case.action.ts
index 39938045c..de0b223d5 100644
--- a/src/cases/store/actions/share-case.action.ts
+++ b/src/cases/store/actions/share-case.action.ts
@@ -3,175 +3,91 @@ import { SharedCase } from '@hmcts/rpx-xui-common-lib/lib/models/case-share.mode
import { UserDetails } from '@hmcts/rpx-xui-common-lib/lib/models/user-details.model';
import { Action } from '@ngrx/store';
-// Assigned cases actions
-export const NAVIGATE_TO_SHARE_ASSIGNED_CASES = '[ShareCase] Navigate To Share Assigned Cases';
-export const LOAD_SHARE_ASSIGNED_CASES = '[ShareCase] Load Share Assigned Cases';
-export const LOAD_SHARE_ASSIGNED_CASES_SUCCESS = '[ShareCase] Load Share Assigned Cases Success';
-export const LOAD_SHARE_ASSIGNED_CASES_FAILURE = '[ShareCase] Load Share Assigned Cases Failure';
-export const ADD_SHARE_ASSIGNED_CASES = '[ShareCase] Add Share Assigned Cases';
-export const ADD_SHARE_ASSIGNED_CASES_GO = '[Router] Add Share Assigned Case Go';
-export const DELETE_A_SHARE_ASSIGNED_CASE = '[ShareCase] Delete A Share Assigned Case';
-export const ASSIGN_USERS_TO_ASSIGNED_CASE = '[ShareCase] Assign Users to Assigned Case';
-export const ASSIGN_USERS_TO_ASSIGNED_CASE_SUCCESS = '[ShareCase] Assign Users to Assigned Case Success';
-export const RESET_ASSIGNED_CASE_SELECTION = '[ShareCase] Reset Assigned Case Selection';
-
-// Unassigned cases actions
-export const NAVIGATE_TO_SHARE_UNASSIGNED_CASES = '[ShareCase] Navigate To Share Unassigned Cases';
-export const LOAD_SHARE_UNASSIGNED_CASES = '[ShareCase] Load Share Unassigned Cases';
-export const LOAD_SHARE_UNASSIGNED_CASES_SUCCESS = '[ShareCase] Load Share Unassigned Cases Success';
-export const LOAD_SHARE_UNASSIGNED_CASES_FAILURE = '[ShareCase] Load Share Unassigned Cases Failure';
-export const ADD_SHARE_UNASSIGNED_CASES = '[ShareCase] Add Share Unassigned Cases';
-export const ADD_SHARE_UNASSIGNED_CASES_GO = '[Router] Add Share Unassigned Case Go';
-export const DELETE_A_SHARE_UNASSIGNED_CASE = '[ShareCase] Delete A Share Unassigned Case';
-export const ASSIGN_USERS_TO_UNASSIGNED_CASE = '[ShareCase] Assign Users to Unassigned Case';
-export const ASSIGN_USERS_TO_UNASSIGNED_CASE_SUCCESS = '[ShareCase] Assign Users to Unassigned Case Success';
-export const RESET_UNASSIGNED_CASE_SELECTION = '[ShareCase] Reset Unassigned Case Selection';
+// cases actions
+export const NAVIGATE_TO_SHARE_CASES = '[ShareCase] Navigate To Share Cases';
+export const LOAD_SHARE_CASES = '[ShareCase] Load Share Cases';
+export const LOAD_SHARE_CASES_SUCCESS = '[ShareCase] Load Share Cases Success';
+export const LOAD_SHARE_CASES_FAILURE = '[ShareCase] Load Share Cases Failure';
+export const ADD_SHARE_CASES = '[ShareCase] Add Share Cases';
+export const ADD_SHARE_CASES_GO = '[Router] Add Share Case Go';
+export const DELETE_A_SHARE_CASE = '[ShareCase] Delete A Share Case';
+export const ASSIGN_USERS_TO_CASE = '[ShareCase] Assign Users to Case';
+export const ASSIGN_USERS_TO_CASE_SUCCESS = '[ShareCase] Assign Users to Case Success';
+export const RESET_CASE_SELECTION = '[ShareCase] Reset Case Selection';
export const LOAD_USERS_FROM_ORG_FOR_CASE = '[LoadUsers] From ORG For A Case';
export const LOAD_USERS_FROM_ORG_FOR_CASE_SUCCESS = '[LoadUsers] From ORG For A Case Success';
-export const SYNCHRONIZE_STATE_TO_STORE_ASSIGNED_CASES = '[ShareCase] Synchronize State To Store Assigned Cases';
-export const SYNCHRONIZE_STATE_TO_STORE_UNASSIGNED_CASES = '[ShareCase] Synchronize State To Store Unassigned Cases';
-
-export class NavigateToShareAssignedCases implements Action {
- public readonly type = NAVIGATE_TO_SHARE_ASSIGNED_CASES;
- constructor(public payload: SharedCase[]) {}
-}
-
-export class NavigateToShareUnassignedCases implements Action {
- public readonly type = NAVIGATE_TO_SHARE_UNASSIGNED_CASES;
- constructor(public payload: SharedCase[]) {}
-}
+export const SYNCHRONIZE_STATE_TO_STORE_CASES = '[ShareCase] Synchronize State To Store Cases';
-export class SynchronizeStateToStoreAssignedCases implements Action {
- public readonly type = SYNCHRONIZE_STATE_TO_STORE_ASSIGNED_CASES;
+export class NavigateToShareCases implements Action {
+ public readonly type = NAVIGATE_TO_SHARE_CASES;
constructor(public payload: SharedCase[]) {}
}
-export class SynchronizeStateToStoreUnassignedCases implements Action {
- public readonly type = SYNCHRONIZE_STATE_TO_STORE_UNASSIGNED_CASES;
+export class SynchronizeStateToStoreCases implements Action {
+ public readonly type = SYNCHRONIZE_STATE_TO_STORE_CASES;
constructor(public payload: SharedCase[]) {}
}
-export class LoadShareAssignedCases implements Action {
- public readonly type = LOAD_SHARE_ASSIGNED_CASES;
+export class LoadShareCases implements Action {
+ public readonly type = LOAD_SHARE_CASES;
constructor(public payload: SharedCase[]) {}
}
-export class LoadShareAssignedCasesSuccess implements Action {
- public readonly type = LOAD_SHARE_ASSIGNED_CASES_SUCCESS;
+export class LoadShareCasesSuccess implements Action {
+ public readonly type = LOAD_SHARE_CASES_SUCCESS;
constructor(public payload: SharedCase[]) {}
}
-export class LoadShareAssignedCaseFailure implements Action {
- public readonly type = LOAD_SHARE_ASSIGNED_CASES_FAILURE;
+export class LoadShareCaseFailure implements Action {
+ public readonly type = LOAD_SHARE_CASES_FAILURE;
constructor(public payload: Error) {}
}
-export class LoadShareUnassignedCases implements Action {
- public readonly type = LOAD_SHARE_UNASSIGNED_CASES;
- constructor(public payload: SharedCase[]) {}
-}
-
-export class LoadShareUnassignedCasesSuccess implements Action {
- public readonly type = LOAD_SHARE_UNASSIGNED_CASES_SUCCESS;
- constructor(public payload: SharedCase[]) {}
-}
-
-export class LoadShareUnassignedCaseFailure implements Action {
- public readonly type = LOAD_SHARE_UNASSIGNED_CASES_FAILURE;
- constructor(public payload: Error) {}
-}
-
-export class AddShareAssignedCases implements Action {
- public readonly type = ADD_SHARE_ASSIGNED_CASES;
- constructor(public payload: {
- path?: any[];
- query?: object;
- extras?: NavigationExtras;
- sharedCases: SharedCase[]
- }) {}
-}
-
-export class AddShareAssignedCaseGo implements Action {
- public readonly type = ADD_SHARE_ASSIGNED_CASES_GO;
- constructor(
- public payload: {
- path: any[];
- query?: object;
- extras?: NavigationExtras;
- sharedCases: SharedCase[]
- }
- ) {}
-}
-
-export class AddShareUnassignedCases implements Action {
- public readonly type = ADD_SHARE_UNASSIGNED_CASES;
+export class AddShareCases implements Action {
+ public readonly type = ADD_SHARE_CASES;
constructor(public payload: {
path?: any[];
query?: object;
extras?: NavigationExtras;
sharedCases: SharedCase[],
group_access?: boolean,
- new_cases?: boolean
+ caaPageType?: string
}) {}
}
-export class AddShareUnassignedCaseGo implements Action {
- public readonly type = ADD_SHARE_UNASSIGNED_CASES_GO;
+export class AddShareCaseGo implements Action {
+ public readonly type = ADD_SHARE_CASES_GO;
constructor(
public payload: {
path: any[];
query?: object;
extras?: NavigationExtras;
- sharedCases: SharedCase[]
- }
- ) {}
-}
-
-export class DeleteAShareAssignedCase implements Action {
- public readonly type = DELETE_A_SHARE_ASSIGNED_CASE;
- constructor(
- public payload: {
- caseId: string;
+ sharedCases: SharedCase[];
+ caaPageType?: string
}
) {}
}
-
-export class DeleteAShareUnassignedCase implements Action {
- public readonly type = DELETE_A_SHARE_UNASSIGNED_CASE;
+export class DeleteAShareCase implements Action {
+ public readonly type = DELETE_A_SHARE_CASE;
constructor(
public payload: {
caseId: string;
}
) {}
}
-
-export class AssignUsersToAssignedCase implements Action {
- public readonly type = ASSIGN_USERS_TO_ASSIGNED_CASE;
- constructor(public payload: SharedCase[]) {}
-}
-
-export class AssignUsersToAssignedCaseSuccess implements Action {
- public readonly type = ASSIGN_USERS_TO_ASSIGNED_CASE_SUCCESS;
- constructor(public payload: SharedCase[]) {}
-}
-
-export class AssignUsersToUnassignedCase implements Action {
- public readonly type = ASSIGN_USERS_TO_UNASSIGNED_CASE;
+export class AssignUsersToCase implements Action {
+ public readonly type = ASSIGN_USERS_TO_CASE;
constructor(public payload: SharedCase[]) {}
}
-export class AssignUsersToUnassignedCaseSuccess implements Action {
- public readonly type = ASSIGN_USERS_TO_UNASSIGNED_CASE_SUCCESS;
+export class AssignUsersToCaseSuccess implements Action {
+ public readonly type = ASSIGN_USERS_TO_CASE_SUCCESS;
constructor(public payload: SharedCase[]) {}
}
-export class ResetAssignedCaseSelection implements Action {
- public readonly type = RESET_ASSIGNED_CASE_SELECTION;
-}
-
-export class ResetUnassignedCaseSelection implements Action {
- public readonly type = RESET_UNASSIGNED_CASE_SELECTION;
+export class ResetCaseSelection implements Action {
+ public readonly type = RESET_CASE_SELECTION;
}
export class LoadUserFromOrgForCase implements Action {
@@ -184,27 +100,16 @@ export class LoadUserFromOrgForCaseSuccess implements Action {
}
export type Actions =
- NavigateToShareAssignedCases
- | NavigateToShareUnassignedCases
- | SynchronizeStateToStoreAssignedCases
- | SynchronizeStateToStoreUnassignedCases
- | LoadShareAssignedCases
- | LoadShareAssignedCasesSuccess
- | LoadShareAssignedCaseFailure
- | LoadShareUnassignedCases
- | LoadShareUnassignedCasesSuccess
- | LoadShareUnassignedCaseFailure
- | AddShareAssignedCases
- | AddShareAssignedCaseGo
- | AddShareUnassignedCases
- | AddShareUnassignedCaseGo
- | DeleteAShareAssignedCase
- | DeleteAShareUnassignedCase
- | AssignUsersToAssignedCase
- | AssignUsersToAssignedCaseSuccess
- | AssignUsersToUnassignedCase
- | AssignUsersToUnassignedCaseSuccess
- | ResetAssignedCaseSelection
- | ResetUnassignedCaseSelection
+ NavigateToShareCases
+ | SynchronizeStateToStoreCases
+ | LoadShareCases
+ | LoadShareCasesSuccess
+ | LoadShareCaseFailure
+ | AddShareCases
+ | AddShareCaseGo
+ | DeleteAShareCase
+ | AssignUsersToCase
+ | AssignUsersToCaseSuccess
+ | ResetCaseSelection
| LoadUserFromOrgForCase
| LoadUserFromOrgForCaseSuccess;
diff --git a/src/cases/store/effects/caa-cases.effects.ts b/src/cases/store/effects/caa-cases.effects.ts
index 6bc1e8f2d..7ce3a4cbd 100644
--- a/src/cases/store/effects/caa-cases.effects.ts
+++ b/src/cases/store/effects/caa-cases.effects.ts
@@ -18,28 +18,15 @@ export class CaaCasesEffects {
private readonly loggerService: LoggerService) {
}
- public loadAssignedCases$ = createEffect(() =>
+ public loadCases$ = createEffect(() =>
this.actions$.pipe(
- ofType(fromCaaActions.LOAD_ASSIGNED_CASES),
- switchMap((action: fromCaaActions.LoadAssignedCases) => {
+ ofType(fromCaaActions.LOAD_CASES),
+ switchMap((action: fromCaaActions.LoadCases) => {
const payload = action.payload;
- console.log('load assigned cases');
- return this.caaCasesService.getCaaCases(payload.caseType, payload.pageNo, payload.pageSize, CaaCasesPageType.AssignedCases, payload.caaCasesFilterType, payload.caaCasesFilterValue).pipe(
- map((caaCases) => new fromCaaActions.LoadAssignedCasesSuccess(caaCases)),
- catchError((error) => CaaCasesEffects.handleError(error, this.loggerService, CaaCasesPageType.AssignedCases))
- );
- })
- )
- );
-
- public loadUnassignedCases$ = createEffect(() =>
- this.actions$.pipe(
- ofType(fromCaaActions.LOAD_UNASSIGNED_CASES),
- switchMap((action: fromCaaActions.LoadUnassignedCases) => {
- const payload = action.payload;
- return this.caaCasesService.getCaaCases(payload.caseType, payload.pageNo, payload.pageSize, CaaCasesPageType.UnassignedCases, payload.caaCasesFilterType, payload.caaCasesFilterValue).pipe(
- map((caaCases) => new fromCaaActions.LoadUnassignedCasesSuccess(caaCases)),
- catchError((error) => CaaCasesEffects.handleError(error, this.loggerService, CaaCasesPageType.UnassignedCases))
+ const pageType = payload.caaCasesPage === CaaCasesPageType.AssignedCases ? CaaCasesPageType.AssignedCases : CaaCasesPageType.UnassignedCases;
+ return this.caaCasesService.getCaaCases(payload.caseType, payload.pageNo, payload.pageSize, pageType, payload.caaCasesFilterType, payload.caaCasesFilterValue).pipe(
+ map((caaCases) => new fromCaaActions.LoadCasesSuccess(caaCases)),
+ catchError((error) => CaaCasesEffects.handleError(error, this.loggerService, pageType))
);
})
)
@@ -67,9 +54,7 @@ export class CaaCasesEffects {
public static handleError(error: HttpErrorResponse, loggerService: LoggerService, caaCasesPageType: string): Observable {
loggerService.error(error);
return error.status === 400
- ? caaCasesPageType === CaaCasesPageType.UnassignedCases
- ? of(new fromCaaActions.LoadUnassignedCasesFailure(error))
- : of(new fromCaaActions.LoadAssignedCasesFailure(error))
+ ? of(new fromCaaActions.LoadCasesFailure(error))
: of(new fromRoot.Go({ path: ['/service-down'] }));
}
}
diff --git a/src/cases/store/effects/share-case.effects.ts b/src/cases/store/effects/share-case.effects.ts
index e8aaa7bfe..450637ff9 100644
--- a/src/cases/store/effects/share-case.effects.ts
+++ b/src/cases/store/effects/share-case.effects.ts
@@ -22,84 +22,45 @@ export class ShareCaseEffects {
) {
}
- public addShareAssignedCases$ = createEffect(() =>
+ public addShareCases$ = createEffect(() =>
this.actions$.pipe(
- ofType(shareCaseActions.ADD_SHARE_ASSIGNED_CASES),
- map((action: shareCaseActions.AddShareAssignedCases) => action.payload),
+ ofType(shareCaseActions.ADD_SHARE_CASES),
+ map((action: shareCaseActions.AddShareCases) => action.payload),
map((newCases) => {
- return new shareCaseActions.AddShareAssignedCaseGo({
- path: [`${this.router.url}/case-share`],
- sharedCases: newCases.sharedCases
+ return new shareCaseActions.AddShareCaseGo({
+ path: this.getPathFromCaseConfig(newCases.caaPageType, newCases.group_access),
+ sharedCases: newCases.sharedCases,
+ caaPageType: newCases.caaPageType
});
})
)
);
- public addShareUnassignedCases$ = createEffect(() =>
+ public navigateToAddShareCase$ = createEffect(() =>
this.actions$.pipe(
- ofType(shareCaseActions.ADD_SHARE_UNASSIGNED_CASES),
- map((action: shareCaseActions.AddShareUnassignedCases) => action.payload),
- map((newCases) => {
- return new shareCaseActions.AddShareUnassignedCaseGo({
- path: this.getPathFromCaseConfig(newCases.group_access, newCases.new_cases),
- sharedCases: newCases.sharedCases
- });
- })
- )
- );
-
- public navigateToAddShareAssignedCase$ = createEffect(() =>
- this.actions$.pipe(
- ofType(shareCaseActions.ADD_SHARE_ASSIGNED_CASES_GO),
- map((action: shareCaseActions.AddShareAssignedCaseGo) => action.payload),
- tap(({ path, query: queryParams, extras, sharedCases }) => {
- const thatSharedCases = sharedCases;
- queryParams = { init: true, pageType: CaaCasesPageType.AssignedCases };
- return this.router.navigate(path, { queryParams, ...extras }).then(() => {
- this.store.dispatch(new shareCaseActions.NavigateToShareAssignedCases(thatSharedCases));
- });
- })
- ),
- { dispatch: false }
- );
-
- public navigateToAddShareUnassignedCase$ = createEffect(() =>
- this.actions$.pipe(
- ofType(shareCaseActions.ADD_SHARE_UNASSIGNED_CASES_GO),
- map((action: shareCaseActions.AddShareUnassignedCaseGo) => action.payload),
- tap(({ path, query: queryParams, extras, sharedCases }) => {
+ ofType(shareCaseActions.ADD_SHARE_CASES_GO),
+ map((action: shareCaseActions.AddShareCaseGo) => action.payload),
+ tap(({ path, query: queryParams, extras, sharedCases, caaPageType }) => {
const thatSharedCases = sharedCases;
- queryParams = { init: true, pageType: CaaCasesPageType.UnassignedCases };
+ const currentPageType = caaPageType === CaaCasesPageType.UnassignedCases ? CaaCasesPageType.UnassignedCases : CaaCasesPageType.AssignedCases;
+ console.log('current page type', currentPageType);
+ queryParams = { init: true, pageType: currentPageType };
return this.router.navigate(path, { queryParams, ...extras }).then(() => {
- this.store.dispatch(new shareCaseActions.NavigateToShareUnassignedCases(thatSharedCases));
+ this.store.dispatch(new shareCaseActions.NavigateToShareCases(thatSharedCases));
});
})
),
{ dispatch: false }
);
- public loadShareAssignedCases$ = createEffect(() =>
- this.actions$.pipe(
- ofType(shareCaseActions.LOAD_SHARE_ASSIGNED_CASES),
- map((action: shareCaseActions.LoadShareAssignedCases) => action.payload),
- switchMap((payload) => {
- this.payload = payload;
- return this.caseShareService.getShareCases(payload).pipe(
- map((response) => new shareCaseActions.LoadShareAssignedCasesSuccess(response)),
- catchError(() => of(new fromRoot.Go({ path: ['/service-down'] })))
- );
- })
- )
- );
-
- public loadShareUnassignedCases$ = createEffect(() =>
+ public loadShareCases$ = createEffect(() =>
this.actions$.pipe(
- ofType(shareCaseActions.LOAD_SHARE_UNASSIGNED_CASES),
- map((action: shareCaseActions.LoadShareUnassignedCases) => action.payload),
+ ofType(shareCaseActions.LOAD_SHARE_CASES),
+ map((action: shareCaseActions.LoadShareCases) => action.payload),
switchMap((payload) => {
this.payload = payload;
return this.caseShareService.getShareCases(payload).pipe(
- map((response) => new shareCaseActions.LoadShareUnassignedCasesSuccess(response)),
+ map((response) => new shareCaseActions.LoadShareCasesSuccess(response)),
catchError(() => of(new fromRoot.Go({ path: ['/service-down'] })))
);
})
@@ -118,36 +79,22 @@ export class ShareCaseEffects {
)
);
- public assignUsersToAssignedCases$ = createEffect(() =>
- this.actions$.pipe(
- ofType(shareCaseActions.ASSIGN_USERS_TO_ASSIGNED_CASE),
- map((action: shareCaseActions.AssignUsersToAssignedCase) => action.payload),
- switchMap((payload) => {
- this.payload = payload;
- return this.caseShareService.assignUsersWithCases(payload).pipe(
- map((response) => new shareCaseActions.AssignUsersToAssignedCaseSuccess(response)),
- catchError(() => of(new fromRoot.Go({ path: ['/service-down'] })))
- );
- })
- )
- );
-
- public assignUsersToUnassignedCases$ = createEffect(() =>
+ public assignUsersToCases$ = createEffect(() =>
this.actions$.pipe(
- ofType(shareCaseActions.ASSIGN_USERS_TO_UNASSIGNED_CASE),
- map((action: shareCaseActions.AssignUsersToUnassignedCase) => action.payload),
+ ofType(shareCaseActions.ASSIGN_USERS_TO_CASE),
+ map((action: shareCaseActions.AssignUsersToCase) => action.payload),
switchMap((payload) => {
this.payload = payload;
return this.caseShareService.assignUsersWithCases(payload).pipe(
- map((response) => new shareCaseActions.AssignUsersToUnassignedCaseSuccess(response)),
+ map((response) => new shareCaseActions.AssignUsersToCaseSuccess(response)),
catchError(() => of(new fromRoot.Go({ path: ['/service-down'] })))
);
})
)
);
- public getPathFromCaseConfig(groupAccess?: boolean, newCases?: boolean) {
- if (groupAccess){
+ public getPathFromCaseConfig(caaCasesPageType: string, groupAccess?: boolean, newCases?: boolean) {
+ if (groupAccess && caaCasesPageType === CaaCasesPageType.NewCases) {
return [`${this.router.url}/accept-cases`];
}
return [`${this.router.url}/case-share`];
diff --git a/src/cases/store/reducers/caa-cases.reducer.ts b/src/cases/store/reducers/caa-cases.reducer.ts
index 785943aee..cf61babc0 100644
--- a/src/cases/store/reducers/caa-cases.reducer.ts
+++ b/src/cases/store/reducers/caa-cases.reducer.ts
@@ -4,33 +4,25 @@ import { CaaCases, SelectedCases } from '../../models/caa-cases.model';
import * as fromCaaActions from '../actions/caa-cases.actions';
export interface CaaCasesState {
- assignedCases: CaaCases;
- unassignedCases: CaaCases;
+ Cases: CaaCases;
caseTypes: SubNavigation[];
selectedCases: SelectedCases;
- assignedCasesLastError: HttpErrorResponse;
- unassignedCasesLastError: HttpErrorResponse;
+ CasesLastError: HttpErrorResponse;
}
export const initialState: CaaCasesState = {
- assignedCases: null,
- unassignedCases: null,
+ Cases: null,
caseTypes: [],
selectedCases: {},
- assignedCasesLastError: null,
- unassignedCasesLastError: null
+ CasesLastError: null
};
export function caaCasesReducer(state = initialState, action: fromCaaActions.CaaCasesActions): CaaCasesState {
switch (action.type) {
- case fromCaaActions.LOAD_ASSIGNED_CASES_SUCCESS:
- return { ...state, assignedCases: action.payload, assignedCasesLastError: null };
- case fromCaaActions.LOAD_ASSIGNED_CASES_FAILURE:
- return { ...state, assignedCases: { idField: '', columnConfigs: [], data: [] }, assignedCasesLastError: action.payload };
- case fromCaaActions.LOAD_UNASSIGNED_CASES_SUCCESS:
- return { ...state, unassignedCases: action.payload, unassignedCasesLastError: null };
- case fromCaaActions.LOAD_UNASSIGNED_CASES_FAILURE:
- return { ...state, unassignedCases: { idField: '', columnConfigs: [], data: [] }, unassignedCasesLastError: action.payload };
+ case fromCaaActions.LOAD_CASES_SUCCESS:
+ return { ...state, Cases: action.payload, CasesLastError: null };
+ case fromCaaActions.LOAD_CASES_FAILURE:
+ return { ...state, Cases: { idField: '', columnConfigs: [], data: [] }, CasesLastError: action.payload };
case fromCaaActions.LOAD_CASE_TYPES_SUCCESS:
return { ...state, caseTypes: action.payload };
case fromCaaActions.UPDATE_SELECTION_FOR_CASE_TYPE:
@@ -42,8 +34,6 @@ export function caaCasesReducer(state = initialState, action: fromCaaActions.Caa
}
}
-export const getAssignedCases = (state: CaaCasesState) => state.assignedCases;
-export const getAssignedCasesError = (state: CaaCasesState) => state.assignedCasesLastError;
-export const getUnassignedCases = (state: CaaCasesState) => state.unassignedCases;
-export const getUnassignedCasesError = (state: CaaCasesState) => state.unassignedCasesLastError;
+export const getCases = (state: CaaCasesState) => state.Cases;
+export const getCasesError = (state: CaaCasesState) => state.CasesLastError;
export const getCaseTypes = (state: CaaCasesState) => state.caseTypes;
diff --git a/src/cases/store/reducers/share-case.reducer.ts b/src/cases/store/reducers/share-case.reducer.ts
index abcc1391e..c942f8217 100644
--- a/src/cases/store/reducers/share-case.reducer.ts
+++ b/src/cases/store/reducers/share-case.reducer.ts
@@ -3,16 +3,14 @@ import { UserDetails } from '@hmcts/rpx-xui-common-lib/lib/models/user-details.m
import * as ShareCasesActions from '../actions/share-case.action';
export interface ShareCasesState {
- shareAssignedCases: SharedCase[];
- shareUnassignedCases: SharedCase[];
+ shareCases: SharedCase[];
loading: boolean;
error: Error;
users: UserDetails[];
}
export const initialSharedCasesState: ShareCasesState = {
- shareAssignedCases: [],
- shareUnassignedCases: [],
+ shareCases: [],
loading: false,
error: undefined,
users: []
@@ -22,24 +20,24 @@ export function shareCasesReducer(
state: ShareCasesState = initialSharedCasesState,
action: ShareCasesActions.Actions): ShareCasesState {
switch (action.type) {
- case ShareCasesActions.NAVIGATE_TO_SHARE_ASSIGNED_CASES:
- const navigateToShareAssignedCases = state.shareAssignedCases.slice();
+ case ShareCasesActions.NAVIGATE_TO_SHARE_CASES:
+ const navigateToShareCases = state.shareCases.slice();
for (const aCase of action.payload) {
- if (!navigateToShareAssignedCases.some((hasACase) => hasACase.caseId === aCase.caseId)) {
- navigateToShareAssignedCases.push(aCase);
+ if (!navigateToShareCases.some((hasACase) => hasACase.caseId === aCase.caseId)) {
+ navigateToShareCases.push(aCase);
}
}
return {
...state,
- shareAssignedCases: navigateToShareAssignedCases
+ shareCases: navigateToShareCases
};
- case ShareCasesActions.LOAD_SHARE_ASSIGNED_CASES:
+ case ShareCasesActions.LOAD_SHARE_CASES:
return {
...state,
loading: true
};
- case ShareCasesActions.LOAD_SHARE_ASSIGNED_CASES_SUCCESS:
- const casesInStore = state.shareAssignedCases.slice();
+ case ShareCasesActions.LOAD_SHARE_CASES_SUCCESS:
+ const casesInStore = state.shareCases.slice();
const casesFromNode: SharedCase[] = sortedUserInCases(action.payload);
const casesWithTypes = [];
for (const aCase of casesInStore) {
@@ -59,39 +57,39 @@ export function shareCasesReducer(
}
return {
...state,
- shareAssignedCases: casesWithTypes,
+ shareCases: casesWithTypes,
loading: false
};
- case ShareCasesActions.LOAD_SHARE_ASSIGNED_CASES_FAILURE:
+ case ShareCasesActions.LOAD_SHARE_CASES_FAILURE:
return {
...state,
error: action.payload,
loading: false
};
- case ShareCasesActions.ADD_SHARE_ASSIGNED_CASES:
- const addShareAssignedCases = state.shareAssignedCases.slice();
+ case ShareCasesActions.ADD_SHARE_CASES:
+ const addShareCases = state.shareCases.slice();
for (const aCase of action.payload.sharedCases) {
- if (!addShareAssignedCases.some((hasACase) => hasACase.caseId === aCase.caseId)) {
- addShareAssignedCases.push(aCase);
+ if (!addShareCases.some((hasACase) => hasACase.caseId === aCase.caseId)) {
+ addShareCases.push(aCase);
}
}
return {
...state,
- shareAssignedCases: addShareAssignedCases
+ shareCases: addShareCases
};
- case ShareCasesActions.ADD_SHARE_ASSIGNED_CASES_GO:
- const addShareAssignedCasesGo = state.shareAssignedCases.slice();
+ case ShareCasesActions.ADD_SHARE_CASES_GO:
+ const addShareCasesGo = state.shareCases.slice();
for (const aCase of action.payload.sharedCases) {
- if (!addShareAssignedCasesGo.some((hasACase) => hasACase.caseId === aCase.caseId)) {
- addShareAssignedCasesGo.push(aCase);
+ if (!addShareCasesGo.some((hasACase) => hasACase.caseId === aCase.caseId)) {
+ addShareCasesGo.push(aCase);
}
}
return {
...state,
- shareAssignedCases: addShareAssignedCasesGo
+ shareCases: addShareCasesGo
};
- case ShareCasesActions.DELETE_A_SHARE_ASSIGNED_CASE:
- const caseInStore4Delete = state.shareAssignedCases.slice();
+ case ShareCasesActions.DELETE_A_SHARE_CASE:
+ const caseInStore4Delete = state.shareCases.slice();
for (let i = 0, l = caseInStore4Delete.length; i < l; i++) {
if (caseInStore4Delete[i].caseId === action.payload.caseId) {
caseInStore4Delete.splice(i, 1);
@@ -100,127 +98,30 @@ export function shareCasesReducer(
}
return {
...state,
- shareAssignedCases: caseInStore4Delete
+ shareCases: caseInStore4Delete
};
- case ShareCasesActions.SYNCHRONIZE_STATE_TO_STORE_ASSIGNED_CASES:
+ case ShareCasesActions.SYNCHRONIZE_STATE_TO_STORE_CASES:
return {
...state,
- shareAssignedCases: action.payload
+ shareCases: action.payload
};
- case ShareCasesActions.ASSIGN_USERS_TO_ASSIGNED_CASE_SUCCESS:
+ case ShareCasesActions.ASSIGN_USERS_TO_CASE_SUCCESS:
return {
...state,
- shareAssignedCases: action.payload,
+ shareCases: action.payload,
loading: true
};
- case ShareCasesActions.RESET_ASSIGNED_CASE_SELECTION:
+ case ShareCasesActions.RESET_CASE_SELECTION:
return {
...state,
- shareAssignedCases: [],
+ shareCases: [],
loading: false
};
- case ShareCasesActions.NAVIGATE_TO_SHARE_UNASSIGNED_CASES:
- const navigateToShareUnassignedCases = state.shareUnassignedCases.slice();
- for (const aCase of action.payload) {
- if (!navigateToShareUnassignedCases.some((hasACase) => hasACase.caseId === aCase.caseId)) {
- navigateToShareUnassignedCases.push(aCase);
- }
- }
- return {
- ...state,
- shareUnassignedCases: navigateToShareUnassignedCases
- };
- case ShareCasesActions.LOAD_SHARE_UNASSIGNED_CASES:
- return {
- ...state,
- loading: true
- };
- case ShareCasesActions.LOAD_SHARE_UNASSIGNED_CASES_SUCCESS:
- const unassignedCasesInStore = state.shareUnassignedCases.slice();
- const unassignedCasesFromNode: SharedCase[] = sortedUserInCases(action.payload);
- const unassignedCasesWithTypes = [];
- for (const aCase of unassignedCasesInStore) {
- const intersectionCase = unassignedCasesFromNode.find((nodeCase) => nodeCase.caseId === aCase.caseId);
- if (intersectionCase && intersectionCase.caseId) {
- const caseTypeId = aCase.caseTypeId ? aCase.caseTypeId : null;
- const caseTitle = aCase.caseTitle ? aCase.caseTitle : null;
- const newCase: SharedCase = {
- ...intersectionCase,
- caseTypeId,
- caseTitle
- };
- unassignedCasesWithTypes.push(newCase);
- } else {
- unassignedCasesWithTypes.push(aCase);
- }
- }
- return {
- ...state,
- shareUnassignedCases: unassignedCasesWithTypes,
- loading: false
- };
- case ShareCasesActions.LOAD_SHARE_UNASSIGNED_CASES_FAILURE:
- return {
- ...state,
- error: action.payload,
- loading: false
- };
- case ShareCasesActions.ADD_SHARE_UNASSIGNED_CASES:
- const addShareUnassignedCases = state.shareUnassignedCases.slice();
- for (const aCase of action.payload.sharedCases) {
- if (!addShareUnassignedCases.some((hasACase) => hasACase.caseId === aCase.caseId)) {
- addShareUnassignedCases.push(aCase);
- }
- }
- return {
- ...state,
- shareUnassignedCases: addShareUnassignedCases
- };
- case ShareCasesActions.ADD_SHARE_UNASSIGNED_CASES_GO:
- const addShareUnassignedCasesGo = state.shareUnassignedCases.slice();
- for (const aCase of action.payload.sharedCases) {
- if (!addShareUnassignedCasesGo.some((hasACase) => hasACase.caseId === aCase.caseId)) {
- addShareUnassignedCasesGo.push(aCase);
- }
- }
- return {
- ...state,
- shareUnassignedCases: addShareUnassignedCasesGo
- };
- case ShareCasesActions.DELETE_A_SHARE_UNASSIGNED_CASE:
- const unassignedCaseInStore4Delete = state.shareUnassignedCases.slice();
- for (let i = 0, l = unassignedCaseInStore4Delete.length; i < l; i++) {
- if (unassignedCaseInStore4Delete[i].caseId === action.payload.caseId) {
- unassignedCaseInStore4Delete.splice(i, 1);
- break;
- }
- }
- return {
- ...state,
- shareUnassignedCases: unassignedCaseInStore4Delete
- };
case ShareCasesActions.LOAD_USERS_FROM_ORG_FOR_CASE_SUCCESS:
return {
...state,
users: action.payload
};
- case ShareCasesActions.SYNCHRONIZE_STATE_TO_STORE_UNASSIGNED_CASES:
- return {
- ...state,
- shareUnassignedCases: action.payload
- };
- case ShareCasesActions.ASSIGN_USERS_TO_UNASSIGNED_CASE_SUCCESS:
- return {
- ...state,
- shareUnassignedCases: action.payload,
- loading: true
- };
- case ShareCasesActions.RESET_UNASSIGNED_CASE_SELECTION:
- return {
- ...state,
- shareUnassignedCases: [],
- loading: false
- };
default:
return state;
}
@@ -245,6 +146,5 @@ export function sortedUserInCases(pendingSortedCases: SharedCase[]): SharedCase[
return cases;
}
-export const getShareAssignedCases = (state: ShareCasesState) => state.shareAssignedCases;
-export const getShareUnassignedCases = (state: ShareCasesState) => state.shareUnassignedCases;
+export const getShareCases = (state: ShareCasesState) => state.shareCases;
export const getOrganisationUsers = (state: ShareCasesState) => state.users;
diff --git a/src/cases/store/selectors/caa-cases.selector.ts b/src/cases/store/selectors/caa-cases.selector.ts
index 83966be27..c01937379 100644
--- a/src/cases/store/selectors/caa-cases.selector.ts
+++ b/src/cases/store/selectors/caa-cases.selector.ts
@@ -7,33 +7,18 @@ export const getCaaCasesState = createSelector(
(state: fromFeature.CaaCasesState) => state.caaCases
);
-export const getAllAssignedCases = createSelector(
+export const getAllCases = createSelector(
getCaaCasesState,
- (caaCases) => caaCases.assignedCases
+ (caaCases) => caaCases.Cases
);
-export const getAllAssignedCasesError = createSelector(
+export const getAllCasesError = createSelector(
getCaaCasesState,
- fromFeature.getAssignedCasesError
+ fromFeature.getCasesError
);
-export const getAllAssignedCaseData = createSelector(
- getAllAssignedCases,
- (caaCases) => caaCases ? caaCases.data : null
-);
-
-export const getAllUnassignedCases = createSelector(
- getCaaCasesState,
- (caaCases) => caaCases.unassignedCases
-);
-
-export const getAllUnassignedCasesError = createSelector(
- getCaaCasesState,
- fromFeature.getUnassignedCasesError
-);
-
-export const getAllUnassignedCaseData = createSelector(
- getAllUnassignedCases,
+export const getAllCaseData = createSelector(
+ getAllCases,
(caaCases) => caaCases ? caaCases.data : null
);
diff --git a/src/cases/store/selectors/share-case.selector.ts b/src/cases/store/selectors/share-case.selector.ts
index 289872492..f3fb185e0 100644
--- a/src/cases/store/selectors/share-case.selector.ts
+++ b/src/cases/store/selectors/share-case.selector.ts
@@ -7,14 +7,9 @@ export const getCaseShareState = createSelector(
(state: fromFeature.CaaCasesState) => state.caseShare
);
-export const getShareAssignedCaseListState = createSelector(
+export const getShareCaseListState = createSelector(
getCaseShareState,
- fromFeature.getShareAssignedCases
-);
-
-export const getShareUnassignedCaseListState = createSelector(
- getCaseShareState,
- fromFeature.getShareUnassignedCases
+ fromFeature.getShareCases
);
export const getOrganisationUsersState = createSelector(
From b56c6cde0002c55031b87d78e4c2f2ee55654577 Mon Sep 17 00:00:00 2001
From: Josh
Date: Tue, 18 Feb 2025 10:46:55 +0000
Subject: [PATCH 14/44] WIP
---
package.json | 2 +-
.../case-share-complete.component.spec.ts | 4 +-
src/cases/containers/cases/cases.component.ts | 2 +-
.../store/actions/caa-cases.actions.spec.ts | 46 ++++----
.../store/actions/share-case.action.spec.ts | 106 ++++++++---------
.../store/effects/caa-cases.effects.spec.ts | 72 +++---------
.../store/effects/share-case.effects.spec.ts | 107 ++++--------------
.../store/reducers/caa-cases.reducer.spec.ts | 31 +----
.../store/reducers/share-case.reducer.spec.ts | 100 ++++++++--------
.../selectors/caa-cases.selector.spec.ts | 22 ++--
.../selectors/share-case.selectors.spec.ts | 13 ++-
src/cases/util/caa-cases.util.spec.ts | 3 +-
yarn.lock | 17 +--
13 files changed, 201 insertions(+), 324 deletions(-)
diff --git a/package.json b/package.json
index cb29b2be3..bad31df5e 100644
--- a/package.json
+++ b/package.json
@@ -81,7 +81,7 @@
"@hmcts/media-viewer": "4.0.4",
"@hmcts/nodejs-healthcheck": "1.7.0",
"@hmcts/properties-volume": "0.0.13",
- "@hmcts/rpx-xui-common-lib": "2.0.29",
+ "@hmcts/rpx-xui-common-lib": "link:../rpx-xui-common-lib/dist/exui-common-lib",
"@hmcts/rpx-xui-node-lib": "2.29.1",
"@ng-idle/core": "^14.0.0",
"@ng-idle/keepalive": "^14.0.0",
diff --git a/src/cases/containers/case-share-complete/case-share-complete.component.spec.ts b/src/cases/containers/case-share-complete/case-share-complete.component.spec.ts
index 51c760c11..57c4df5ae 100644
--- a/src/cases/containers/case-share-complete/case-share-complete.component.spec.ts
+++ b/src/cases/containers/case-share-complete/case-share-complete.component.spec.ts
@@ -180,7 +180,7 @@ describe('CaseShareCompleteComponent', () => {
component.ngOnInit();
component.completeScreenMode = 'COMPLETE';
fixture.detectChanges();
- expect(component.isFromAssignedCasesRoute).toBe(true);
+ expect(component.pageType).toBe('assigned-cases');
const successTextAssignedCases1 = fixture.debugElement.nativeElement.querySelector('#what-happens-next-added');
expect(successTextAssignedCases1).toBeTruthy();
expect(successTextAssignedCases1.textContent).toContain('The people you added');
@@ -197,7 +197,7 @@ describe('CaseShareCompleteComponent', () => {
component.ngOnInit();
component.completeScreenMode = 'COMPLETE';
fixture.detectChanges();
- expect(component.isFromAssignedCasesRoute).toBe(false);
+ expect(component.pageType).toBe('unassgined-cases');
const successTextAssignedCases1 = fixture.debugElement.nativeElement.querySelector('#what-happens-next-added');
expect(successTextAssignedCases1).toBeNull();
const successTextAssignedCases2 = fixture.debugElement.nativeElement.querySelector('#what-happens-next-removed');
diff --git a/src/cases/containers/cases/cases.component.ts b/src/cases/containers/cases/cases.component.ts
index eac5690f5..80594b342 100644
--- a/src/cases/containers/cases/cases.component.ts
+++ b/src/cases/containers/cases/cases.component.ts
@@ -47,7 +47,7 @@ export class CasesComponent implements OnInit {
public cases: any; // can we type this?
public casesError$: Observable;
public caseResultsTableShareButtonText: string = 'Share cases';
- private selectedCases: any[] = [];
+ public selectedCases: any[] = [];
constructor(private readonly caaCasesStore: Store,
private readonly organisationStore: Store,
diff --git a/src/cases/store/actions/caa-cases.actions.spec.ts b/src/cases/store/actions/caa-cases.actions.spec.ts
index ef002b0c7..9be55981f 100644
--- a/src/cases/store/actions/caa-cases.actions.spec.ts
+++ b/src/cases/store/actions/caa-cases.actions.spec.ts
@@ -4,67 +4,69 @@ import { CaaCases } from '../../models/caa-cases.model';
import * as fromActions from './caa-cases.actions';
describe('Caa actions', () => {
- it('load assigned cases action', () => {
+ it('load cases action', () => {
const caseType = 'caseTypeId1';
const pageNo = 1;
const pageSize = 10;
const caaCasesFilterType = null;
const caaCasesFilterValue = null;
- const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
- const action = new fromActions.LoadAssignedCases(payload);
+ const caaCasesPage = 'assigned-cases';
+ const payload = { caseType, pageNo, pageSize, caaCasesPage, caaCasesFilterType, caaCasesFilterValue };
+ const action = new fromActions.LoadCases(payload);
expect({ ...action }).toEqual({
payload,
- type: fromActions.LOAD_ASSIGNED_CASES
+ type: fromActions.LOAD_CASES
});
});
- it('load assigned cases success action', () => {
+ it('load cases success action', () => {
const payload = {} as CaaCases;
- const action = new fromActions.LoadAssignedCasesSuccess(payload);
+ const action = new fromActions.LoadCasesSuccess(payload);
expect({ ...action }).toEqual({
payload,
- type: fromActions.LOAD_ASSIGNED_CASES_SUCCESS
+ type: fromActions.LOAD_CASES_SUCCESS
});
});
- it('load assigned cases failure action', () => {
- const payload = new HttpErrorResponse({ error: 'assigned cases error' });
- const action = new fromActions.LoadAssignedCasesFailure(payload);
+ it('load cases failure action', () => {
+ const payload = new HttpErrorResponse({ error: ' cases error' });
+ const action = new fromActions.LoadCasesFailure(payload);
expect({ ...action }).toEqual({
payload,
- type: fromActions.LOAD_ASSIGNED_CASES_FAILURE
+ type: fromActions.LOAD_CASES_FAILURE
});
});
- it('load unassigned cases action', () => {
+ it('load un cases action', () => {
const caseType = 'caseTypeId1';
const pageNo = 1;
const pageSize = 10;
const caaCasesFilterType = null;
const caaCasesFilterValue = null;
- const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
- const action = new fromActions.LoadUnassignedCases(payload);
+ const caaCasesPage = 'assigned-cases';
+ const payload = { caseType, pageNo, pageSize, caaCasesPage, caaCasesFilterType, caaCasesFilterValue };
+ const action = new fromActions.LoadCases(payload);
expect({ ...action }).toEqual({
payload,
- type: fromActions.LOAD_UNASSIGNED_CASES
+ type: fromActions.LOAD_CASES
});
});
- it('load unassigned cases success action', () => {
+ it('load un cases success action', () => {
const payload = {} as CaaCases;
- const action = new fromActions.LoadUnassignedCasesSuccess(payload);
+ const action = new fromActions.LoadCasesSuccess(payload);
expect({ ...action }).toEqual({
payload,
- type: fromActions.LOAD_UNASSIGNED_CASES_SUCCESS
+ type: fromActions.LOAD_CASES_SUCCESS
});
});
- it('load unassigned cases failure action', () => {
- const payload = new HttpErrorResponse({ error: 'unassigned cases error' });
- const action = new fromActions.LoadUnassignedCasesFailure(payload);
+ it('load un cases failure action', () => {
+ const payload = new HttpErrorResponse({ error: 'un cases error' });
+ const action = new fromActions.LoadCasesFailure(payload);
expect({ ...action }).toEqual({
payload,
- type: fromActions.LOAD_UNASSIGNED_CASES_FAILURE
+ type: fromActions.LOAD_CASES_FAILURE
});
});
diff --git a/src/cases/store/actions/share-case.action.spec.ts b/src/cases/store/actions/share-case.action.spec.ts
index 3775c8238..505696507 100644
--- a/src/cases/store/actions/share-case.action.spec.ts
+++ b/src/cases/store/actions/share-case.action.spec.ts
@@ -1,92 +1,92 @@
import * as fromCaseShare from './share-case.action';
describe('Case Share Actions', () => {
- it('NavigateToShareAssignedCases', () => {
+ it('NavigateToShareCases', () => {
const payload = [];
- const action = new fromCaseShare.NavigateToShareAssignedCases(payload);
+ const action = new fromCaseShare.NavigateToShareCases(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.NAVIGATE_TO_SHARE_ASSIGNED_CASES,
+ type: fromCaseShare.NAVIGATE_TO_SHARE_CASES,
payload
});
});
- it('NavigateToShareUnassignedCases', () => {
+ it('NavigateToShareCases', () => {
const payload = [];
- const action = new fromCaseShare.NavigateToShareUnassignedCases(payload);
+ const action = new fromCaseShare.NavigateToShareCases(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.NAVIGATE_TO_SHARE_UNASSIGNED_CASES,
+ type: fromCaseShare.NAVIGATE_TO_SHARE_CASES,
payload
});
});
- it('SynchronizeStateToStoreAssignedCases', () => {
+ it('SynchronizeStateToStoreCases', () => {
const payload = [];
- const action = new fromCaseShare.SynchronizeStateToStoreAssignedCases(payload);
+ const action = new fromCaseShare.SynchronizeStateToStoreCases(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.SYNCHRONIZE_STATE_TO_STORE_ASSIGNED_CASES,
+ type: fromCaseShare.SYNCHRONIZE_STATE_TO_STORE_CASES,
payload
});
});
- it('SynchronizeStateToStoreUnassignedCases', () => {
+ it('SynchronizeStateToStoreCases', () => {
const payload = [];
- const action = new fromCaseShare.SynchronizeStateToStoreUnassignedCases(payload);
+ const action = new fromCaseShare.SynchronizeStateToStoreCases(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.SYNCHRONIZE_STATE_TO_STORE_UNASSIGNED_CASES,
+ type: fromCaseShare.SYNCHRONIZE_STATE_TO_STORE_CASES,
payload
});
});
- it('LoadShareAssignedCases', () => {
+ it('LoadShareCases', () => {
const payload = [];
- const action = new fromCaseShare.LoadShareAssignedCases(payload);
+ const action = new fromCaseShare.LoadShareCases(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.LOAD_SHARE_ASSIGNED_CASES,
+ type: fromCaseShare.LOAD_SHARE_CASES,
payload
});
});
- it('LoadShareAssignedCasesSuccess', () => {
+ it('LoadShareCasesSuccess', () => {
const payload = [];
- const action = new fromCaseShare.LoadShareAssignedCasesSuccess(payload);
+ const action = new fromCaseShare.LoadShareCasesSuccess(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.LOAD_SHARE_ASSIGNED_CASES_SUCCESS,
+ type: fromCaseShare.LOAD_SHARE_CASES_SUCCESS,
payload
});
});
- it('LoadShareAssignedCaseFailure', () => {
+ it('LoadShareCaseFailure', () => {
const payload: Error = new Error();
- const action = new fromCaseShare.LoadShareAssignedCaseFailure(payload);
+ const action = new fromCaseShare.LoadShareCaseFailure(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.LOAD_SHARE_ASSIGNED_CASES_FAILURE,
+ type: fromCaseShare.LOAD_SHARE_CASES_FAILURE,
payload
});
});
- it('LoadShareUnassignedCases', () => {
+ it('LoadShareCases', () => {
const payload = [];
- const action = new fromCaseShare.LoadShareUnassignedCases(payload);
+ const action = new fromCaseShare.LoadShareCases(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.LOAD_SHARE_UNASSIGNED_CASES,
+ type: fromCaseShare.LOAD_SHARE_CASES,
payload
});
});
- it('LoadShareUnassignedAssignedCasesSuccess', () => {
+ it('LoadShareCasesSuccess', () => {
const payload = [];
- const action = new fromCaseShare.LoadShareUnassignedCasesSuccess(payload);
+ const action = new fromCaseShare.LoadShareCasesSuccess(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.LOAD_SHARE_UNASSIGNED_CASES_SUCCESS,
+ type: fromCaseShare.LOAD_SHARE_CASES_SUCCESS,
payload
});
});
- it('LoadShareUnassignedCaseFailure', () => {
+ it('LoadShareCaseFailure', () => {
const payload: Error = new Error();
- const action = new fromCaseShare.LoadShareUnassignedCaseFailure(payload);
+ const action = new fromCaseShare.LoadShareCaseFailure(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.LOAD_SHARE_UNASSIGNED_CASES_FAILURE,
+ type: fromCaseShare.LOAD_SHARE_CASES_FAILURE,
payload
});
});
@@ -98,88 +98,88 @@ describe('Case Share Actions', () => {
});
});
- it('AddShareAssignedCases', () => {
+ it('AddShareCases', () => {
const payload = {
sharedCases: []
};
- const action = new fromCaseShare.AddShareAssignedCases(payload);
+ const action = new fromCaseShare.AddShareCases(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.ADD_SHARE_ASSIGNED_CASES,
+ type: fromCaseShare.ADD_SHARE_CASES,
payload
});
});
- it('AddShareAssignedCaseGo', () => {
+ it('AddShareCaseGo', () => {
const payload = {
path: [],
sharedCases: []
};
- const action = new fromCaseShare.AddShareAssignedCaseGo(payload);
+ const action = new fromCaseShare.AddShareCaseGo(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.ADD_SHARE_ASSIGNED_CASES_GO,
+ type: fromCaseShare.ADD_SHARE_CASES_GO,
payload
});
});
- it('AddShareUnassignedCases', () => {
+ it('AddShareCases', () => {
const payload = {
sharedCases: []
};
- const action = new fromCaseShare.AddShareUnassignedCases(payload);
+ const action = new fromCaseShare.AddShareCases(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.ADD_SHARE_UNASSIGNED_CASES,
+ type: fromCaseShare.ADD_SHARE_CASES,
payload
});
});
- it('AddShareUnassignedCaseGo', () => {
+ it('AddShareCaseGo', () => {
const payload = {
path: [],
sharedCases: []
};
- const action = new fromCaseShare.AddShareUnassignedCaseGo(payload);
+ const action = new fromCaseShare.AddShareCaseGo(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.ADD_SHARE_UNASSIGNED_CASES_GO,
+ type: fromCaseShare.ADD_SHARE_CASES_GO,
payload
});
});
- it('DeleteAShareAssignedCase', () => {
+ it('DeleteAShareCase', () => {
const payload = {
caseId: '1'
};
- const action = new fromCaseShare.DeleteAShareAssignedCase(payload);
+ const action = new fromCaseShare.DeleteAShareCase(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.DELETE_A_SHARE_ASSIGNED_CASE,
+ type: fromCaseShare.DELETE_A_SHARE_CASE,
payload
});
});
- it('DeleteAShareUnassignedCase', () => {
+ it('DeleteAShareCase', () => {
const payload = {
caseId: '1'
};
- const action = new fromCaseShare.DeleteAShareUnassignedCase(payload);
+ const action = new fromCaseShare.DeleteAShareCase(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.DELETE_A_SHARE_UNASSIGNED_CASE,
+ type: fromCaseShare.DELETE_A_SHARE_CASE,
payload
});
});
it('AssignUsersToAssignedCase', () => {
const payload = [];
- const action = new fromCaseShare.AssignUsersToAssignedCase(payload);
+ const action = new fromCaseShare.AssignUsersToCase(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.ASSIGN_USERS_TO_ASSIGNED_CASE,
+ type: fromCaseShare.ASSIGN_USERS_TO_CASE,
payload
});
});
- it('AssignUsersToUnassignedCase', () => {
+ it('AssignUsersToCase', () => {
const payload = [];
- const action = new fromCaseShare.AssignUsersToUnassignedCase(payload);
+ const action = new fromCaseShare.AssignUsersToCase(payload);
expect({ ...action }).toEqual({
- type: fromCaseShare.ASSIGN_USERS_TO_UNASSIGNED_CASE,
+ type: fromCaseShare.ASSIGN_USERS_TO_CASE,
payload
});
});
diff --git a/src/cases/store/effects/caa-cases.effects.spec.ts b/src/cases/store/effects/caa-cases.effects.spec.ts
index 55e320545..9534cbe4a 100644
--- a/src/cases/store/effects/caa-cases.effects.spec.ts
+++ b/src/cases/store/effects/caa-cases.effects.spec.ts
@@ -16,8 +16,7 @@ describe('CaaCasesEffects', () => {
let effects: CaaCasesEffects;
const caaCasesServiceMock = jasmine.createSpyObj('CaaCasesService', ['getCaaCases', 'getCaaCaseTypes']);
const loggerServiceMock = jasmine.createSpyObj('LoggerService', ['error']);
- const assignedCases = {} as CaaCases;
- const unassignedCases = {} as CaaCases;
+ const cases = {} as CaaCases;
const navItems = [] as NavItemModel[];
beforeEach(() => {
@@ -35,23 +34,24 @@ describe('CaaCasesEffects', () => {
addMatchers();
});
- describe('loadAssignedCases$', () => {
- it('loadAssignedCases successful', () => {
- caaCasesServiceMock.getCaaCases.and.returnValue(of(assignedCases));
+ describe('loadCases$', () => {
+ it('loadCases successful', () => {
+ caaCasesServiceMock.getCaaCases.and.returnValue(of(cases));
const caseType = '';
const pageNo = 1;
const pageSize = 10;
const caaCasesFilterType = null;
const caaCasesFilterValue = null;
- const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
- const action = new caaCasesActions.LoadAssignedCases(payload);
- const completion = new caaCasesActions.LoadAssignedCasesSuccess(assignedCases);
+ const caaCasesPage = CaaCasesPageType.AssignedCases;
+ const payload = { caseType, pageNo, pageSize, caaCasesPage, caaCasesFilterType, caaCasesFilterValue };
+ const action = new caaCasesActions.LoadCases(payload);
+ const completion = new caaCasesActions.LoadCasesSuccess(cases);
actions$ = hot('-a', { a: action });
const expected = cold('-b', { b: completion });
- expect(effects.loadAssignedCases$).toBeObservable(expected);
+ expect(effects.loadCases$).toBeObservable(expected);
});
- it('loadAssignedCases error', () => {
+ it('loadCases error', () => {
const error: HttpErrorResponse = {
error: 'Error',
status: 400,
@@ -69,55 +69,13 @@ describe('CaaCasesEffects', () => {
const pageSize = 10;
const caaCasesFilterType = null;
const caaCasesFilterValue = null;
- const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
- const action = new caaCasesActions.LoadAssignedCases(payload);
- const completion = new caaCasesActions.LoadAssignedCasesFailure(error);
+ const caaCasesPage = CaaCasesPageType.AssignedCases;
+ const payload = { caseType, pageNo, pageSize, caaCasesPage, caaCasesFilterType, caaCasesFilterValue };
+ const action = new caaCasesActions.LoadCases(payload);
+ const completion = new caaCasesActions.LoadCasesFailure(error);
actions$ = hot('-a', { a: action });
const expected = cold('-b', { b: completion });
- expect(effects.loadAssignedCases$).toBeObservable(expected);
- });
- });
-
- describe('loadUnassignedCases$', () => {
- it('loadUnassignedCases successful', () => {
- caaCasesServiceMock.getCaaCases.and.returnValue(of(unassignedCases));
- const caseType = '';
- const pageNo = 1;
- const pageSize = 10;
- const caaCasesFilterType = null;
- const caaCasesFilterValue = null;
- const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
- const action = new caaCasesActions.LoadUnassignedCases(payload);
- const completion = new caaCasesActions.LoadUnassignedCasesSuccess(unassignedCases);
- actions$ = hot('-a', { a: action });
- const expected = cold('-b', { b: completion });
- expect(effects.loadUnassignedCases$).toBeObservable(expected);
- });
-
- it('loadUnassignedCases error', () => {
- const error: HttpErrorResponse = {
- error: 'Error',
- status: 400,
- message: 'Error',
- headers: null,
- statusText: null,
- name: null,
- ok: false,
- type: null,
- url: null
- };
- caaCasesServiceMock.getCaaCases.and.returnValue(throwError(error));
- const caseType = '';
- const pageNo = 1;
- const pageSize = 10;
- const caaCasesFilterType = null;
- const caaCasesFilterValue = null;
- const payload = { caseType, pageNo, pageSize, caaCasesFilterType, caaCasesFilterValue };
- const action = new caaCasesActions.LoadUnassignedCases(payload);
- const completion = new caaCasesActions.LoadUnassignedCasesFailure(error);
- actions$ = hot('-a', { a: action });
- const expected = cold('-b', { b: completion });
- expect(effects.loadUnassignedCases$).toBeObservable(expected);
+ expect(effects.loadCases$).toBeObservable(expected);
});
});
diff --git a/src/cases/store/effects/share-case.effects.spec.ts b/src/cases/store/effects/share-case.effects.spec.ts
index 80f45974f..2950ec7d0 100644
--- a/src/cases/store/effects/share-case.effects.spec.ts
+++ b/src/cases/store/effects/share-case.effects.spec.ts
@@ -8,18 +8,12 @@ import { addMatchers, cold, hot, initTestScheduler } from 'jasmine-marbles';
import { of } from 'rxjs';
import { CaseShareService } from '../../services';
import {
- AddShareAssignedCaseGo,
- AddShareAssignedCases,
- AddShareUnassignedCaseGo,
- AddShareUnassignedCases,
- AssignUsersToAssignedCase,
- AssignUsersToAssignedCaseSuccess,
- AssignUsersToUnassignedCase,
- AssignUsersToUnassignedCaseSuccess,
- LoadShareAssignedCases,
- LoadShareAssignedCasesSuccess,
- LoadShareUnassignedCases,
- LoadShareUnassignedCasesSuccess,
+ AddShareCaseGo,
+ AddShareCases,
+ AssignUsersToCase,
+ AssignUsersToCaseSuccess,
+ LoadShareCases,
+ LoadShareCasesSuccess,
LoadUserFromOrgForCase,
LoadUserFromOrgForCaseSuccess
} from '../actions';
@@ -67,14 +61,14 @@ describe('Share Case Effects', () => {
addMatchers();
}));
- describe('addShareAssignedCases$', () => {
+ describe('addShareCases$', () => {
it('should add share assigned case action', () => {
- const action = new AddShareAssignedCases({
+ const action = new AddShareCases({
sharedCases: [
{ caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
{ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
});
- const completion = new AddShareAssignedCaseGo({
+ const completion = new AddShareCaseGo({
path: ['/unassigned-cases/case-share'],
sharedCases: [
{ caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
@@ -82,30 +76,11 @@ describe('Share Case Effects', () => {
});
actions$ = hot('-a', { a: action });
const expected = cold('-b', { b: completion });
- expect(effects.addShareAssignedCases$).toBeObservable(expected);
+ expect(effects.addShareCases$).toBeObservable(expected);
});
});
- describe('addShareUnassignedCases$', () => {
- it('should add share unassigned case action', () => {
- const action = new AddShareUnassignedCases({
- sharedCases: [
- { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
- { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
- });
- const completion = new AddShareUnassignedCaseGo({
- path: ['/unassigned-cases/case-share'],
- sharedCases: [
- { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
- { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
- });
- actions$ = hot('-a', { a: action });
- const expected = cold('-b', { b: completion });
- expect(effects.addShareUnassignedCases$).toBeObservable(expected);
- });
- });
-
- describe('navigateToAddShareAssignedCase$', () => {
+ describe('navigateToAddShareCase$', () => {
it('should add share assigned case go', () => {
const payload = {
path: ['/unassigned-cases/case-share'],
@@ -114,50 +89,16 @@ describe('Share Case Effects', () => {
{ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
};
routerMock.navigate.and.returnValue(Promise.resolve(true));
- const action = new AddShareAssignedCaseGo(payload);
+ const action = new AddShareCaseGo(payload);
actions$ = hot('-a', { a: action });
- effects.navigateToAddShareAssignedCase$.subscribe(() => {
+ effects.navigateToAddShareCase$.subscribe(() => {
expect(routerMock.navigate).toHaveBeenCalled();
});
});
});
- describe('navigateToAddShareUnassignedCase$', () => {
- it('should add share unassigned case go', () => {
- const payload = {
- path: ['/unassigned-cases/case-share'],
- sharedCases: [
- { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
- { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }]
- };
- routerMock.navigate.and.returnValue(Promise.resolve(true));
- const action = new AddShareUnassignedCaseGo(payload);
- actions$ = hot('-a', { a: action });
- effects.navigateToAddShareUnassignedCase$.subscribe(() => {
- expect(routerMock.navigate).toHaveBeenCalled();
- });
- });
- });
-
- describe('loadShareAssignedCases$', () => {
- it('should load share assigned cases', () => {
- const requestPayload = [
- { caseId: '1', caseTitle: 'James123' },
- { caseId: '2', caseTitle: 'Steve321' }];
- const returnPayload = [
- { caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
- { caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }];
- caseShareServiceMock.getShareCases.and.returnValue(of(returnPayload));
- const action = new LoadShareAssignedCases(requestPayload);
- const completion = new LoadShareAssignedCasesSuccess(returnPayload);
- actions$ = hot('-a', { a: action });
- const expected = cold('-b', { b: completion });
- expect(effects.loadShareAssignedCases$).toBeObservable(expected);
- });
- });
-
- describe('loadShareUnassignedCases$', () => {
- it('should load share unassigned cases', () => {
+ describe('loadShareCases$', () => {
+ it('should load share cases', () => {
const requestPayload = [
{ caseId: '1', caseTitle: 'James123' },
{ caseId: '2', caseTitle: 'Steve321' }];
@@ -165,11 +106,11 @@ describe('Share Case Effects', () => {
{ caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
{ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }];
caseShareServiceMock.getShareCases.and.returnValue(of(returnPayload));
- const action = new LoadShareUnassignedCases(requestPayload);
- const completion = new LoadShareUnassignedCasesSuccess(returnPayload);
+ const action = new LoadShareCases(requestPayload);
+ const completion = new LoadShareCasesSuccess(returnPayload);
actions$ = hot('-a', { a: action });
const expected = cold('-b', { b: completion });
- expect(effects.loadShareUnassignedCases$).toBeObservable(expected);
+ expect(effects.loadShareCases$).toBeObservable(expected);
});
});
@@ -222,11 +163,11 @@ describe('Share Case Effects', () => {
{ caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
{ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }];
caseShareServiceMock.assignUsersWithCases.and.returnValue(of(returnPayload));
- const action = new AssignUsersToAssignedCase(requestPayload);
- const completion = new AssignUsersToAssignedCaseSuccess(returnPayload);
+ const action = new AssignUsersToCase(requestPayload);
+ const completion = new AssignUsersToCaseSuccess(returnPayload);
actions$ = hot('-a', { a: action });
const expected = cold('-b', { b: completion });
- expect(effects.assignUsersToAssignedCases$).toBeObservable(expected);
+ expect(effects.assignUsersToCases$).toBeObservable(expected);
});
});
@@ -255,11 +196,11 @@ describe('Share Case Effects', () => {
{ caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
{ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }];
caseShareServiceMock.assignUsersWithCases.and.returnValue(of(returnPayload));
- const action = new AssignUsersToUnassignedCase(requestPayload);
- const completion = new AssignUsersToUnassignedCaseSuccess(returnPayload);
+ const action = new AssignUsersToCase(requestPayload);
+ const completion = new AssignUsersToCaseSuccess(returnPayload);
actions$ = hot('-a', { a: action });
const expected = cold('-b', { b: completion });
- expect(effects.assignUsersToUnassignedCases$).toBeObservable(expected);
+ expect(effects.assignUsersToCases$).toBeObservable(expected);
});
});
});
diff --git a/src/cases/store/reducers/caa-cases.reducer.spec.ts b/src/cases/store/reducers/caa-cases.reducer.spec.ts
index 41ec429b7..c71b75083 100644
--- a/src/cases/store/reducers/caa-cases.reducer.spec.ts
+++ b/src/cases/store/reducers/caa-cases.reducer.spec.ts
@@ -4,20 +4,14 @@ import * as fromCaaCasesReducer from './caa-cases.reducer';
describe('CaaCases Reducer', () => {
const initialState: fromCaaCasesReducer.CaaCasesState = {
- assignedCases: {
+ Cases: {
idField: 'id1',
columnConfigs: null,
data: null
},
- unassignedCases: {
- idField: 'id2',
- columnConfigs: null,
- data: null
- },
caseTypes: [],
selectedCases: {},
- assignedCasesLastError: new HttpErrorResponse({ error: 'assigned cases error' }),
- unassignedCasesLastError: new HttpErrorResponse({ error: 'unassigned cases error' })
+ CasesLastError: new HttpErrorResponse({ error: 'assigned cases error' })
};
it('should undefined action return default state', () => {
@@ -28,29 +22,16 @@ describe('CaaCases Reducer', () => {
});
it('should loadAssignedCasesSuccess action set correct state', () => {
- const action = new fromActions.LoadAssignedCasesSuccess(initialState.assignedCases);
+ const action = new fromActions.LoadCasesSuccess(initialState.Cases);
const state = fromCaaCasesReducer.caaCasesReducer(initialState, action);
- expect(state.assignedCases).toBe(initialState.assignedCases);
+ expect(state.Cases).toBe(initialState.Cases);
});
it('should LoadAssignedCasesFailure action set error', () => {
const error = new HttpErrorResponse({ error: 'assigned cases error' });
- const action = new fromActions.LoadAssignedCasesFailure(initialState.assignedCasesLastError);
- const state = fromCaaCasesReducer.caaCasesReducer(initialState, action);
- expect(state.assignedCasesLastError).toEqual(error);
- });
-
- it('should loadUnassignedCasesSuccess action set correct state', () => {
- const action = new fromActions.LoadUnassignedCasesSuccess(initialState.unassignedCases);
- const state = fromCaaCasesReducer.caaCasesReducer(initialState, action);
- expect(state.unassignedCases).toBe(initialState.unassignedCases);
- });
-
- it('should LoadUnassignedCasesFailure action set error', () => {
- const error = new HttpErrorResponse({ error: 'unassigned cases error' });
- const action = new fromActions.LoadUnassignedCasesFailure(initialState.unassignedCasesLastError);
+ const action = new fromActions.LoadCasesFailure(initialState.CasesLastError);
const state = fromCaaCasesReducer.caaCasesReducer(initialState, action);
- expect(state.unassignedCasesLastError).toEqual(error);
+ expect(state.CasesLastError).toEqual(error);
});
it('should loadCaseTypesSuccess action set correct state', () => {
diff --git a/src/cases/store/reducers/share-case.reducer.spec.ts b/src/cases/store/reducers/share-case.reducer.spec.ts
index d7e17ee4e..cf93b3872 100644
--- a/src/cases/store/reducers/share-case.reducer.spec.ts
+++ b/src/cases/store/reducers/share-case.reducer.spec.ts
@@ -14,39 +14,39 @@ describe('Share case reducer', () => {
const payload = {
sharedCases: []
};
- const action = new fromActions.AddShareAssignedCases(payload);
+ const action = new fromActions.AddShareCases(payload);
const state = fromReducer.shareCasesReducer(initialState, action);
- const mockState = { shareAssignedCases: [], shareUnassignedCases: [], loading: false, error: undefined, users: [] };
+ const mockState = { shareCases: [], loading: false, error: undefined, users: [] };
expect(state).toEqual(mockState);
});
it('should load state when navigate to share assigned case', () => {
const selectedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
- const action = new fromActions.NavigateToShareAssignedCases(selectedCases);
+ const action = new fromActions.NavigateToShareCases(selectedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(state.shareAssignedCases.length).toEqual(2);
+ expect(state.shareCases.length).toEqual(2);
});
it('should load state when navigate to share unassigned case', () => {
const selectedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
- const action = new fromActions.NavigateToShareUnassignedCases(selectedCases);
+ const action = new fromActions.NavigateToShareCases(selectedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(state.shareUnassignedCases.length).toEqual(2);
+ expect(state.shareCases.length).toEqual(2);
});
it('should load share assigned case', () => {
const selectedCases = [];
- const action = new fromActions.LoadShareAssignedCases(selectedCases);
+ const action = new fromActions.LoadShareCases(selectedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(state.shareAssignedCases.length).toEqual(0);
+ expect(state.shareCases.length).toEqual(0);
expect(state.loading).toBeTruthy();
});
it('should load share unassigned case', () => {
const selectedCases = [];
- const action = new fromActions.LoadShareUnassignedCases(selectedCases);
+ const action = new fromActions.LoadShareCases(selectedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(state.shareUnassignedCases.length).toEqual(0);
+ expect(state.shareCases.length).toEqual(0);
expect(state.loading).toBeTruthy();
});
@@ -58,9 +58,9 @@ describe('Share case reducer', () => {
{ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }
]
};
- const action = new fromActions.AddShareAssignedCaseGo(payload);
+ const action = new fromActions.AddShareCaseGo(payload);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(state.shareAssignedCases.length).toEqual(2);
+ expect(state.shareCases.length).toEqual(2);
});
it('should load share unassigned case', () => {
@@ -71,57 +71,57 @@ describe('Share case reducer', () => {
{ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }
]
};
- const action = new fromActions.AddShareUnassignedCaseGo(payload);
+ const action = new fromActions.AddShareCaseGo(payload);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(state.shareUnassignedCases.length).toEqual(2);
+ expect(state.shareCases.length).toEqual(2);
});
it('should load share assigned case with case type', () => {
initialState = {
- shareAssignedCases: [
+ shareCases: [
{ caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
{ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }
]
};
const caseFromNode = [{ caseId: '1', caseTitle: '' }, { caseId: '2', caseTitle: '' }];
- const action = new fromActions.LoadShareAssignedCasesSuccess(caseFromNode);
+ const action = new fromActions.LoadShareCasesSuccess(caseFromNode);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(state.shareAssignedCases.length).toEqual(2);
- expect(state.shareAssignedCases[0].caseTypeId).toEqual('type1');
- expect(state.shareAssignedCases[0].caseTitle).toEqual('James123');
+ expect(state.shareCases.length).toEqual(2);
+ expect(state.shareCases[0].caseTypeId).toEqual('type1');
+ expect(state.shareCases[0].caseTitle).toEqual('James123');
});
it('should load share unassigned case with case type', () => {
initialState = {
- shareUnassignedCases: [
+ shareCases: [
{ caseId: '1', caseTitle: 'James123', caseTypeId: 'type1' },
{ caseId: '2', caseTitle: 'Steve321', caseTypeId: 'type2' }
]
};
const caseFromNode = [{ caseId: '1', caseTitle: '' }, { caseId: '2', caseTitle: '' }];
- const action = new fromActions.LoadShareUnassignedCasesSuccess(caseFromNode);
+ const action = new fromActions.LoadShareCasesSuccess(caseFromNode);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(state.shareUnassignedCases.length).toEqual(2);
- expect(state.shareUnassignedCases[0].caseTypeId).toEqual('type1');
- expect(state.shareUnassignedCases[0].caseTitle).toEqual('James123');
+ expect(state.shareCases.length).toEqual(2);
+ expect(state.shareCases[0].caseTypeId).toEqual('type1');
+ expect(state.shareCases[0].caseTitle).toEqual('James123');
});
it('should save selected share assigned cases into store', () => {
const selectedCases = {
sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
};
- const action = new fromActions.AddShareAssignedCases(selectedCases);
+ const action = new fromActions.AddShareCases(selectedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(state.shareAssignedCases.length).toEqual(2);
+ expect(state.shareCases.length).toEqual(2);
});
it('should save selected share unassigned cases into store', () => {
const selectedCases = {
sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
};
- const action = new fromActions.AddShareUnassignedCases(selectedCases);
+ const action = new fromActions.AddShareCases(selectedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(state.shareUnassignedCases.length).toEqual(2);
+ expect(state.shareCases.length).toEqual(2);
});
it('should save selected share cases without duplication', () => {
@@ -131,91 +131,91 @@ describe('Share case reducer', () => {
const addedSelectedCases = {
sharedCases: [{ caseId: '2', caseTitle: 'Steve321' }, { caseId: '3', caseTitle: 'Kenny456' }]
};
- const oldAction = new fromActions.AddShareAssignedCases(selectedCases);
+ const oldAction = new fromActions.AddShareCases(selectedCases);
const oldState = fromReducer.shareCasesReducer(initialState, oldAction);
- const newAction = new fromActions.AddShareAssignedCases(addedSelectedCases);
+ const newAction = new fromActions.AddShareCases(addedSelectedCases);
const newState = fromReducer.shareCasesReducer(oldState, newAction);
- expect(newState.shareAssignedCases.length).toEqual(3);
+ expect(newState.shareCases.length).toEqual(3);
});
it('should delete an assigned case from store', () => {
const selectedCases = {
sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
};
- const oldAction = new fromActions.AddShareAssignedCases(selectedCases);
+ const oldAction = new fromActions.AddShareCases(selectedCases);
const oldState = fromReducer.shareCasesReducer(initialState, oldAction);
const payload = {
caseId: '1'
};
- const newAction = new fromActions.DeleteAShareAssignedCase(payload);
+ const newAction = new fromActions.DeleteAShareCase(payload);
const newState = fromReducer.shareCasesReducer(oldState, newAction);
- expect(newState.shareAssignedCases.length).toEqual(1);
+ expect(newState.shareCases.length).toEqual(1);
});
it('should delete an unassigned case from store', () => {
const selectedCases = {
sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
};
- const oldAction = new fromActions.AddShareUnassignedCases(selectedCases);
+ const oldAction = new fromActions.AddShareCases(selectedCases);
const oldState = fromReducer.shareCasesReducer(initialState, oldAction);
const payload = {
caseId: '1'
};
- const newAction = new fromActions.DeleteAShareUnassignedCase(payload);
+ const newAction = new fromActions.DeleteAShareCase(payload);
const newState = fromReducer.shareCasesReducer(oldState, newAction);
- expect(newState.shareUnassignedCases.length).toEqual(1);
+ expect(newState.shareCases.length).toEqual(1);
});
it('should get state properties for assigned cases', () => {
const selectedCases = {
sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
};
- const action = new fromActions.AddShareAssignedCases(selectedCases);
+ const action = new fromActions.AddShareCases(selectedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(fromReducer.getShareAssignedCases(state).length).toEqual(2);
+ expect(fromReducer.getShareCases(state).length).toEqual(2);
});
it('should get state properties for unassigned cases', () => {
const selectedCases = {
sharedCases: [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }]
};
- const action = new fromActions.AddShareUnassignedCases(selectedCases);
+ const action = new fromActions.AddShareCases(selectedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(fromReducer.getShareUnassignedCases(state).length).toEqual(2);
+ expect(fromReducer.getShareCases(state).length).toEqual(2);
});
it('should load user from org for case success', () => {
const sharedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
- const action = new fromActions.LoadShareAssignedCasesSuccess(sharedCases);
+ const action = new fromActions.LoadShareCasesSuccess(sharedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
expect(fromReducer.getOrganisationUsers(state)).toBeTruthy();
});
it('should synchronize state to store for assigned cases', () => {
const sharedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
- const action = new fromActions.SynchronizeStateToStoreAssignedCases(sharedCases);
+ const action = new fromActions.SynchronizeStateToStoreCases(sharedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(fromReducer.getShareAssignedCases(state).length).toEqual(2);
+ expect(fromReducer.getShareCases(state).length).toEqual(2);
});
it('should synchronize state to store for unassigned cases', () => {
const sharedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
- const action = new fromActions.SynchronizeStateToStoreUnassignedCases(sharedCases);
+ const action = new fromActions.SynchronizeStateToStoreCases(sharedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(fromReducer.getShareUnassignedCases(state).length).toEqual(2);
+ expect(fromReducer.getShareCases(state).length).toEqual(2);
});
it('should assign user to case success', () => {
const sharedCases = [{ caseId: '1', caseTitle: 'James123' }, { caseId: '2', caseTitle: 'Steve321' }];
- const action = new fromActions.AssignUsersToAssignedCaseSuccess(sharedCases);
+ const action = new fromActions.AssignUsersToCaseSuccess(sharedCases);
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(fromReducer.getShareAssignedCases(state).length).toEqual(2);
+ expect(fromReducer.getShareCases(state).length).toEqual(2);
});
it('should reset state if share case completed', () => {
- const action = new fromActions.ResetAssignedCaseSelection();
+ const action = new fromActions.ResetCaseSelection();
const state = fromReducer.shareCasesReducer(initialState, action);
- expect(fromReducer.getShareAssignedCases(state).length).toEqual(0);
+ expect(fromReducer.getShareCases(state).length).toEqual(0);
});
it('should sort users', () => {
diff --git a/src/cases/store/selectors/caa-cases.selector.spec.ts b/src/cases/store/selectors/caa-cases.selector.spec.ts
index 6bdb53907..a67cbcf45 100644
--- a/src/cases/store/selectors/caa-cases.selector.spec.ts
+++ b/src/cases/store/selectors/caa-cases.selector.spec.ts
@@ -3,11 +3,9 @@ import { select, Store, StoreModule } from '@ngrx/store';
import { reducers } from '../reducers';
import { CaaCasesState, initialState } from '../reducers/caa-cases.reducer';
import {
- getAllAssignedCases,
- getAllAssignedCasesError,
+ getAllCases,
+ getAllCasesError,
getAllCaseTypes,
- getAllUnassignedCases,
- getAllUnassignedCasesError,
getSelectedCases
} from './caa-cases.selector';
@@ -27,34 +25,34 @@ describe('CaaCases selectors', () => {
it('should return all assigned cases', () => {
let result;
- store.pipe(select(getAllAssignedCases)).subscribe((value) => {
+ store.pipe(select(getAllCases)).subscribe((value) => {
result = value;
});
- expect(result).toEqual(initialState.assignedCases);
+ expect(result).toEqual(initialState.Cases);
});
it('should return all assigned cases error', () => {
let result;
- store.pipe(select(getAllAssignedCasesError)).subscribe((value) => {
+ store.pipe(select(getAllCasesError)).subscribe((value) => {
result = value;
});
- expect(result).toEqual(initialState.assignedCasesLastError);
+ expect(result).toEqual(initialState.CasesLastError);
});
it('should return all unassigned cases', () => {
let result;
- store.pipe(select(getAllUnassignedCases)).subscribe((value) => {
+ store.pipe(select(getAllCases)).subscribe((value) => {
result = value;
});
- expect(result).toEqual(initialState.unassignedCases);
+ expect(result).toEqual(initialState.Cases);
});
it('should return all unassigned cases error', () => {
let result;
- store.pipe(select(getAllUnassignedCasesError)).subscribe((value) => {
+ store.pipe(select(getAllCasesError)).subscribe((value) => {
result = value;
});
- expect(result).toEqual(initialState.assignedCasesLastError);
+ expect(result).toEqual(initialState.CasesLastError);
});
it('should return all case types', () => {
diff --git a/src/cases/store/selectors/share-case.selectors.spec.ts b/src/cases/store/selectors/share-case.selectors.spec.ts
index b11b194d7..985ed91fb 100644
--- a/src/cases/store/selectors/share-case.selectors.spec.ts
+++ b/src/cases/store/selectors/share-case.selectors.spec.ts
@@ -4,15 +4,17 @@ import { RouterTestingModule } from '@angular/router/testing';
import { select, Store, StoreModule } from '@ngrx/store';
import { OrganisationState } from '../../../organisation/store';
import { UserState } from '../../../users/store';
-import { CaaCasesComponent } from '../../containers';
+import { CasesComponent } from '../../containers';
import { CaaCasesService } from '../../services';
-import { CaaCasesState, getShareAssignedCaseListState, reducers } from '../index';
+import { CaaCasesState, getShareCaseListState, reducers } from '../index';
+import { ChangeDetectorRef } from '@angular/core';
describe('Share case selectors', () => {
let store: Store;
let organisationStore: Store;
let userStore: Store;
let caaCasesService: jasmine.SpyObj;
+ let cdr: ChangeDetectorRef;
const router: any = {};
beforeEach(() => {
@@ -40,12 +42,13 @@ describe('Share case selectors', () => {
store = TestBed.inject(Store);
organisationStore = TestBed.inject(Store);
userStore = TestBed.inject(Store);
+ cdr = TestBed.inject(ChangeDetectorRef);
spyOn(store, 'dispatch').and.callThrough();
});
describe('get share case state', () => {
xit('should return search state', () => {
- const caseListComponent = new CaaCasesComponent(store, organisationStore, userStore, router, caaCasesService);
+ const caseListComponent = new CasesComponent(store, organisationStore, userStore, router, caaCasesService, cdr);
caseListComponent.selectedCases = [{
case_id: '1',
case_fields: {
@@ -57,9 +60,9 @@ describe('Share case selectors', () => {
solsSolicitorAppReference: 'Steve321'
}
}];
- caseListComponent.shareAssignedCaseSubmit();
+ //caseListComponent.shareAssignedCaseSubmit();
let result = [];
- store.pipe(select(getShareAssignedCaseListState)).subscribe((value) => {
+ store.pipe(select(getShareCaseListState)).subscribe((value) => {
result = value;
});
expect(result.length).toEqual(2);
diff --git a/src/cases/util/caa-cases.util.spec.ts b/src/cases/util/caa-cases.util.spec.ts
index bbd348a21..f5717d272 100644
--- a/src/cases/util/caa-cases.util.spec.ts
+++ b/src/cases/util/caa-cases.util.spec.ts
@@ -1,6 +1,7 @@
import { FormControl } from '@angular/forms';
import { User } from '@hmcts/rpx-xui-common-lib';
import { CaaCasesUtil } from './caa-cases.util';
+import { CaseTypesResultsResponse } from '../models/caa-cases.model';
describe('CaaCasesUtil', () => {
let control: FormControl;
@@ -31,7 +32,7 @@ describe('CaaCasesUtil', () => {
case_type_id: 'FT_ComplexOrganisation'
}
]
- };
+ } as CaseTypesResultsResponse;
const results = CaaCasesUtil.getCaaNavItems(response);
expect(results.length).toEqual(4);
expect(results[0].text).toEqual('FT_MasterCaseType');
diff --git a/yarn.lock b/yarn.lock
index fd7d21e29..f3d9f7a5e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2922,18 +2922,11 @@ __metadata:
languageName: node
linkType: hard
-"@hmcts/rpx-xui-common-lib@npm:2.0.29":
- version: 2.0.29
- resolution: "@hmcts/rpx-xui-common-lib@npm:2.0.29"
- dependencies:
- tslib: ^2.0.0
- peerDependencies:
- launchdarkly-js-client-sdk: ^3.3.0
- ngx-pagination: ^3.2.1
- rpx-xui-translation: ^0.1.1
- checksum: c6fa9dddbbcf714f92c44a1240ac50445ef5695255a8f66d4724894c7bf2426b834574f34acc8e13e38a5b6b936d7b15edf4bc1083d4fd9314f8e8863281dc4b
+"@hmcts/rpx-xui-common-lib@link:../rpx-xui-common-lib/dist/exui-common-lib::locator=rpx-xui-manage-organisations%40workspace%3A.":
+ version: 0.0.0-use.local
+ resolution: "@hmcts/rpx-xui-common-lib@link:../rpx-xui-common-lib/dist/exui-common-lib::locator=rpx-xui-manage-organisations%40workspace%3A."
languageName: node
- linkType: hard
+ linkType: soft
"@hmcts/rpx-xui-node-lib@npm:2.29.1":
version: 2.29.1
@@ -19750,7 +19743,7 @@ __metadata:
"@hmcts/media-viewer": 4.0.4
"@hmcts/nodejs-healthcheck": 1.7.0
"@hmcts/properties-volume": 0.0.13
- "@hmcts/rpx-xui-common-lib": 2.0.29
+ "@hmcts/rpx-xui-common-lib": "link:../rpx-xui-common-lib/dist/exui-common-lib"
"@hmcts/rpx-xui-node-lib": 2.29.1
"@ng-idle/core": ^14.0.0
"@ng-idle/keepalive": ^14.0.0
From 6ebdd42d9738c9fb2d659304f3ac4fd0846947be Mon Sep 17 00:00:00 2001
From: Josh
Date: Wed, 4 Jun 2025 10:26:15 +0100
Subject: [PATCH 15/44] fix tests
---
package.json | 2 +-
.../hmcts-global-footer.component.html | 2 +-
src/app/containers/app/app.component.html | 2 +-
.../cases-filter.component.spec.ts | 24 ++++++++++++++--
.../cases-results-table.component.spec.ts | 24 ++++++++++++++--
.../case-share-complete.component.html | 2 +-
.../case-share-complete.component.spec.ts | 2 +-
.../containers/cases/cases.component.spec.ts | 26 +++++++++++++++--
.../store/effects/share-case.effects.spec.ts | 2 +-
.../cases-filter.component.spec.ts | 26 +++++++++++++++--
.../cases-results-table.component.spec.ts | 28 ++++++++++++++++---
.../case-share-complete.component.html | 2 +-
.../case-share-complete.component.spec.ts | 2 +-
.../case-share-confirm.component.spec.ts | 4 +--
.../containers/cases/cases.component.spec.ts | 24 ++++++++++++++--
.../store/effects/share-case.effects.spec.ts | 2 +-
.../account-overview.component.html | 2 +-
.../containers/profile/profile.component.html | 4 +--
.../invite-user-success.component.html | 2 +-
.../containers/users/users.component.html | 2 +-
yarn.lock | 12 ++++----
21 files changed, 158 insertions(+), 38 deletions(-)
diff --git a/package.json b/package.json
index f633a3d62..4285bcd0c 100644
--- a/package.json
+++ b/package.json
@@ -82,7 +82,7 @@
"@hmcts/media-viewer": "4.1.0",
"@hmcts/nodejs-healthcheck": "1.7.0",
"@hmcts/properties-volume": "0.0.13",
- "@hmcts/rpx-xui-common-lib": "2.1.0",
+ "@hmcts/rpx-xui-common-lib": "2.1.0-uc-rc1",
"@hmcts/rpx-xui-node-lib": "2.30.6",
"@ng-idle/core": "^14.0.0",
"@ng-idle/keepalive": "^14.0.0",
diff --git a/src/app/components/hmcts-global-footer/hmcts-global-footer.component.html b/src/app/components/hmcts-global-footer/hmcts-global-footer.component.html
index 0bf4cbbae..d0ae3b141 100644
--- a/src/app/components/hmcts-global-footer/hmcts-global-footer.component.html
+++ b/src/app/components/hmcts-global-footer/hmcts-global-footer.component.html
@@ -1,5 +1,5 @@