Skip to content

Commit

Permalink
Merge pull request #1830 from bcgov/develop
Browse files Browse the repository at this point in the history
Deployment PR - 1287
  • Loading branch information
trslater authored Sep 9, 2024
2 parents 4f18b84 + 8c28adc commit 6c4462c
Show file tree
Hide file tree
Showing 33 changed files with 1,008 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class ApplicationSearchTableComponent {
@Input() totalCount: number | undefined;
@Input() statuses: ApplicationStatusDto[] = [];
@Input() regions: ApplicationRegionDto[] = [];
@Input() isCommissioner: boolean = false;

@Output() tableChange = new EventEmitter<TableChange>();

Expand Down Expand Up @@ -70,7 +71,9 @@ export class ApplicationSearchTableComponent {
}

onSelectRecord(record: SearchResult) {
const url = this.router.serializeUrl(this.router.createUrlTree([`/application/${record.referenceId}`]));
const url = this.isCommissioner
? this.router.serializeUrl(this.router.createUrlTree([`/commissioner/application/${record.referenceId}`]))
: this.router.serializeUrl(this.router.createUrlTree([`/application/${record.referenceId}`]));

window.open(url, '_blank');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,26 @@ import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { FileTypeDataSourceService } from '../../../services/search/file-type/file-type-data-source.service';

import { FileTypeFilterDropDownComponent } from './file-type-filter-drop-down.component';
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { AuthenticationService, ICurrentUser } from '../../../services/authentication/authentication.service';
import { BehaviorSubject, of } from 'rxjs';

describe('FileTypeFilterDropDownComponent', () => {
let component: FileTypeFilterDropDownComponent;
let fixture: ComponentFixture<FileTypeFilterDropDownComponent>;
let mockAuthenticationService: DeepMocked<AuthenticationService>;
let currentUser: BehaviorSubject<ICurrentUser | undefined>;

beforeEach(async () => {
mockAuthenticationService = createMock();
currentUser = new BehaviorSubject<ICurrentUser | undefined>(undefined);
await TestBed.configureTestingModule({
providers: [
{
provide: AuthenticationService,
useValue: mockAuthenticationService,
},
],
declarations: [FileTypeFilterDropDownComponent],
schemas: [NO_ERRORS_SCHEMA],
imports: [MatAutocompleteModule],
Expand All @@ -19,7 +32,8 @@ describe('FileTypeFilterDropDownComponent', () => {
fixture = TestBed.createComponent(FileTypeFilterDropDownComponent);
component = fixture.componentInstance;
component.label = 'Label';
component.fileTypeData = new FileTypeDataSourceService();
mockAuthenticationService.$currentUser = currentUser;
component.fileTypeData = new FileTypeDataSourceService(mockAuthenticationService);
fixture.detectChanges();
});

Expand Down
11 changes: 6 additions & 5 deletions alcs-frontend/src/app/features/search/search.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ <h4>Date Range</h4>

<div class="search-fields-wrapper search-result-wrapper" *ngIf="!searchResultsHidden">
<h2 class="search-title">Search Results:</h2>
<mat-tab-group id="results" mat-align-tabs="start" mat-stretch-tabs="false" #searchResultTabs>
<mat-tab-group id="results" mat-align-tabs="start" [mat-stretch-tabs]="isCommissioner" #searchResultTabs>
<mat-tab>
<ng-template mat-tab-label> Applications: {{ applicationTotal }}</ng-template>
<app-application-search-table
Expand All @@ -284,14 +284,15 @@ <h2 class="search-title">Search Results:</h2>
[statuses]="applicationStatuses"
[pageIndex]="pageIndex"
[regions]="regions"
[isCommissioner]="isCommissioner"
(tableChange)="onTableChange($event)"
></app-application-search-table>
<div class="center">
<mat-spinner class="spinner" *ngIf="isLoading"></mat-spinner>
</div>
</mat-tab>

<mat-tab>
<mat-tab *ngIf="!isCommissioner">
<ng-template mat-tab-label> Notice of Intent: {{ noticeOfIntentTotal }}</ng-template>
<app-notice-of-intent-search-table
*ngIf="!isLoading"
Expand All @@ -307,7 +308,7 @@ <h2 class="search-title">Search Results:</h2>
</div>
</mat-tab>

<mat-tab>
<mat-tab *ngIf="!isCommissioner">
<ng-template mat-tab-label> Planning Reviews: {{ planningReviewsTotal }}</ng-template>
<app-planning-review-search-table
*ngIf="!isLoading"
Expand All @@ -322,7 +323,7 @@ <h2 class="search-title">Search Results:</h2>
</div>
</mat-tab>

<mat-tab>
<mat-tab *ngIf="!isCommissioner">
<ng-template mat-tab-label> Notifications: {{ notificationTotal }}</ng-template>
<app-notification-search-table
[statuses]="notificationStatuses"
Expand All @@ -337,7 +338,7 @@ <h2 class="search-title">Search Results:</h2>
</div>
</mat-tab>

<mat-tab>
<mat-tab *ngIf="!isCommissioner">
<ng-template mat-tab-label> Inquiries: {{ inquiriesTotal }}</ng-template>
<app-inquiry-search-table
*ngIf="!isLoading"
Expand Down
11 changes: 10 additions & 1 deletion alcs-frontend/src/app/features/search/search.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { SearchService } from '../../services/search/search.service';
import { ToastService } from '../../services/toast/toast.service';

import { SearchComponent } from './search.component';
import { AuthenticationService, ICurrentUser } from '../../services/authentication/authentication.service';

describe('SearchComponent', () => {
let component: SearchComponent;
Expand All @@ -23,6 +24,8 @@ describe('SearchComponent', () => {
let mockApplicationService: DeepMocked<ApplicationService>;
let mockNotificationStatusService: DeepMocked<NotificationSubmissionStatusService>;
let mockNOIStatusService: DeepMocked<NotificationSubmissionStatusService>;
let mockAuthService: DeepMocked<AuthenticationService>;
let currentUser: BehaviorSubject<ICurrentUser | undefined>;

beforeEach(async () => {
mockSearchService = createMock();
Expand All @@ -31,8 +34,9 @@ describe('SearchComponent', () => {
mockApplicationService = createMock();
mockNotificationStatusService = createMock();
mockNOIStatusService = createMock();

mockAuthService = createMock();
mockApplicationService.$applicationRegions = new BehaviorSubject<ApplicationRegionDto[]>([]);
currentUser = new BehaviorSubject<ICurrentUser | undefined>(undefined);

await TestBed.configureTestingModule({
providers: [
Expand Down Expand Up @@ -66,12 +70,17 @@ describe('SearchComponent', () => {
provide: NoticeOfIntentSubmissionStatusService,
useValue: mockNOIStatusService,
},
{
provide: AuthenticationService,
useValue: mockAuthService,
},
],
declarations: [SearchComponent],
imports: [MatAutocompleteModule],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();

mockAuthService.$currentUser = currentUser;
fixture = TestBed.createComponent(SearchComponent);
component = fixture.componentInstance;
fixture.detectChanges();
Expand Down
22 changes: 21 additions & 1 deletion alcs-frontend/src/app/features/search/search.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { ToastService } from '../../services/toast/toast.service';
import { formatDateForApi } from '../../shared/utils/api-date-formatter';
import { FileTypeFilterDropDownComponent } from './file-type-filter-drop-down/file-type-filter-drop-down.component';
import { TableChange } from './search.interface';
import { AuthenticationService, ROLES } from '../../services/authentication/authentication.service';

export const defaultStatusBackgroundColour = '#ffffff';
export const defaultStatusColour = '#313132';
Expand Down Expand Up @@ -108,6 +109,7 @@ export class SearchComponent implements OnInit, OnDestroy {
noiStatuses: NoticeOfIntentStatusDto[] = [];
isLoading = false;
today = new Date();
isCommissioner = false;

constructor(
private searchService: SearchService,
Expand All @@ -118,6 +120,7 @@ export class SearchComponent implements OnInit, OnDestroy {
private applicationService: ApplicationService,
private toastService: ToastService,
private titleService: Title,
private authService: AuthenticationService,
public fileTypeService: FileTypeDataSourceService,
public portalStatusDataService: PortalStatusDataSourceService,
) {
Expand Down Expand Up @@ -163,6 +166,15 @@ export class SearchComponent implements OnInit, OnDestroy {
this.pidControl.valueChanges.pipe(takeUntil(this.$destroy)).subscribe(() => {
this.pidInvalid = this.pidControl.invalid && (this.pidControl.dirty || this.pidControl.touched);
});

this.authService.$currentUser.subscribe((currentUser) => {
if (currentUser) {
this.isCommissioner =
currentUser.client_roles && currentUser.client_roles.length === 1
? currentUser.client_roles.includes(ROLES.COMMISSIONER)
: false;
}
});
}

private setup() {
Expand Down Expand Up @@ -238,6 +250,14 @@ export class SearchComponent implements OnInit, OnDestroy {

getSearchParams(): SearchRequestDto {
const resolutionNumberString = this.formatStringSearchParam(this.searchForm.controls.resolutionNumber.value);
let fileTypes: string[];

if (this.searchForm.controls.componentType.value === null) {
fileTypes = this.isCommissioner ? this.fileTypeService.getCommissionerListData() : [];
} else {
fileTypes = this.searchForm.controls.componentType.value!;
}

return {
// pagination
pageSize: this.itemsPerPage,
Expand Down Expand Up @@ -268,7 +288,7 @@ export class SearchComponent implements OnInit, OnDestroy {
dateDecidedTo: this.searchForm.controls.dateDecidedTo.value
? formatDateForApi(this.searchForm.controls.dateDecidedTo.value)
: undefined,
fileTypes: this.searchForm.controls.componentType.value ? this.searchForm.controls.componentType.value : [],
fileTypes: fileTypes,
};
}

Expand Down
14 changes: 14 additions & 0 deletions alcs-frontend/src/app/services/incoming-file/incomig-file.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { CardType } from '../../shared/card/card.component';
import { AssigneeDto } from '../user/user.dto';

export type IncomingFileDto = {
fileNumber: string;
applicant: string;
boardCode: string;
assignee: AssigneeDto | null;
type: CardType;
highPriority: boolean;
activeDays: number;
};

export type IncomingFileBoardMapDto = Record<string, IncomingFileDto[]>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { IncomingFileService } from './incoming-file.service';
import { IncomingFileBoardMapDto } from './incomig-file.dto';
import { CardType } from '../../shared/card/card.component';
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { HttpClient } from '@angular/common/http';
import { ToastService } from '../toast/toast.service';
import { of } from 'rxjs';

describe('ApplicationIncomingFileService', () => {
let service: IncomingFileService;
let httpClient: DeepMocked<HttpClient>;
let toastService: DeepMocked<ToastService>;

beforeEach(() => {
httpClient = createMock();
toastService = createMock();

TestBed.configureTestingModule({
imports: [HttpClientTestingModule, MatSnackBarModule],
providers: [
{ provide: HttpClient, useValue: httpClient },
{ provide: ToastService, useValue: toastService },
],
});
service = TestBed.inject(IncomingFileService);
});

let unsortedFiles: IncomingFileBoardMapDto = {
'board-1': [
{
fileNumber: '1',
applicant: 'applicant',
boardCode: 'board-1',
type: CardType.APP,
assignee: null,
highPriority: false,
activeDays: 10,
},
{
fileNumber: '2',
applicant: 'applicant',
boardCode: 'board-1',
type: CardType.PLAN,
assignee: null,
highPriority: true,
activeDays: 12,
},
{
fileNumber: '3',
applicant: 'applicant',
boardCode: 'board-1',
type: CardType.APP,
assignee: null,
highPriority: true,
activeDays: 30,
},
],
};

let expectedSortedFiles: IncomingFileBoardMapDto = {
'board-1': [
{
fileNumber: '3',
applicant: 'applicant',
boardCode: 'board-1',
type: CardType.APP,
assignee: null,
highPriority: true,
activeDays: 30,
},
{
fileNumber: '2',
applicant: 'applicant',
boardCode: 'board-1',
type: CardType.PLAN,
assignee: null,
highPriority: true,
activeDays: 12,
},
{
fileNumber: '1',
applicant: 'applicant',
boardCode: 'board-1',
type: CardType.APP,
assignee: null,
highPriority: false,
activeDays: 10,
},
],
};

it('should be created', () => {
expect(service).toBeTruthy();
});

it('should call get for fetchingTypes', async () => {
httpClient.get.mockReturnValue(of(unsortedFiles));

const res = await service.fetch();
expect(httpClient.get).toHaveBeenCalledTimes(1);
expect(Object.keys(res!).length).toEqual(1);
});

it('should sort the incoming data based on priority and active days', async () => {
httpClient.get.mockReturnValue(of(unsortedFiles));

const res = await service.fetchAndSort();
expect(httpClient.get).toHaveBeenCalledTimes(1);
expect(res).toEqual(expectedSortedFiles);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Injectable } from '@angular/core';
import { environment } from '../../../environments/environment';
import { HttpClient } from '@angular/common/http';
import { ToastService } from '../toast/toast.service';
import { firstValueFrom } from 'rxjs';
import { IncomingFileBoardMapDto } from './incomig-file.dto';

@Injectable({
providedIn: 'root',
})
export class IncomingFileService {
private url = `${environment.apiUrl}/incoming-files`;

constructor(
private http: HttpClient,
private toastService: ToastService,
) {}

async fetch() {
try {
return await firstValueFrom(this.http.get<IncomingFileBoardMapDto>(`${this.url}`));
} catch (err) {
this.toastService.showErrorToast('Failed to fetch incoming files');
}
return;
}

async fetchAndSort() {
const incomingFiles = await this.fetch();

if (incomingFiles) {
Object.keys(incomingFiles!).forEach((board) => {
incomingFiles![board].sort((fileOne, fileTwo) => {
if (fileOne.highPriority !== fileTwo.highPriority) {
return fileOne.highPriority ? -1 : 1;
}
return fileTwo.activeDays - fileOne.activeDays;
});
});

return incomingFiles;
}

return;
}
}
Loading

0 comments on commit 6c4462c

Please sign in to comment.