From f95f7d0f6487f81564f1b61bf9540ad1b3192c8a Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 9 Jan 2025 08:28:38 -0800 Subject: [PATCH 01/20] TCVP-2962: Made contact language more generic --- .../dispute-submit-success.component.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/frontend/citizen-portal/src/app/components/dispute-submit-success/dispute-submit-success.component.html b/src/frontend/citizen-portal/src/app/components/dispute-submit-success/dispute-submit-success.component.html index ef74cb886..ba01d806d 100644 --- a/src/frontend/citizen-portal/src/app/components/dispute-submit-success/dispute-submit-success.component.html +++ b/src/frontend/citizen-portal/src/app/components/dispute-submit-success/dispute-submit-success.component.html @@ -28,8 +28,8 @@

Ticket request sent successfully

Next Steps

- A member of the court registry will review your request and you will receive an email to the address you supplied - which will inform you if the ticket request has been approved or rejected, and what to expect next. + A member of the court registry will review your request and inform you if the ticket request has been approved or + rejected, and what to expect next.

A confirmation email of the request information will be sent to: @@ -42,8 +42,8 @@

Ticket request sent successfully


- A member of the court registry will review your request and you will receive an email to the address you supplied - which will inform you if the dispute update request has been approved or rejected, and what to expect next. + A member of the court registry will review your request and inform you if the ticket request has been approved or + rejected, and what to expect next.


From fed2a061691eb26d0920af4a03ab23ae92dc5536 Mon Sep 17 00:00:00 2001 From: Dave Date: Fri, 20 Dec 2024 10:37:54 -0800 Subject: [PATCH 02/20] TCVP-2962 - Updated confirmation text --- .../dispute-submit-success.component.html | 9 +++------ .../email-verification/email-verification.component.html | 6 ++---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/frontend/citizen-portal/src/app/components/dispute-submit-success/dispute-submit-success.component.html b/src/frontend/citizen-portal/src/app/components/dispute-submit-success/dispute-submit-success.component.html index ba01d806d..efcbb7124 100644 --- a/src/frontend/citizen-portal/src/app/components/dispute-submit-success/dispute-submit-success.component.html +++ b/src/frontend/citizen-portal/src/app/components/dispute-submit-success/dispute-submit-success.component.html @@ -28,8 +28,7 @@

Ticket request sent successfully

Next Steps

- A member of the court registry will review your request and inform you if the ticket request has been approved or - rejected, and what to expect next. + A member of the court registry will review your request and inform you if the ticket request has been approved or rejected, and what to expect next.

A confirmation email of the request information will be sent to: @@ -37,13 +36,11 @@

Ticket request sent successfully

{{ noticeOfDispute.email_address }}

- A member of the court registry will review your request and inform you if the ticket request has been approved or - rejected, and what to expect next. + A member of the court registry will review your request and inform you if the ticket request has been approved or rejected, and what to expect next.

- A member of the court registry will review your request and inform you if the ticket request has been approved or - rejected, and what to expect next. + A member of the court registry will review your request and inform you if the ticket request has been approved or rejected, and what to expect next.


diff --git a/src/frontend/citizen-portal/src/app/components/email-verification/email-verification.component.html b/src/frontend/citizen-portal/src/app/components/email-verification/email-verification.component.html index 5e01ceb6a..ed44937b4 100644 --- a/src/frontend/citizen-portal/src/app/components/email-verification/email-verification.component.html +++ b/src/frontend/citizen-portal/src/app/components/email-verification/email-verification.component.html @@ -17,8 +17,7 @@

Email successfully confirmed.

Next Steps

- A member of the court registry will review your request and you will receive an email to the address you supplied - which will inform you if the ticket request has been approved or rejected, and what to expect next. + A member of the court registry will review your request and inform you if the ticket request has been approved or rejected, and what to expect next.

A confirmation email of the request information will be sent to the email address you supplied. @@ -40,8 +39,7 @@

Your email address could NOT be verified.

- A member of the court registry will review your request and you will be notified if the ticket request has been - approved or rejected, and what to expect next. + A member of the court registry will review your request and inform you if the ticket request has been approved or rejected, and what to expect next.
From 309116f8cf5e45e65c5b3cb4c71670590d54c6d5 Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 7 Jan 2025 09:10:30 -0800 Subject: [PATCH 03/20] Updated Status Filter label --- .../src/app/components/table-filters/table-filters.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts index dd851015b..5c8efbcf6 100644 --- a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts +++ b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts @@ -14,7 +14,7 @@ export class TableFiltersComponent implements OnInit { @Input() tabIndex: number; @Input() tableFilterKeys: TableFilterKeys[] = []; @Input() statusFilterOptions: DisputeStatus[] = []; - @Input() statusFilterDefaultText: string = "-- select --"; + @Input() statusFilterDefaultText: string = "All"; @Input() courthouseTeamNames: string[] = []; @Output() onFilterChanged: EventEmitter = new EventEmitter(); From 539795a06a8c65cb73935fb093140b84c980ca85 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 9 Jan 2025 13:07:51 -0800 Subject: [PATCH 04/20] TCVP-3063: Updated default filters, and hid NEW count unless filtering to NEW --- .../staff-workbench/ticket-inbox/ticket-inbox.component.html | 4 ++-- .../staff-workbench/ticket-inbox/ticket-inbox.component.ts | 3 +++ .../app/components/table-filters/table-filters.component.ts | 2 +- .../staff-portal/src/app/services/dispute.service.ts | 5 ++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.html b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.html index 527df26cb..4454bbeef 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.html +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.html @@ -1,6 +1,6 @@ - + [statusFilterDefaultText]="'ALL'" (onFilterChanged)="onApplyFilter($event)"> +
{{ newCount }} NEW ticket diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts index 61416aff6..35c25e2ee 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts @@ -47,6 +47,7 @@ export class TicketInboxComponent implements OnInit { sortBy: Array = ["submittedTs"]; sortDirection: Array = [SortDirection.Desc]; newCount: number = 0; + newCountShow: boolean = false; filters: TableFilter = new TableFilter(); previousFilters: TableFilter = new TableFilter(); @@ -129,6 +130,8 @@ export class TicketInboxComponent implements OnInit { this.filters = dataFilters; this.previousFilters = { ...dataFilters }; this.getAllDisputes(); + + this.newCountShow = this.filters.status == DisputeStatus.New; } backWorkbench(element) { diff --git a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts index 5c8efbcf6..f8d22213a 100644 --- a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts +++ b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts @@ -14,7 +14,7 @@ export class TableFiltersComponent implements OnInit { @Input() tabIndex: number; @Input() tableFilterKeys: TableFilterKeys[] = []; @Input() statusFilterOptions: DisputeStatus[] = []; - @Input() statusFilterDefaultText: string = "All"; + @Input() statusFilterDefaultText: string = "ALL"; @Input() courthouseTeamNames: string[] = []; @Output() onFilterChanged: EventEmitter = new EventEmitter(); diff --git a/src/frontend/staff-portal/src/app/services/dispute.service.ts b/src/frontend/staff-portal/src/app/services/dispute.service.ts index e86f28fb3..091689e7d 100644 --- a/src/frontend/staff-portal/src/app/services/dispute.service.ts +++ b/src/frontend/staff-portal/src/app/services/dispute.service.ts @@ -122,9 +122,8 @@ export class DisputeService implements IDisputeService { */ public getDisputes(sortBy: Array, sortDirection: Array, pageNumber: number, filters?: TableFilter): Observable { - return this.disputeApiService.apiDisputeDisputesGet(filters.status ? undefined : [ExcludeStatus.Cancelled, - ExcludeStatus.Processing, ExcludeStatus.Rejected, ExcludeStatus.Concluded], filters.ticketNumber, filters.disputantSurname, - filters.status ? [filters.status] : [DisputeStatus.New, DisputeStatus.Validated], filters.dateSubmittedFrom, + return this.disputeApiService.apiDisputeDisputesGet(filters.status ? undefined : [], filters.ticketNumber, filters.disputantSurname, + filters.status ? [filters.status] : [DisputeStatus.New, DisputeStatus.Validated, DisputeStatus.Processing, DisputeStatus.Rejected, DisputeStatus.Cancelled, DisputeStatus.Concluded], filters.dateSubmittedFrom, filters.dateSubmittedTo, undefined, sortBy, sortDirection, undefined, pageNumber, 25) .pipe( map((response: PagedDisputeListItemCollection) => { From d9d6fbca3be761f9f30d4eb875f3bac3e2827c19 Mon Sep 17 00:00:00 2001 From: Dave Date: Fri, 10 Jan 2025 14:27:40 -0800 Subject: [PATCH 05/20] TCVP-3063 Adding DualStatus option --- .../jj-dispute-digital-case-file.component.ts | 2 +- .../dispute-decision-inbox.component.ts | 2 +- .../ticket-inbox/ticket-inbox.component.ts | 9 ++-- .../update-request-inbox.component.ts | 4 +- .../table-filters.component.html | 2 +- .../table-filters/table-filters.component.ts | 4 +- .../src/app/services/dispute.service.ts | 53 ++++++++++--------- .../models/table-filter-options.model.ts | 46 +++++++++++++++- 8 files changed, 85 insertions(+), 37 deletions(-) diff --git a/src/frontend/staff-portal/src/app/components/jj-workbench/jj-dispute-digital-case-file/jj-dispute-digital-case-file.component.ts b/src/frontend/staff-portal/src/app/components/jj-workbench/jj-dispute-digital-case-file/jj-dispute-digital-case-file.component.ts index 05a9f026e..3b43c5dc5 100644 --- a/src/frontend/staff-portal/src/app/components/jj-workbench/jj-dispute-digital-case-file/jj-dispute-digital-case-file.component.ts +++ b/src/frontend/staff-portal/src/app/components/jj-workbench/jj-dispute-digital-case-file/jj-dispute-digital-case-file.component.ts @@ -49,7 +49,7 @@ export class JJDisputeDigitalCaseFileComponent implements OnInit { ngOnInit(): void { let dataFilter: TableFilter = this.tableFilterService.tableFilters[this.tabIndex]; - dataFilter.status = dataFilter.status ?? ""; + //dataFilter.status = dataFilter.status ?? ""; this.filters = dataFilter; this.previousFilters = { ...dataFilter }; this.currentPage = this.tableFilterService.currentPage[this.tabIndex]; diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/dispute-decision-inbox/dispute-decision-inbox.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/dispute-decision-inbox/dispute-decision-inbox.component.ts index 38ac132d0..f73a28d04 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/dispute-decision-inbox/dispute-decision-inbox.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/dispute-decision-inbox/dispute-decision-inbox.component.ts @@ -69,7 +69,7 @@ export class DisputeDecisionInboxComponent implements OnInit { public ngOnInit() { let dataFilter: TableFilter = this.tableFilterService.tableFilters[this.tabIndex]; - dataFilter.status = dataFilter.status ?? ""; + //dataFilter.status = dataFilter.status ?? ""; this.filters = dataFilter; this.previousFilters = { ...dataFilter }; this.currentPage = this.tableFilterService.currentPage[this.tabIndex]; diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts index 35c25e2ee..b865b279b 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts @@ -5,7 +5,7 @@ import { DisputeService, Dispute } from 'app/services/dispute.service'; import { DisputeRequestCourtAppearanceYn, DisputeDisputantDetectedOcrIssues, DisputeStatus, DisputeSystemDetectedOcrIssues, PagedDisputeListItemCollection, SortDirection } from 'app/api'; import { LoggerService } from '@core/services/logger.service'; import { AuthService, KeycloakProfile } from 'app/services/auth.service'; -import { TableFilter, TableFilterKeys } from '@shared/models/table-filter-options.model'; +import { TableFilter, TableFilterKeys, TableFilterStatus, TableFilterStatusOptions } from '@shared/models/table-filter-options.model'; import { TableFilterService } from 'app/services/table-filter.service'; @Component({ @@ -22,7 +22,7 @@ export class TicketInboxComponent implements OnInit { dataSource = new MatTableDataSource(this.disputes); tableFilterKeys: TableFilterKeys[] = ["dateSubmittedFrom", "dateSubmittedTo", "disputantSurname", "status", "ticketNumber"]; - statusFilterOptions = [DisputeStatus.New, DisputeStatus.Processing, DisputeStatus.Validated, DisputeStatus.Rejected, DisputeStatus.Cancelled, DisputeStatus.Concluded]; + statusFilterOptions = TableFilterStatusOptions; displayedColumns: string[] = [ '__RedGreenAlert', @@ -72,7 +72,7 @@ export class TicketInboxComponent implements OnInit { // when authentication token available, get data let dataFilter: TableFilter = this.tableFilterService.tableFilters[this.tabIndex]; - dataFilter.status = dataFilter.status ?? ""; + //dataFilter.status = dataFilter.status ?? []; this.filters = dataFilter; this.previousFilters = { ...dataFilter }; this.currentPage = this.tableFilterService.currentPage[this.tabIndex]; @@ -131,7 +131,8 @@ export class TicketInboxComponent implements OnInit { this.previousFilters = { ...dataFilters }; this.getAllDisputes(); - this.newCountShow = this.filters.status == DisputeStatus.New; + debugger; + this.newCountShow = this.filters? this.filters.status.mapping.includes(DisputeStatus.New) : false; } backWorkbench(element) { diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts index 899070a58..ca1b12b75 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts @@ -6,7 +6,7 @@ import { Dispute, DisputeStatus } from 'app/api'; import { LoggerService } from '@core/services/logger.service'; import { AuthService, KeycloakProfile } from 'app/services/auth.service'; import { DateUtil } from '@shared/utils/date-util'; -import { TableFilter, TableFilterKeys } from '@shared/models/table-filter-options.model'; +import { TableFilter, TableFilterKeys, TableFilterStatus, TableFilterStatusOptions } from '@shared/models/table-filter-options.model'; import { TableFilterService } from 'app/services/table-filter.service'; @Component({ @@ -20,7 +20,7 @@ export class UpdateRequestInboxComponent implements OnInit, AfterViewInit { dataSource = new MatTableDataSource(); tableFilterKeys: TableFilterKeys[] = ["dateSubmittedFrom", "dateSubmittedTo", "disputantSurname", "status", "ticketNumber"]; - statusFilterOptions = [DisputeStatus.New, DisputeStatus.Processing, DisputeStatus.Validated, DisputeStatus.Rejected, DisputeStatus.Cancelled, DisputeStatus.Concluded]; + statusFilterOptions = TableFilterStatusOptions; displayedColumns: string[] = [ 'submittedTs', 'ticketNumber', diff --git a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html index ddefa7b81..2b1291f72 100644 --- a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html +++ b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html @@ -91,7 +91,7 @@ {{ statusFilterDefaultText }} - {{item}} + {{item.Label}}
diff --git a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts index f8d22213a..9068e4912 100644 --- a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts +++ b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts @@ -42,7 +42,7 @@ export class TableFiltersComponent implements OnInit { this.tableFilterConfigs[key] = true; }) this.dataFilters = this.tableFilterService.tableFilters[this.tabIndex]; - this.dataFilters.status = this.dataFilters.status ?? ""; + //this.dataFilters.status = this.dataFilters.status ?? []; } resetSearchFilters() { @@ -52,7 +52,7 @@ export class TableFiltersComponent implements OnInit { // Put this call in a Timeout to keep UI responsive. setTimeout(() => { this.tableFilterService.tableFilters[this.tabIndex] = this.dataFilters; - this.dataFilters.status = this.dataFilters.status ?? ""; + //this.dataFilters.status = this.dataFilters.status ?? []; this.onFilterChanged.emit(this.dataFilters); }, 100); } diff --git a/src/frontend/staff-portal/src/app/services/dispute.service.ts b/src/frontend/staff-portal/src/app/services/dispute.service.ts index 091689e7d..4d7db5800 100644 --- a/src/frontend/staff-portal/src/app/services/dispute.service.ts +++ b/src/frontend/staff-portal/src/app/services/dispute.service.ts @@ -5,10 +5,11 @@ import { DisputeService as DisputeApiService, Dispute as DisputeBase, DisputeWit import { Observable, BehaviorSubject } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; import { EventEmitter, Injectable } from '@angular/core'; -import { TableFilter } from '@shared/models/table-filter-options.model'; +import { TableFilter, TableFilterStatus } from '@shared/models/table-filter-options.model'; import { HttpClient, HttpContext, HttpHeaders, HttpResponse } from '@angular/common/http'; import { AuthService } from './auth.service'; + export interface IDisputeService { disputes$: Observable; disputes: Dispute[]; @@ -122,31 +123,33 @@ export class DisputeService implements IDisputeService { */ public getDisputes(sortBy: Array, sortDirection: Array, pageNumber: number, filters?: TableFilter): Observable { - return this.disputeApiService.apiDisputeDisputesGet(filters.status ? undefined : [], filters.ticketNumber, filters.disputantSurname, - filters.status ? [filters.status] : [DisputeStatus.New, DisputeStatus.Validated, DisputeStatus.Processing, DisputeStatus.Rejected, DisputeStatus.Cancelled, DisputeStatus.Concluded], filters.dateSubmittedFrom, - filters.dateSubmittedTo, undefined, sortBy, sortDirection, undefined, pageNumber, 25) - .pipe( - map((response: PagedDisputeListItemCollection) => { - this.logger.info('DisputeService::getDisputes', response); - this._disputes.next(response.items); - response.items.forEach(dispute => { - dispute = this.joinDisputantGivenNames(dispute); - dispute = this.joinContactGivenNames(dispute); - dispute = this.joinLawyerNames(dispute); - dispute = this.joinAddressLines(dispute); - }); - return response; - }), - catchError((error: any) => { - this.toastService.openErrorToast(this.configService.dispute_error); - this.logger.error( - 'DisputeService::getDisputes error has occurred: ', - error - ); - throw error; - }) - ); + var disputeStatuses = filters.status ? filters.status.mapping : [DisputeStatus.New, DisputeStatus.Validated, DisputeStatus.Processing, DisputeStatus.Rejected, DisputeStatus.Cancelled, DisputeStatus.Concluded]; + + return this.disputeApiService.apiDisputeDisputesGet(undefined, filters.ticketNumber, filters.disputantSurname, + disputeStatuses, filters.dateSubmittedFrom, filters.dateSubmittedTo, undefined, sortBy, sortDirection, undefined, pageNumber, 25) + .pipe( + map((response: PagedDisputeListItemCollection) => { + this.logger.info('DisputeService::getDisputes', response); + this._disputes.next(response.items); + response.items.forEach(dispute => { + dispute = this.joinDisputantGivenNames(dispute); + dispute = this.joinContactGivenNames(dispute); + dispute = this.joinLawyerNames(dispute); + dispute = this.joinAddressLines(dispute); + }); + + return response; + }), + catchError((error: any) => { + this.toastService.openErrorToast(this.configService.dispute_error); + this.logger.error( + 'DisputeService::getDisputes error has occurred: ', + error + ); + throw error; + }) + ); } public get disputantUpdateRequests$(): Observable { diff --git a/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts b/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts index 0a278f8c0..6588f492a 100644 --- a/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts +++ b/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts @@ -1,5 +1,49 @@ import { Agency, DisputeStatus } from "app/api"; + + /** + * This is an intermediate layer of "options" to allow us to create special cases like "New & Validated", but still only send a final list of DisputeStatuses we want to the API + */ +export class TableFilterStatus { + label: string; + mapping: DisputeStatus[]; +} + +export const TableFilterStatusOptions = [ + { + Label: 'UNKNOWN', + Mapping: [DisputeStatus.Unknown] + }, + { + Label: 'NEW', + Mapping: [DisputeStatus.New] + }, + { + Label: 'VALIDATED', + Mapping: [DisputeStatus.Validated] + }, + { + Label: 'NEW AND VALIDATED', + Mapping: [DisputeStatus.New, DisputeStatus.Validated] + }, + { + Label: 'PROCESSING', + Mapping: [DisputeStatus.Processing] + }, + { + Label: 'REJECTED', + Mapping: [DisputeStatus.Rejected] + }, + { + Label: 'CANCELLED', + Mapping: [DisputeStatus.Cancelled] + }, + { + Label: 'CONCLUDED', + Mapping: [DisputeStatus.Concluded] + }, +]; + export class TableFilter { dateSubmittedFrom?: string; dateSubmittedTo?: string; @@ -10,7 +54,7 @@ export class TableFilter { surname?: string; team?: string; courthouseLocation?: Agency[]; - status?: DisputeStatus | ''; + status?: TableFilterStatus; } export type TableFilterKeys = keyof TableFilter; export type TableFilterConfigs = { From a514d64c66406f8c44a6b4846bc667e3021d2810 Mon Sep 17 00:00:00 2001 From: Dave Date: Fri, 10 Jan 2025 16:34:06 -0800 Subject: [PATCH 06/20] TCVP-3063: fixed some issues with Dual Status --- .../ticket-inbox/ticket-inbox.component.ts | 1 - .../table-filters.component.html | 2 +- .../models/table-filter-options.model.ts | 53 ++++++++----------- 3 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts index b865b279b..025680204 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts @@ -131,7 +131,6 @@ export class TicketInboxComponent implements OnInit { this.previousFilters = { ...dataFilters }; this.getAllDisputes(); - debugger; this.newCountShow = this.filters? this.filters.status.mapping.includes(DisputeStatus.New) : false; } diff --git a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html index 2b1291f72..01d7b45a3 100644 --- a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html +++ b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html @@ -91,7 +91,7 @@ {{ statusFilterDefaultText }} - {{item.Label}} + {{item.label}}
diff --git a/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts b/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts index 6588f492a..c74216ceb 100644 --- a/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts +++ b/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts @@ -9,38 +9,27 @@ export class TableFilterStatus { mapping: DisputeStatus[]; } -export const TableFilterStatusOptions = [ - { - Label: 'UNKNOWN', - Mapping: [DisputeStatus.Unknown] - }, - { - Label: 'NEW', - Mapping: [DisputeStatus.New] - }, - { - Label: 'VALIDATED', - Mapping: [DisputeStatus.Validated] - }, - { - Label: 'NEW AND VALIDATED', - Mapping: [DisputeStatus.New, DisputeStatus.Validated] - }, - { - Label: 'PROCESSING', - Mapping: [DisputeStatus.Processing] - }, - { - Label: 'REJECTED', - Mapping: [DisputeStatus.Rejected] - }, - { - Label: 'CANCELLED', - Mapping: [DisputeStatus.Cancelled] - }, - { - Label: 'CONCLUDED', - Mapping: [DisputeStatus.Concluded] +export const TableFilterStatusOptions = [{ + label: 'NEW', + mapping: [DisputeStatus.New] + },{ + label: 'VALIDATED', + mapping: [DisputeStatus.Validated] + },{ + label: 'NEW & VALIDATED', + mapping: [DisputeStatus.New, DisputeStatus.Validated] + },{ + label: 'PROCESSING', + mapping: [DisputeStatus.Processing] + },{ + label: 'REJECTED', + mapping: [DisputeStatus.Rejected] + },{ + label: 'CANCELLED', + mapping: [DisputeStatus.Cancelled] + },{ + label: 'CONCLUDED', + mapping: [DisputeStatus.Concluded] }, ]; From c4520510f07ee86f180f12e3f067f3b3a8e06c44 Mon Sep 17 00:00:00 2001 From: Dave Date: Mon, 13 Jan 2025 10:43:10 -0800 Subject: [PATCH 07/20] TCVP-3063: Fixed the 'Default' ALL filter, and Reset Filter behavior. --- .../ticket-inbox/ticket-inbox.component.html | 2 +- .../staff-workbench/ticket-inbox/ticket-inbox.component.ts | 5 +++-- .../components/table-filters/table-filters.component.html | 1 - .../components/table-filters/table-filters.component.ts | 6 +++--- .../src/app/shared/models/table-filter-options.model.ts | 7 ++++++- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.html b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.html index 4454bbeef..c45d0e2ad 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.html +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.html @@ -1,5 +1,5 @@ + [statusFilterDefault]="statusFilterDefault" (onFilterChanged)="onApplyFilter($event)">
diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts index 025680204..e3b2961dd 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-inbox/ticket-inbox.component.ts @@ -5,7 +5,7 @@ import { DisputeService, Dispute } from 'app/services/dispute.service'; import { DisputeRequestCourtAppearanceYn, DisputeDisputantDetectedOcrIssues, DisputeStatus, DisputeSystemDetectedOcrIssues, PagedDisputeListItemCollection, SortDirection } from 'app/api'; import { LoggerService } from '@core/services/logger.service'; import { AuthService, KeycloakProfile } from 'app/services/auth.service'; -import { TableFilter, TableFilterKeys, TableFilterStatus, TableFilterStatusOptions } from '@shared/models/table-filter-options.model'; +import { TableFilter, TableFilterKeys, TableFilterStatus, TableFilterStatusOptions, TableFilterStatusDefault } from '@shared/models/table-filter-options.model'; import { TableFilterService } from 'app/services/table-filter.service'; @Component({ @@ -23,6 +23,7 @@ export class TicketInboxComponent implements OnInit { tableFilterKeys: TableFilterKeys[] = ["dateSubmittedFrom", "dateSubmittedTo", "disputantSurname", "status", "ticketNumber"]; statusFilterOptions = TableFilterStatusOptions; + statusFilterDefault = TableFilterStatusDefault; displayedColumns: string[] = [ '__RedGreenAlert', @@ -131,7 +132,7 @@ export class TicketInboxComponent implements OnInit { this.previousFilters = { ...dataFilters }; this.getAllDisputes(); - this.newCountShow = this.filters? this.filters.status.mapping.includes(DisputeStatus.New) : false; + this.newCountShow = (this.filters && this.filters.status) ? this.filters.status.mapping.includes(DisputeStatus.New) : false; } backWorkbench(element) { diff --git a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html index 01d7b45a3..e85aae1dc 100644 --- a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html +++ b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.html @@ -90,7 +90,6 @@ - {{ statusFilterDefaultText }} {{item.label}} diff --git a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts index 9068e4912..ea25fa362 100644 --- a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts +++ b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { TableFilter, TableFilterConfigs, TableFilterKeys } from '@shared/models/table-filter-options.model'; +import { TableFilter, TableFilterConfigs, TableFilterKeys, TableFilterStatus, TableFilterStatusDefault } from '@shared/models/table-filter-options.model'; import { DisputeStatus } from 'app/api'; import { LookupsService } from 'app/services/lookups.service'; import { TableFilterService } from 'app/services/table-filter.service'; @@ -14,7 +14,7 @@ export class TableFiltersComponent implements OnInit { @Input() tabIndex: number; @Input() tableFilterKeys: TableFilterKeys[] = []; @Input() statusFilterOptions: DisputeStatus[] = []; - @Input() statusFilterDefaultText: string = "ALL"; + @Input() statusFilterDefaultText: string = 'ALL'; @Input() courthouseTeamNames: string[] = []; @Output() onFilterChanged: EventEmitter = new EventEmitter(); @@ -42,7 +42,7 @@ export class TableFiltersComponent implements OnInit { this.tableFilterConfigs[key] = true; }) this.dataFilters = this.tableFilterService.tableFilters[this.tabIndex]; - //this.dataFilters.status = this.dataFilters.status ?? []; + this.dataFilters.status = this.dataFilters.status ?? TableFilterStatusDefault; } resetSearchFilters() { diff --git a/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts b/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts index c74216ceb..e7049c2ec 100644 --- a/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts +++ b/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts @@ -10,6 +10,9 @@ export class TableFilterStatus { } export const TableFilterStatusOptions = [{ + label: 'ALL', + mapping: [DisputeStatus.New, DisputeStatus.Validated, DisputeStatus.Processing, DisputeStatus.Rejected, DisputeStatus.Cancelled, DisputeStatus.Concluded] + },{ label: 'NEW', mapping: [DisputeStatus.New] },{ @@ -33,6 +36,8 @@ export const TableFilterStatusOptions = [{ }, ]; +export const TableFilterStatusDefault = TableFilterStatusOptions[0]; + export class TableFilter { dateSubmittedFrom?: string; dateSubmittedTo?: string; @@ -43,7 +48,7 @@ export class TableFilter { surname?: string; team?: string; courthouseLocation?: Agency[]; - status?: TableFilterStatus; + status?: TableFilterStatus = TableFilterStatusDefault; } export type TableFilterKeys = keyof TableFilter; export type TableFilterConfigs = { From 1d5d34ababdb913eb263b155991a9451e469aedb Mon Sep 17 00:00:00 2001 From: Dave Date: Mon, 13 Jan 2025 11:10:22 -0800 Subject: [PATCH 08/20] TCVP-3063: fixed an issue with filters in Update Requests --- .../update-request-inbox/update-request-inbox.component.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts index ca1b12b75..2d04fdc39 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts @@ -92,6 +92,11 @@ export class UpdateRequestInboxComponent implements OnInit, AfterViewInit { else if ("dateSubmittedTo" === field) { return !value || !DateUtil.isValid(value) || DateUtil.isDateOnOrBefore(record.submittedTs, value); } + else if ("status" === field) { + var status = record[field]; + var statusFilters = (value as unknown) as TableFilterStatus; + return statusFilters.mapping.includes(status); + } else if (record[field]) { return record[field].toLocaleLowerCase().indexOf(value.trim().toLocaleLowerCase()) != -1; } From cd4584eade9cd2b4244315f49692e87ba64e8787 Mon Sep 17 00:00:00 2001 From: Emad Date: Mon, 13 Jan 2025 12:33:00 -0800 Subject: [PATCH 09/20] [TCVP-2955] modfiy dl # validation rules for BC and non-BC provinces/states --- .../ticket-info/ticket-info.component.html | 35 ++++++++++--------- .../ticket-info/ticket-info.component.ts | 24 +++++++++++-- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html index 0316184f5..ac7ff1d69 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html @@ -172,22 +172,25 @@

Personal Information

- DL number - - - - {{ "error.required" | translate }} - - - Must be a valid BC driver's licence number of seven to nine digits - - + [ngClass]="{'underErrThreshold': applyUnderErrThreshold('drivers_licence_number'), 'overErrThreshold': applyOverErrThreshold('drivers_licence_number')}"> + DL number + + + + {{ "error.required" | translate }} + + + Must be a valid BC driver's licence number of seven to nine digits + + + Must be a numeric value for BC driver's licence + +
diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.ts index b6062a55c..8bb684c22 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.ts @@ -164,6 +164,19 @@ export class TicketInfoComponent implements OnInit { violationTime: [null, [Validators.required, Validators.pattern(/^(0[0-9]|1[0-9]|2[0-3])[0-5][0-9]$/)]], // api returns issued date, extract time from that }) }); + // Custom validator for driversLicenceNumber + this.form.get('violationTicket').get('driversLicenceProvince').valueChanges.subscribe(value => { + if (value === this.bc.provAbbreviationCd) { + this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([ + Validators.maxLength(9), + Validators.minLength(7), + Validators.pattern(/^\d+$/) // Only numeric values + ]); + } else { + this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([Validators.maxLength(20)]); + } + this.form.get('violationTicket').get('disputantDriversLicenceNumber').updateValueAndValidity(); + }); // retreive fresh copy from db this.getDispute(); } @@ -316,8 +329,11 @@ export class TicketInfoComponent implements OnInit { this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([Validators.maxLength(20)]); } else{ if (provAbbreviationCd == this.bc.provAbbreviationCd) { - this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([Validators.maxLength(9)]) - this.form.get('violationTicket').get('disputantDriversLicenceNumber').addValidators([Validators.minLength(7)]); + this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([ + Validators.maxLength(9), + Validators.minLength(7), + Validators.pattern(/^\d+$/) + ]); } else { this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([Validators.maxLength(20)]); } @@ -326,7 +342,9 @@ export class TicketInfoComponent implements OnInit { let ctryFound = this.config.countries.filter(x => x.ctryId === provFound.ctryId).shift(); this.form.get('violationTicket').get('driversLicenceCountry').setValue(ctryFound.ctryLongNm); } - } + } + this.form.get('violationTicket').get('disputantDriversLicenceNumber').markAsTouched(); + this.form.get('violationTicket').get('disputantDriversLicenceNumber').markAsDirty(); this.form.get('violationTicket').get('disputantDriversLicenceNumber').updateValueAndValidity(); }, 5) } From 181b822891071863b98333644ef92dc0d2256b33 Mon Sep 17 00:00:00 2001 From: Emad Date: Mon, 13 Jan 2025 16:54:20 -0800 Subject: [PATCH 10/20] [TCVP-3092] fix bug, when user press enter key when ocr error box is open, just close the error dialog box --- .../image-ticket-not-found-dialog.component.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/frontend/citizen-portal/src/app/shared/dialogs/image-ticket-not-found-dialog/image-ticket-not-found-dialog.component.ts b/src/frontend/citizen-portal/src/app/shared/dialogs/image-ticket-not-found-dialog/image-ticket-not-found-dialog.component.ts index e88cdfe2c..6a3f1de2d 100644 --- a/src/frontend/citizen-portal/src/app/shared/dialogs/image-ticket-not-found-dialog/image-ticket-not-found-dialog.component.ts +++ b/src/frontend/citizen-portal/src/app/shared/dialogs/image-ticket-not-found-dialog/image-ticket-not-found-dialog.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, ChangeDetectionStrategy} from '@angular/core'; +import { Component, Inject, ChangeDetectionStrategy, HostListener} from '@angular/core'; import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog'; import { MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA, MatLegacyDialogRef as MatDialogRef } from '@angular/material/legacy-dialog'; @@ -59,5 +59,15 @@ export class ImageTicketNotFoundDialogComponent { ...options, }; } + @HostListener('document:keydown', ['$event']) + public preventEvent(event: KeyboardEvent): void { + if (this.options.messageKey === 'error500') { + event.preventDefault(); + event.stopPropagation(); + if (event.key === 'Enter') { + this.dialogRef.close(); + } + } + } } From db49301a36453b62f0edebfd8f3854d2ada8c642 Mon Sep 17 00:00:00 2001 From: Emad Date: Mon, 13 Jan 2025 17:52:31 -0800 Subject: [PATCH 11/20] [TCVP-3089] make loading indicator wider with animation --- .../src/scss/vendors/_ngx-progress.scss | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/frontend/staff-portal/src/scss/vendors/_ngx-progress.scss b/src/frontend/staff-portal/src/scss/vendors/_ngx-progress.scss index 3b1707720..00fd963ed 100644 --- a/src/frontend/staff-portal/src/scss/vendors/_ngx-progress.scss +++ b/src/frontend/staff-portal/src/scss/vendors/_ngx-progress.scss @@ -21,12 +21,46 @@ // Change the height of the progress bar // to match the height of the top border // of the container - height: 3px !important; + height: 6px !important; } .ng-bar { // Actual bar that translates when the progress increments - background: theme-palette(yellow) !important; + background: repeating-linear-gradient( + 45deg, + lighten(theme-palette(yellow), 0%), + lighten(theme-palette(yellow), 0%) 10px, + theme-palette(yellow) 10px, + theme-palette(yellow) 20px + ) !important; + position: relative; + overflow: hidden; + + &::after { + content: ''; + position: absolute; + top: 0; + left: -50%; + width: 150%; + height: 150%; + background: repeating-linear-gradient( + 45deg, + rgba(255, 255, 255, 0) 0%, + rgba(255, 255, 255, 0.5) 10px, + rgba(255, 255, 255, 0) 20px + ); + box-shadow: 0 0 10px 5px rgba(255, 255, 255, 0.5); + animation: light-sweep 2s infinite; + } +} + +@keyframes light-sweep { + 0% { + left: +50%; + } + 100% { + left: 100%; + } } // .ng-spinner { From 298a85570366efe07c013647f3ddfd393089577e Mon Sep 17 00:00:00 2001 From: Deepak Yadav Date: Fri, 31 Jan 2025 15:27:21 -0800 Subject: [PATCH 12/20] TCVP-2915: BCSC 'Could not be authenticated' Error message --- src/frontend/citizen-portal/src/app/services/dispute.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/citizen-portal/src/app/services/dispute.service.ts b/src/frontend/citizen-portal/src/app/services/dispute.service.ts index abd627fd6..4f5653574 100644 --- a/src/frontend/citizen-portal/src/app/services/dispute.service.ts +++ b/src/frontend/citizen-portal/src/app/services/dispute.service.ts @@ -133,7 +133,7 @@ export class DisputeService { const data: DialogOptions = { titleKey: "Warning", actionType: "warn", - messageKey: `You could not be authenticated as the contact noted on this dispute. ` + err, + messageKey: `You could not be authenticated as the contact noted on this dispute as your information does not match your BC Services Card information.`, actionTextKey: "Close", cancelHide: true }; From cd83a9a3b9c762f34697d1b8de7cf1aa5e41fa24 Mon Sep 17 00:00:00 2001 From: Deepak Yadav Date: Mon, 3 Feb 2025 00:20:53 -0800 Subject: [PATCH 13/20] TCVP-2230: Update/Harmonize Back Button --- .../staff-workbench/ticket-info/ticket-info.component.html | 6 +++--- .../update-request-info/update-request-info.component.html | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html index 0316184f5..fa88a4c3a 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html @@ -2,9 +2,9 @@
- - arrow_back Back to TRM home - +
diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-info/update-request-info.component.html b/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-info/update-request-info.component.html index 5ddd7574c..1b6132056 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-info/update-request-info.component.html +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-info/update-request-info.component.html @@ -1,8 +1,8 @@
- - arrow_back Back to Inbox - +
From e50ece81315a81a458b29d3ba8e66364b7bc0197 Mon Sep 17 00:00:00 2001 From: Deepak Yadav Date: Mon, 3 Feb 2025 00:23:05 -0800 Subject: [PATCH 14/20] TCVP-2806: Document upload - virus scan - needs page refresh --- .../jj-dispute/jj-dispute.component.ts | 38 +++++++++++++++---- .../upload/upload.component.ts | 35 ++++++++++++++--- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/frontend/staff-portal/src/app/components/jj-dispute-info/jj-dispute/jj-dispute.component.ts b/src/frontend/staff-portal/src/app/components/jj-dispute-info/jj-dispute/jj-dispute.component.ts index 9625402a4..8d6005707 100644 --- a/src/frontend/staff-portal/src/app/components/jj-dispute-info/jj-dispute/jj-dispute.component.ts +++ b/src/frontend/staff-portal/src/app/components/jj-dispute-info/jj-dispute/jj-dispute.component.ts @@ -19,6 +19,7 @@ import { TabType } from '@shared/enums/tab-type.enum'; import { Dispute } from 'app/services/dispute.service'; import { DisputeStatus } from '@shared/consts/DisputeStatus.model'; import { HearingType } from '@shared/consts/HearingType.model'; +import { ChangeDetectorRef } from '@angular/core'; @Component({ selector: 'app-jj-dispute', @@ -131,7 +132,8 @@ export class JJDisputeComponent implements OnInit { private lookupsService: LookupsService, private config: ConfigService, private documentService: DocumentService, - private historyRecordService: HistoryRecordService + private historyRecordService: HistoryRecordService, + private cdr: ChangeDetectorRef, ) { this.authService.jjList$.subscribe(result => { this.jjList = result; @@ -559,18 +561,40 @@ export class JJDisputeComponent implements OnInit { onUpload(files: FileList) { if (files.length <= 0) return; - - // upload to coms + + // Initially, set the status to "waiting for virus scan..." + let item: FileMetadata = { + fileId: '', + fileName: files[0].name, + virusScanStatus: "waiting for virus scan..." + }; + + // Add the item to the fileData array + this.lastUpdatedJJDispute.fileData.push(item); + + // Manually trigger change detection to ensure the UI is refreshed + this.cdr.detectChanges(); + + // Upload the file this.documentService.apiDocumentPost(this.lastUpdatedJJDispute.noticeOfDisputeGuid, this.fileTypeToUpload, files[0], this.lastUpdatedJJDispute.id) .subscribe(fileId => { - - // add to display of files in DCF - let item: FileMetadata = { fileId: fileId, fileName: files[0].name, virusScanStatus: "waiting for virus scan..." }; - this.lastUpdatedJJDispute.fileData.push(item); + // Once the file is uploaded, update the fileId and status + item.fileId = fileId; + item.virusScanStatus = ""; // or any other status + + // Manually trigger change detection again to update the view + this.cdr.detectChanges(); + + // Call refreshFileHistory() to update the history if needed this.refreshFileHistory(); + }, error => { + // If the upload fails, set an error message + item.virusScanStatus = "upload failed"; + this.cdr.detectChanges(); // Ensure the component updates in case of error }); } + onPrint(isCompleteVersion: boolean) { var type = DcfTemplateType.DcfTemplate; if (!isCompleteVersion) { diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/upload/upload.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/upload/upload.component.ts index 8bd4f7aae..a886b2a2f 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/upload/upload.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/upload/upload.component.ts @@ -6,6 +6,7 @@ import { DocumentService } from 'app/api/api/document.service'; import { FileMetadata } from 'app/api/model/fileMetadata.model'; import { Dispute } from 'app/services/dispute.service'; import { JJDisputeService } from 'app/services/jj-dispute.service'; +import { ChangeDetectorRef } from '@angular/core'; @Component({ selector: 'app-upload', @@ -26,6 +27,7 @@ export class UploadComponent { private dialog: MatDialog, private documentService: DocumentService, private jjDisputeService: JJDisputeService, + private cdr: ChangeDetectorRef, ) { } @@ -63,10 +65,33 @@ export class UploadComponent { onUpload(files: FileList) { if (files.length <= 0) return; - this.documentService.apiDocumentPost(this.disputeInfo.noticeOfDisputeGuid, this.fileTypeToUpload, files[0], - null).subscribe(fileId => { - let item: FileMetadata = { fileId: fileId, fileName: files[0].name, virusScanStatus: "waiting for virus scan..." }; - this.disputeInfo.fileData.push(item); - }); + + // Initially, set the status to "waiting for virus scan..." + let item: FileMetadata = { + fileId: '', + fileName: files[0].name, + virusScanStatus: "waiting for virus scan..." + }; + + // Add the item to the fileData array + this.disputeInfo.fileData.push(item); + + // Manually trigger change detection to ensure the UI is refreshed + this.cdr.detectChanges(); + + // Now upload the file + this.documentService.apiDocumentPost(this.disputeInfo.noticeOfDisputeGuid, this.fileTypeToUpload, files[0], null) + .subscribe(fileId => { + // Once the file is uploaded, update the status and fileId + item.fileId = fileId; + item.virusScanStatus = ""; // or any other status + + // Manually trigger change detection again to update the view + this.cdr.detectChanges(); + }, error => { + // If the upload fails, set an error message + item.virusScanStatus = "upload failed"; + this.cdr.detectChanges(); // Ensure the component updates in case of error + }); } } From dc4b44c5818a498fe12741b72bd3065e0f59c7e3 Mon Sep 17 00:00:00 2001 From: Deepak Yadav Date: Mon, 3 Feb 2025 00:26:30 -0800 Subject: [PATCH 15/20] TCVP-3053: Update Wording on Citizen Portal - ISC wording from RoadSafety --- .../src/app/components/landing/landing.component.html | 2 +- .../components/ticket-landing/ticket-landing.component.html | 6 ++++++ .../components/ticket-landing/ticket-landing.component.ts | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/frontend/citizen-portal/src/app/components/landing/landing.component.html b/src/frontend/citizen-portal/src/app/components/landing/landing.component.html index 14c12b4db..05bb95596 100644 --- a/src/frontend/citizen-portal/src/app/components/landing/landing.component.html +++ b/src/frontend/citizen-portal/src/app/components/landing/landing.component.html @@ -93,7 +93,7 @@

Useful links

- RoadSafetyBC + Intersection Safety Camera Tickets (RoadSafetyBC)
Governing drivers, putting road safety policies in place, and diff --git a/src/frontend/citizen-portal/src/app/components/ticket-landing/ticket-landing.component.html b/src/frontend/citizen-portal/src/app/components/ticket-landing/ticket-landing.component.html index 63e296447..5cba4c93d 100644 --- a/src/frontend/citizen-portal/src/app/components/ticket-landing/ticket-landing.component.html +++ b/src/frontend/citizen-portal/src/app/components/ticket-landing/ticket-landing.component.html @@ -9,6 +9,12 @@
  • want to raise a defence
  • +
    + If you received an Intersection Safety Camera ticket (ticket number starts with an 'S'), click + + here + for more information. +
    diff --git a/src/frontend/citizen-portal/src/app/components/ticket-landing/ticket-landing.component.ts b/src/frontend/citizen-portal/src/app/components/ticket-landing/ticket-landing.component.ts index 22ac3e1d5..4ae51d135 100644 --- a/src/frontend/citizen-portal/src/app/components/ticket-landing/ticket-landing.component.ts +++ b/src/frontend/citizen-portal/src/app/components/ticket-landing/ticket-landing.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { AppConfigService } from 'app/services/app-config.service'; @Component({ selector: 'app-ticket-landing', @@ -7,7 +8,10 @@ import { Component } from '@angular/core'; }) export class TicketLandingComponent { + roadSafetyBCVisitUsLink: string; constructor( + private appConfigService: AppConfigService ) { + this.roadSafetyBCVisitUsLink = this.appConfigService.roadSafetyBCVisitUsLink; } } From cb5fc5f4f0a36b660c9a4f3aa387ffc9cb207139 Mon Sep 17 00:00:00 2001 From: Emad Date: Mon, 3 Feb 2025 11:59:15 -0800 Subject: [PATCH 16/20] added dl license number validtaion for citizen portal --- .../disputant-form.component.html | 12 ++++-- .../disputant-form.component.ts | 39 +++++++++++++------ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/frontend/citizen-portal/src/app/components/disputant-form/disputant-form.component.html b/src/frontend/citizen-portal/src/app/components/disputant-form/disputant-form.component.html index a922cf72f..dbc798412 100644 --- a/src/frontend/citizen-portal/src/app/components/disputant-form/disputant-form.component.html +++ b/src/frontend/citizen-portal/src/app/components/disputant-form/disputant-form.component.html @@ -231,10 +231,14 @@

    Contact details

    minlength="7" maxlength="9" /> - - Must be a valid driver's licence number of seven to nine digits - + + + Must be a valid driver's licence number of seven to nine digits. + + + Must be a valid driver's licence number with a maximum of 20 characters. + +
    diff --git a/src/frontend/citizen-portal/src/app/components/disputant-form/disputant-form.component.ts b/src/frontend/citizen-portal/src/app/components/disputant-form/disputant-form.component.ts index b5b5a6c1e..c104ba8aa 100644 --- a/src/frontend/citizen-portal/src/app/components/disputant-form/disputant-form.component.ts +++ b/src/frontend/citizen-portal/src/app/components/disputant-form/disputant-form.component.ts @@ -78,31 +78,41 @@ export class DisputantFormComponent implements OnInit, AfterViewInit { } else { this.countryFormControl.setValue(country); } - + let province = this.provincesAndStates.filter(i => i.provAbbreviationCd === this.form.value.address_province).shift(); if (!this.form.value.address_province) { this.provinceFormControl.setValue(this.bc); } else { this.provinceFormControl.setValue(province); } - + let form = this.form as NoticeOfDisputeFormGroup; - // search for drivers licence province using abbreviation e.g. BC if (form.value.drivers_licence_province) { let foundProvinces = this.provincesAndStates.filter(x => x.provAbbreviationCd === form.value.drivers_licence_province).shift(); if (foundProvinces) { this.driversLicenceProvinceFormControl.setValue(foundProvinces); - } else{ + } else { this.driversLicenceProvinceFormControl.setValue(null); } - } else if (form.controls.drivers_licence_province) { // have control but no value - if(this.mode !== DisputeFormMode.UPDATE) { + } else if (form.controls.drivers_licence_province) { + if (this.mode !== DisputeFormMode.UPDATE) { this.driversLicenceProvinceFormControl.setValue(this.bc); } else { this.driversLicenceProvinceFormControl.setValue(null); - } + } } - + + // Check for the driver's licence number validity on load + const driversLicenceNumber = form.controls.drivers_licence_number.value; + const isBC = this.driversLicenceProvinceFormControl.value?.provId === this.bc.provId; + const isInvalid = isBC ? !(driversLicenceNumber && driversLicenceNumber.length >= 7 && driversLicenceNumber.length <= 9 && /^[0-9]+$/.test(driversLicenceNumber)) : + !(driversLicenceNumber && driversLicenceNumber.length <= 20); + + if (isInvalid) { + form.controls.drivers_licence_number.markAsTouched(); + form.controls.drivers_licence_number.markAsDirty(); + } + if (this.preferEmail !== undefined && this.preferEmail !== true) { this.form.controls.email_address.disable(); this.optOut = true; @@ -180,10 +190,17 @@ export class DisputantFormComponent implements OnInit, AfterViewInit { } if (province != null && province.provId === this.bc.provId) { - form.controls.drivers_licence_number.setValidators([Validators.maxLength(9)]); - form.controls.drivers_licence_number.addValidators([Validators.minLength(7)]); + form.controls.drivers_licence_number.setValidators([ + Validators.required, + Validators.minLength(7), + Validators.maxLength(9), + Validators.pattern(/^\d+$/) // Ensure it's numeric + ]); } else { - form.controls.drivers_licence_number.setValidators([Validators.maxLength(20)]); + form.controls.drivers_licence_number.setValidators([ + Validators.required, + Validators.maxLength(20) + ]); } form.controls.drivers_licence_number.updateValueAndValidity(); From a98a35694d637d8300e2ee7fce86994420b5edd9 Mon Sep 17 00:00:00 2001 From: Emad Date: Mon, 3 Feb 2025 13:59:42 -0800 Subject: [PATCH 17/20] fix error check expression --- .../image-ticket-not-found-dialog.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/citizen-portal/src/app/shared/dialogs/image-ticket-not-found-dialog/image-ticket-not-found-dialog.component.ts b/src/frontend/citizen-portal/src/app/shared/dialogs/image-ticket-not-found-dialog/image-ticket-not-found-dialog.component.ts index 6a3f1de2d..473ddba91 100644 --- a/src/frontend/citizen-portal/src/app/shared/dialogs/image-ticket-not-found-dialog/image-ticket-not-found-dialog.component.ts +++ b/src/frontend/citizen-portal/src/app/shared/dialogs/image-ticket-not-found-dialog/image-ticket-not-found-dialog.component.ts @@ -61,7 +61,7 @@ export class ImageTicketNotFoundDialogComponent { } @HostListener('document:keydown', ['$event']) public preventEvent(event: KeyboardEvent): void { - if (this.options.messageKey === 'error500') { + if (/error/i.test(this.options.messageKey)) { event.preventDefault(); event.stopPropagation(); if (event.key === 'Enter') { From 6d9746947beb9aaae45ecb1488db3ea80dafa0f6 Mon Sep 17 00:00:00 2001 From: Dave Date: Wed, 5 Feb 2025 08:45:42 -0800 Subject: [PATCH 18/20] WIP on Fixed a configuration issue for citizens-api --- docker-compose.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 0d34a70c7..57c8095af 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -44,6 +44,9 @@ services: SERILOG__WRITETO__0__ARGS__THEME: Serilog.Sinks.SystemConsole.Themes.ConsoleTheme::None, Serilog.Sinks.Console SERILOG__WRITETO__0__NAME: Console SERILOG__MINIMUMLEVEL__DEFAULT: ${SERILOG__MINIMUMLEVEL__DEFAULT:-Information} + ORDSDATASERVICE__ADDRESS: ${ORDSDATASERVICE__ADDRESS} + ORDSDATASERVICE__PASSWORD: ${ORDSDATASERVICE__PASSWORD} + ORDSDATASERVICE__USERNAME: ${ORDSDATASERVICE__USERNAME} ports: - "5080:8080" restart: always From 3bb4498bbbb90bd4faa797a8e15b4a0444956c27 Mon Sep 17 00:00:00 2001 From: Emad Date: Thu, 6 Feb 2025 13:33:39 -0800 Subject: [PATCH 19/20] [TCVP-2955] clear error message, prettier code --- .../ticket-info/ticket-info.component.html | 215 ++-- .../ticket-info/ticket-info.component.ts | 1116 +++++++++++------ 2 files changed, 881 insertions(+), 450 deletions(-) diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html index 428dc96ba..74f0f7ab1 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.html @@ -41,15 +41,18 @@

    Retrieving ticket information...

    - +

    Ticket Image

    -
    - +
    + Click to expand ticket image
    @@ -72,12 +75,15 @@

    Violation Ticket Details

    Ticket number - - + {{ "error.required" | translate }} - + This ticket number is not valid. It must be 2 letters and 8 numbers. @@ -88,8 +94,10 @@

    Violation Ticket Details

    Date - - + + {{ "error.required" | translate }} @@ -100,11 +108,14 @@

    Violation Ticket Details

    Time - - + + {{ "error.required" | translate }} - + Invalid time. Use 24hr format. @@ -124,11 +135,14 @@

    Personal Information

    Surname - - + + {{ "error.required" | translate }} - + {{ "error.max_length" | translate }}30 @@ -139,11 +153,14 @@

    Personal Information

    Given name(s) - - + + {{ "error.required" | translate }} - + {{ "error.max_length" | translate }}30 per name @@ -155,7 +172,9 @@

    Personal Information

    Prov/State of DL - + {{bc.provNm}} {{ @@ -165,32 +184,44 @@

    Personal Information

    state.provNm }}
    - {{ "error.required" | translate }} + {{ "error.required" | translate + }}
    - DL number - - - - {{ "error.required" | translate }} - - - Must be a valid BC driver's licence number of seven to nine digits - - - Must be a numeric value for BC driver's licence - - + [ngClass]="{'underErrThreshold': applyUnderErrThreshold('drivers_licence_number'), 'overErrThreshold': applyOverErrThreshold('drivers_licence_number')}"> + DL number + + + + {{ "error.required" | translate }} + + + Must be a valid BC driver's licence number of seven to nine digits + + + + Must be a valid driver's licence number with a maximum of 20 characters. + + + + Must be a numeric value for BC driver's licence + +
    @@ -219,8 +250,10 @@

    Count 1

    [value]="statute.__statuteString"> {{ statute.__statuteString }} - {{ "error.required" | translate }} - Invalid statute selection. + {{ "error.required" | translate + }} + Invalid statute selection.
    @@ -229,12 +262,12 @@

    Count 1

    [ngClass]="{'underErrThreshold': applyUnderErrThreshold('counts.count_no_1.ticketed_amount'), 'overErrThreshold': applyOverErrThreshold('counts.count_no_1.ticketed_amount')}"> Fine amount ($) - {{ "error.required" | translate }} + {{ "error.required" | translate + }}
    -
    @@ -278,12 +313,12 @@

    Count 2

    [ngClass]="{'underErrThreshold': applyUnderErrThreshold('counts.count_no_2.ticketed_amount'), 'overErrThreshold': applyOverErrThreshold('counts.count_no_2.ticketed_amount')}"> Fine amount ($) - {{ "error.required" | translate }} + {{ "error.required" | translate + }}
    -
    @@ -327,12 +364,12 @@

    Count 3

    [ngClass]="{'underErrThreshold': applyUnderErrThreshold('counts.count_no_3.ticketed_amount'), 'overErrThreshold': applyOverErrThreshold('counts.count_no_3.ticketed_amount')}"> Fine amount ($) - {{ "error.required" | translate }} + {{ "error.required" | translate + }}
    -
    @@ -377,7 +416,7 @@

    Court Location

    Save
    @@ -542,7 +581,7 @@

    {{ "label.who_contacting" | translate }}

    {{ "label.mailing_address" | translate }} - + {{ "error.required" | translate }} {{ "error.max_length" | translate @@ -572,7 +611,7 @@

    {{ "label.who_contacting" | translate }}

    {{ "label.city" | translate }} - + {{ "error.required" | translate }} {{ "error.max_length" | @@ -583,8 +622,10 @@

    {{ "label.who_contacting" | translate }}

    - {{ "label.province" | translate }} - {{ "label.state" | translate }} + {{ "label.province" | + translate }} + {{ "label.state" | translate + }} @@ -604,8 +645,7 @@

    {{ "label.who_contacting" | translate }}

    {{ "label.province_state" | translate }} - {{ + {{ "error.required" | translate }} {{ "error.max_length" | translate }}30 @@ -619,21 +659,23 @@

    {{ "label.who_contacting" | translate }}

    - {{ "label.postal_code" | translate }} - {{ "label.postal_code" | + translate }} + Zip Code - {{ "label.postal_zip" | translate }} - - {{ "error.required" | translate }} + {{ "error.required" | translate + }} {{ "error.postal_zip" | translate }} @@ -649,9 +691,11 @@

    {{ "label.who_contacting" | translate }}

    - - {{ "error.phone_number" | translate }} + + {{ "error.phone_number" | + translate }}
    @@ -660,7 +704,7 @@

    {{ "label.who_contacting" | translate }}

    {{ "label.email_address" | translate }} - + @@ -696,7 +740,8 @@

    {{ "label.who_contacting" | translate }}

    {{ "label.dl_number" | translate }} @@ -739,14 +784,12 @@

    {{ "label.who_contacting" | translate }}

    (click)="reject()"> Reject -
    - +
    diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.ts index 8bb684c22..7f0b7bcc9 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/ticket-info/ticket-info.component.ts @@ -1,6 +1,17 @@ -import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, +} from '@angular/core'; import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { MatLegacyDialog as MatDialog, MatLegacyDialogConfig as MatDialogConfig } from '@angular/material/legacy-dialog'; +import { + MatLegacyDialog as MatDialog, + MatLegacyDialogConfig as MatDialogConfig, +} from '@angular/material/legacy-dialog'; import { ActivatedRoute } from '@angular/router'; import { LoggerService } from '@core/services/logger.service'; import { UtilsService } from '@core/services/utils.service'; @@ -8,13 +19,24 @@ import { FormControlValidators } from '@core/validators/form-control.validators' import { Dispute, DisputeService } from '../../../services/dispute.service'; import { CountryCodeValue, ProvinceCodeValue } from '@config/config.model'; import { ConfigService } from '@config/config.service'; -import { DisputeContactTypeCd, ViolationTicket, ViolationTicketCount, ViolationTicketCountIsAct, ViolationTicketCountIsRegulation, DisputeStatus, DcfTemplateType } from 'app/api'; +import { + DisputeContactTypeCd, + ViolationTicket, + ViolationTicketCount, + ViolationTicketCountIsAct, + ViolationTicketCountIsRegulation, + DisputeStatus, + DcfTemplateType, +} from 'app/api'; import { LookupsService, Statute } from 'app/services/lookups.service'; import { DialogOptions } from '@shared/dialogs/dialog-options.model'; import { ConfirmReasonDialogComponent } from '@shared/dialogs/confirm-reason-dialog/confirm-reason-dialog.component'; import { ConfirmDialogComponent } from '@shared/dialogs/confirm-dialog/confirm-dialog.component'; import { TicketImageDialogComponent } from '@shared/dialogs/ticket-image-dialog/ticket-image-dialog.component'; -import { ViolationTicketService, OCRMessageToDisplay } from 'app/services/violation-ticket.service'; +import { + ViolationTicketService, + OCRMessageToDisplay, +} from 'app/services/violation-ticket.service'; import { StringUtils } from '@core/utils/string-utils.class'; import { TicketImageContainerComponent } from '@shared/dialogs/ticket-image-container/ticket-image-container.component'; @@ -26,7 +48,8 @@ import { TicketImageContainerComponent } from '@shared/dialogs/ticket-image-cont export class TicketInfoComponent implements OnInit { @Input() public disputeInfo: Dispute; @Output() public backInbox: EventEmitter = new EventEmitter(); - @ViewChild(TicketImageContainerComponent) ticketImageContainer: TicketImageContainerComponent; + @ViewChild(TicketImageContainerComponent) + ticketImageContainer: TicketImageContainerComponent; public isMobile: boolean; public previousButtonIcon = 'keyboard_arrow_left'; public validateClicked = false; @@ -47,7 +70,7 @@ export class TicketInfoComponent implements OnInit { public states: ProvinceCodeValue[]; public initialDisputeValues: Dispute; public imageToShow: any; - public errorThreshold: number = 0.800; + public errorThreshold: number = 0.8; public courtLocationFlag: OCRMessageToDisplay; public IsAct = ViolationTicketCountIsAct; public IsRegulation = ViolationTicketCountIsRegulation; @@ -66,8 +89,8 @@ export class TicketInfoComponent implements OnInit { public collapseObj: any = { ticketInformation: true, contactInformation: true, - imageInformation: true - } + imageInformation: true, + }; constructor( protected route: ActivatedRoute, protected formBuilder: FormBuilder, @@ -87,8 +110,14 @@ export class TicketInfoComponent implements OnInit { this.isMobile = this.utilsService.isMobile(); if (this.config.provincesAndStates) { - this.provinces = this.config.provincesAndStates.filter(x => x.ctryId === this.canada.ctryId && x.provAbbreviationCd !== this.bc.provAbbreviationCd); - this.states = this.config.provincesAndStates.filter(x => x.ctryId === this.usa.ctryId); + this.provinces = this.config.provincesAndStates.filter( + (x) => + x.ctryId === this.canada.ctryId && + x.provAbbreviationCd !== this.bc.provAbbreviationCd + ); + this.states = this.config.provincesAndStates.filter( + (x) => x.ctryId === this.usa.ctryId + ); } } @@ -102,7 +131,10 @@ export class TicketInfoComponent implements OnInit { homePhoneNumber: [null, [Validators.maxLength(20)]], emailAddress: [null, [Validators.email, Validators.maxLength(100)]], disputantSurname: [null, [Validators.required, Validators.maxLength(30)]], - disputantGivenNames: [null, [Validators.required, Validators.maxLength(92)]], + disputantGivenNames: [ + null, + [Validators.required, Validators.maxLength(92)], + ], contactTypeCd: [null, [Validators.required]], contactSurnameNm: [null, [Validators.maxLength(30)]], contactGivenNames: [null, [Validators.maxLength(92)]], @@ -115,7 +147,10 @@ export class TicketInfoComponent implements OnInit { addressProvinceCountryId: [null], addressProvinceSeqNo: [null], postalCode: [null], // space needs to be added back to the middle for display - driversLicenceNumber: [null, [Validators.minLength(7), Validators.maxLength(9)]], + driversLicenceNumber: [ + null, + [Validators.minLength(7), Validators.maxLength(9)], + ], driversLicenceProvince: [null, [Validators.maxLength(30)]], driversLicenceProvinceProvId: [null], driversLicenceCountryId: [null], @@ -124,9 +159,18 @@ export class TicketInfoComponent implements OnInit { violationTicket: this.formBuilder.group({ ticketNumber: [null, Validators.required], courtLocation: [null, [Validators.required, Validators.maxLength(50)]], - disputantSurname: [null, [Validators.required, Validators.maxLength(30)]], - disputantGivenNames: [null, [Validators.required, Validators.maxLength(92)]], - disputantDriversLicenceNumber: [null, [Validators.minLength(7), Validators.maxLength(9)]], + disputantSurname: [ + null, + [Validators.required, Validators.maxLength(30)], + ], + disputantGivenNames: [ + null, + [Validators.required, Validators.maxLength(92)], + ], + disputantDriversLicenceNumber: [ + null, + [Validators.minLength(7), Validators.maxLength(9)], + ], driversLicenceProvince: [null, [Validators.maxLength(30)]], driversLicenceCountry: [null], issuedTs: [null, Validators.required], @@ -138,7 +182,7 @@ export class TicketInfoComponent implements OnInit { subsection: [null], paragraph: [null], fullDescription: [null], - ticketedAmount: [null, [FormControlValidators.currency]] + ticketedAmount: [null, [FormControlValidators.currency]], }), violationTicketCount2: this.formBuilder.group({ actOrRegulationNameCode: [null], @@ -148,7 +192,7 @@ export class TicketInfoComponent implements OnInit { subsection: [null], paragraph: [null], fullDescription: [null], - ticketedAmount: [null, [FormControlValidators.currency]] + ticketedAmount: [null, [FormControlValidators.currency]], }), violationTicketCount3: this.formBuilder.group({ actOrRegulationNameCode: [null], @@ -158,25 +202,43 @@ export class TicketInfoComponent implements OnInit { subsection: [null], paragraph: [null], fullDescription: [null], - ticketedAmount: [null, [FormControlValidators.currency]] + ticketedAmount: [null, [FormControlValidators.currency]], }), - violationDate: [null, [Validators.required]], // api returns issued date, extract date from that - violationTime: [null, [Validators.required, Validators.pattern(/^(0[0-9]|1[0-9]|2[0-3])[0-5][0-9]$/)]], // api returns issued date, extract time from that - }) + violationDate: [null, [Validators.required]], // api returns issued date, extract date from that + violationTime: [ + null, + [ + Validators.required, + Validators.pattern(/^(0[0-9]|1[0-9]|2[0-3])[0-5][0-9]$/), + ], + ], // api returns issued date, extract time from that + }), }); // Custom validator for driversLicenceNumber - this.form.get('violationTicket').get('driversLicenceProvince').valueChanges.subscribe(value => { - if (value === this.bc.provAbbreviationCd) { - this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([ - Validators.maxLength(9), - Validators.minLength(7), - Validators.pattern(/^\d+$/) // Only numeric values - ]); - } else { - this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([Validators.maxLength(20)]); - } - this.form.get('violationTicket').get('disputantDriversLicenceNumber').updateValueAndValidity(); - }); + this.form + .get('violationTicket') + .get('driversLicenceProvince') + .valueChanges.subscribe((value) => { + if (value === this.bc.provAbbreviationCd) { + this.form + .get('violationTicket') + .get('disputantDriversLicenceNumber') + .setValidators([ + Validators.maxLength(9), + Validators.minLength(7), + Validators.pattern(/^\d+$/), // Only numeric values + ]); + } else { + this.form + .get('violationTicket') + .get('disputantDriversLicenceNumber') + .setValidators([Validators.maxLength(20)]); + } + this.form + .get('violationTicket') + .get('disputantDriversLicenceNumber') + .updateValueAndValidity(); + }); // retreive fresh copy from db this.getDispute(); } @@ -212,87 +274,128 @@ export class TicketInfoComponent implements OnInit { } public onCountryChange(ctryId: number) { - setTimeout(() => { this.form.get('postalCode').setValidators([Validators.maxLength(6)]); - this.form.get('addressProvince').setValidators([Validators.maxLength(30)]); + this.form + .get('addressProvince') + .setValidators([Validators.maxLength(30)]); this.form.get('addressProvince').setValue(null); this.form.get('addressProvinceSeqNo').setValidators(null); this.form.get('addressProvinceSeqNo').setValue(null); this.form.get('addressProvinceCountryId').setValue(null); this.form.get('addressProvinceProvId').setValue(null); - this.form.get('homePhoneNumber').setValidators([Validators.maxLength(20)]); - this.form.get('driversLicenceProvince').setValidators([Validators.maxLength(30)]); - this.form.get("driversLicenceProvinceSeqNo").setValidators(null); + this.form + .get('homePhoneNumber') + .setValidators([Validators.maxLength(20)]); + this.form + .get('driversLicenceProvince') + .setValidators([Validators.maxLength(30)]); + this.form.get('driversLicenceProvinceSeqNo').setValidators(null); if (ctryId === this.canada.ctryId || ctryId == this.usa.ctryId) { - this.form.get('addressProvinceSeqNo').addValidators([Validators.required]); + this.form + .get('addressProvinceSeqNo') + .addValidators([Validators.required]); this.form.get('postalCode').addValidators([Validators.required]); - this.form.get('homePhoneNumber').addValidators([FormControlValidators.phone]); + this.form + .get('homePhoneNumber') + .addValidators([FormControlValidators.phone]); } if (ctryId == this.canada.ctryId) { - this.form.get('postalCode').addValidators([Validators.minLength(6)]); + this.form.get('postalCode').addValidators([Validators.minLength(6)]); this.form.get('addressProvinceCountryId').setValue(ctryId); - this.form.get("addressProvinceSeqNo").setValue(this.bc.provSeqNo); - this.form.get("addressProvinceProvId").setValue(this.bc.provId); - this.form.get("addressProvince").setValue(this.bc.provAbbreviationCd); + this.form.get('addressProvinceSeqNo').setValue(this.bc.provSeqNo); + this.form.get('addressProvinceProvId').setValue(this.bc.provId); + this.form.get('addressProvince').setValue(this.bc.provAbbreviationCd); } this.form.get('postalCode').updateValueAndValidity(); this.form.get('addressProvince').updateValueAndValidity(); - this.form.get("addressProvinceCountryId").updateValueAndValidity(); - this.form.get("addressProvinceSeqNo").updateValueAndValidity(); - this.form.get("addressProvinceProvId").updateValueAndValidity(); + this.form.get('addressProvinceCountryId').updateValueAndValidity(); + this.form.get('addressProvinceSeqNo').updateValueAndValidity(); + this.form.get('addressProvinceProvId').updateValueAndValidity(); this.form.get('homePhoneNumber').updateValueAndValidity(); this.form.get('driversLicenceProvince').updateValueAndValidity(); - this.form.get("driversLicenceProvinceSeqNo").updateValueAndValidity(); + this.form.get('driversLicenceProvinceSeqNo').updateValueAndValidity(); }, 5); } onFullDescription1Keyup() { - this.filteredCount1Statutes = this.filterStatutes(this.form.get('violationTicket').get('violationTicketCount1').get('fullDescription').value); + this.filteredCount1Statutes = this.filterStatutes( + this.form + .get('violationTicket') + .get('violationTicketCount1') + .get('fullDescription').value + ); } onFullDescription2Keyup() { - this.filteredCount2Statutes = this.filterStatutes(this.form.get('violationTicket').get('violationTicketCount2').get('fullDescription').value); + this.filteredCount2Statutes = this.filterStatutes( + this.form + .get('violationTicket') + .get('violationTicketCount2') + .get('fullDescription').value + ); } onFullDescription3Keyup() { - this.filteredCount3Statutes = this.filterStatutes(this.form.get('violationTicket').get('violationTicketCount3').get('fullDescription').value); + this.filteredCount3Statutes = this.filterStatutes( + this.form + .get('violationTicket') + .get('violationTicketCount3') + .get('fullDescription').value + ); } // return a filtered list of statutes public filterStatutes(val: string): Statute[] { - if (!this.lookupsService.statutes || this.lookupsService.statutes.length == 0) return []; - return this.lookupsService.statutes?.filter(option => (option.__statuteString || "").toUpperCase().indexOf((val || "").toUpperCase()) >= 0); + if ( + !this.lookupsService.statutes || + this.lookupsService.statutes.length == 0 + ) + return []; + return this.lookupsService.statutes?.filter( + (option) => + (option.__statuteString || '') + .toUpperCase() + .indexOf((val || '').toUpperCase()) >= 0 + ); } // is the statute valid? on the form public isStatuteValid(countNo: number): boolean { - let countForm = this.form.get('violationTicket').get('violationTicketCount' + countNo.toString()); - if (countForm.get('fullDescription').value && !countForm.get('section').value && - countForm.get('fullDescription').value !== " ") + let countForm = this.form + .get('violationTicket') + .get('violationTicketCount' + countNo.toString()); + if ( + countForm.get('fullDescription').value && + !countForm.get('section').value && + countForm.get('fullDescription').value !== ' ' + ) return false; return true; } public resendEmailVerification() { - this.disputeService.resendEmailVerification(this.lastUpdatedDispute.disputeId) - .subscribe(email => { + this.disputeService + .resendEmailVerification(this.lastUpdatedDispute.disputeId) + .subscribe((email) => { const data: DialogOptions = { - titleKey: "Email Verification Resent", - icon: "email", - actionType: "green", + titleKey: 'Email Verification Resent', + icon: 'email', + actionType: 'green', messageKey: - "The email verification has been resent to the contact email address provided.\n\n" + this.lastUpdatedDispute.emailAddress, - actionTextKey: "Ok", - cancelHide: true + 'The email verification has been resent to the contact email address provided.\n\n' + + this.lastUpdatedDispute.emailAddress, + actionTextKey: 'Ok', + cancelHide: true, }; - this.dialog.open(ConfirmDialogComponent, { data }).afterClosed() - .subscribe((action: any) => { - }); - }) + this.dialog + .open(ConfirmDialogComponent, { data }) + .afterClosed() + .subscribe((action: any) => {}); + }); } public onExpandTicketImage(event: MouseEvent) { @@ -309,82 +412,138 @@ export class TicketInfoComponent implements OnInit { // violation ticket borders only for new status public applyOverErrThreshold(fieldName: string): boolean { if (this.lastUpdatedDispute.status != this.DispStatus.New) return false; - if (this.lastUpdatedDispute.violationTicket.ocrViolationTicket && this.lastUpdatedDispute.violationTicket.ocrViolationTicket.fields[fieldName]?.fieldConfidence <= 0.80) return false; + if ( + this.lastUpdatedDispute.violationTicket.ocrViolationTicket && + this.lastUpdatedDispute.violationTicket.ocrViolationTicket.fields[ + fieldName + ]?.fieldConfidence <= 0.8 + ) + return false; return true; } public applyUnderErrThreshold(fieldName: string): boolean { if (this.lastUpdatedDispute.status != this.DispStatus.New) return false; - if (this.lastUpdatedDispute.violationTicket.ocrViolationTicket && this.lastUpdatedDispute.violationTicket.ocrViolationTicket.fields[fieldName]?.fieldConfidence > 0.80) return false; + if ( + this.lastUpdatedDispute.violationTicket.ocrViolationTicket && + this.lastUpdatedDispute.violationTicket.ocrViolationTicket.fields[ + fieldName + ]?.fieldConfidence > 0.8 + ) + return false; return true; } // change validators on drivers licence number in violation ticket when changing province / state public onViolationTicketDLProvinceChange(provAbbreviationCd: string) { - setTimeout(() => { - if(provAbbreviationCd === null){ - this.form.get('violationTicket').get('driversLicenceCountry').setValue(null); - this.form.get('violationTicket').get('driversLicenceProvince').setValue(null); - this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([Validators.maxLength(20)]); - } else{ + if (provAbbreviationCd === null) { + this.form + .get('violationTicket') + .get('driversLicenceCountry') + .setValue(null); + this.form + .get('violationTicket') + .get('driversLicenceProvince') + .setValue(null); + this.form + .get('violationTicket') + .get('disputantDriversLicenceNumber') + .setValidators([Validators.maxLength(20)]); + } else { if (provAbbreviationCd == this.bc.provAbbreviationCd) { - this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([ - Validators.maxLength(9), - Validators.minLength(7), - Validators.pattern(/^\d+$/) - ]); + this.form + .get('violationTicket') + .get('disputantDriversLicenceNumber') + .setValidators([ + Validators.maxLength(9), + Validators.minLength(7), + Validators.pattern(/^\d+$/), + ]); } else { - this.form.get('violationTicket').get('disputantDriversLicenceNumber').setValidators([Validators.maxLength(20)]); + this.form + .get('violationTicket') + .get('disputantDriversLicenceNumber') + .setValidators([Validators.maxLength(20)]); } - let provFound = this.config.provincesAndStates.filter(x => x.provAbbreviationCd === provAbbreviationCd).shift(); + let provFound = this.config.provincesAndStates + .filter((x) => x.provAbbreviationCd === provAbbreviationCd) + .shift(); if (provFound) { - let ctryFound = this.config.countries.filter(x => x.ctryId === provFound.ctryId).shift(); - this.form.get('violationTicket').get('driversLicenceCountry').setValue(ctryFound.ctryLongNm); + let ctryFound = this.config.countries + .filter((x) => x.ctryId === provFound.ctryId) + .shift(); + this.form + .get('violationTicket') + .get('driversLicenceCountry') + .setValue(ctryFound.ctryLongNm); } } - this.form.get('violationTicket').get('disputantDriversLicenceNumber').markAsTouched(); - this.form.get('violationTicket').get('disputantDriversLicenceNumber').markAsDirty(); - this.form.get('violationTicket').get('disputantDriversLicenceNumber').updateValueAndValidity(); - }, 5) + this.form + .get('violationTicket') + .get('disputantDriversLicenceNumber') + .markAsTouched(); + this.form + .get('violationTicket') + .get('disputantDriversLicenceNumber') + .markAsDirty(); + this.form + .get('violationTicket') + .get('disputantDriversLicenceNumber') + .updateValueAndValidity(); + }, 5); } public onAddressProvinceChange(provId: number) { setTimeout(() => { - let provFound = this.config.provincesAndStates.filter(x => x.provId === provId).shift(); - this.form.get("addressProvinceCountryId").setValue(provFound.ctryId); - this.form.get("addressProvinceSeqNo").setValue(provFound.provSeqNo); - this.form.get("addressProvinceProvId").setValue(provFound.provId); - this.form.get("addressProvince").setValue(provFound.provAbbreviationCd); - }, 0) + let provFound = this.config.provincesAndStates + .filter((x) => x.provId === provId) + .shift(); + this.form.get('addressProvinceCountryId').setValue(provFound.ctryId); + this.form.get('addressProvinceSeqNo').setValue(provFound.provSeqNo); + this.form.get('addressProvinceProvId').setValue(provFound.provId); + this.form.get('addressProvince').setValue(provFound.provAbbreviationCd); + }, 0); } // change validators on drivers licence number in notice of dispute when changing province / state public onNoticeOfDisputeDLProvinceChange(provId: number) { setTimeout(() => { - if(provId === null){ - this.form.get("driversLicenceProvince").setValue(null); - this.form.get("driversLicenceCountryId").setValue(null); - this.form.get("driversLicenceProvinceSeqNo").setValue(null); - this.form.get('driversLicenceNumber').setValidators([Validators.maxLength(20)]); - } else{ - let provFound = this.config.provincesAndStates.filter(x => x.provId === provId).shift(); - this.form.get("driversLicenceCountryId").setValue(provFound.ctryId); - this.form.get("driversLicenceProvinceSeqNo").setValue(provFound.provSeqNo); + if (provId === null) { + this.form.get('driversLicenceProvince').setValue(null); + this.form.get('driversLicenceCountryId').setValue(null); + this.form.get('driversLicenceProvinceSeqNo').setValue(null); + this.form + .get('driversLicenceNumber') + .setValidators([Validators.maxLength(20)]); + } else { + let provFound = this.config.provincesAndStates + .filter((x) => x.provId === provId) + .shift(); + this.form.get('driversLicenceCountryId').setValue(provFound.ctryId); + this.form + .get('driversLicenceProvinceSeqNo') + .setValue(provFound.provSeqNo); if (provId === this.bc.provId) { - this.form.get('driversLicenceNumber').setValidators([Validators.maxLength(9)]); - this.form.get('driversLicenceNumber').addValidators([Validators.minLength(7)]); + this.form + .get('driversLicenceNumber') + .setValidators([Validators.maxLength(9)]); + this.form + .get('driversLicenceNumber') + .addValidators([Validators.minLength(7)]); } else { - this.form.get('driversLicenceNumber').setValidators([Validators.maxLength(20)]); - } + this.form + .get('driversLicenceNumber') + .setValidators([Validators.maxLength(20)]); + } } this.form.get('driversLicenceNumber').updateValueAndValidity(); this.onFieldChange(); - }, 5) + }, 5); } onKeyPressNumbers(event: any, BCOnly: boolean) { - var charCode = (event.which) ? event.which : event.keyCode; + var charCode = event.which ? event.which : event.keyCode; // Only Numbers 0-9 if ((charCode < 48 || charCode > 57) && BCOnly) { event.preventDefault(); @@ -395,49 +554,86 @@ export class TicketInfoComponent implements OnInit { } public onSubmitViolationTicket(): void { - // We are only sending the violation Ticket fields so update a local copy of lastUpdatedDispute // with violation Ticket form fields only that were changed let putDispute = this.lastUpdatedDispute; - putDispute.violationTicket.ticketNumber = this.form.get('violationTicket').get('ticketNumber').value; - putDispute.violationTicket.disputantSurname = this.form.get('violationTicket').get('disputantSurname').value; - putDispute.violationTicket.disputantGivenNames = this.form.get('violationTicket').get('disputantGivenNames').value; - putDispute.violationTicket.disputantDriversLicenceNumber = this.form.get('violationTicket').get('disputantDriversLicenceNumber').value; - putDispute.violationTicket.driversLicenceProvince = this.form.get('violationTicket').get('driversLicenceProvince').value; - putDispute.violationTicket.driversLicenceCountry = this.form.get('violationTicket').get('driversLicenceCountry').value; - putDispute.violationTicket.courtLocation = this.form.get('violationTicket').get('courtLocation').value; + putDispute.violationTicket.ticketNumber = this.form + .get('violationTicket') + .get('ticketNumber').value; + putDispute.violationTicket.disputantSurname = this.form + .get('violationTicket') + .get('disputantSurname').value; + putDispute.violationTicket.disputantGivenNames = this.form + .get('violationTicket') + .get('disputantGivenNames').value; + putDispute.violationTicket.disputantDriversLicenceNumber = this.form + .get('violationTicket') + .get('disputantDriversLicenceNumber').value; + putDispute.violationTicket.driversLicenceProvince = this.form + .get('violationTicket') + .get('driversLicenceProvince').value; + putDispute.violationTicket.driversLicenceCountry = this.form + .get('violationTicket') + .get('driversLicenceCountry').value; + putDispute.violationTicket.courtLocation = this.form + .get('violationTicket') + .get('courtLocation').value; // reconstruct issued date as string from violation date and violation time format yyyy-mm-ddTHH:mm putDispute.violationTicket.issuedTs = this.form.get('violationTicket').get('violationDate').value + - "T" + - this.form.get('violationTicket').get('violationTime').value.substring(0, 2) - + ":" + - this.form.get('violationTicket').get('violationTime').value.substring(2, 4) + "Z"; - putDispute.issuedTs = this.form.get('violationTicket').get('violationDate').value + - "T" + - this.form.get('violationTicket').get('violationTime').value.substring(0, 2) - + ":" + - this.form.get('violationTicket').get('violationTime').value.substring(2, 4) + ":00Z";; + 'T' + + this.form + .get('violationTicket') + .get('violationTime') + .value.substring(0, 2) + + ':' + + this.form + .get('violationTicket') + .get('violationTime') + .value.substring(2, 4) + + 'Z'; + putDispute.issuedTs = + this.form.get('violationTicket').get('violationDate').value + + 'T' + + this.form + .get('violationTicket') + .get('violationTime') + .value.substring(0, 2) + + ':' + + this.form + .get('violationTicket') + .get('violationTime') + .value.substring(2, 4) + + ':00Z'; // Counts 1,2,3 - putDispute.violationTicket.violationTicketCounts = [] as ViolationTicketCount[]; + putDispute.violationTicket.violationTicketCounts = + [] as ViolationTicketCount[]; for (let i = 1; i <= 3; i++) { // stuff 3 violation ticket counts in putDispute - let violationTicketCount = this.form.get('violationTicket').get('violationTicketCount' + i.toString()).value as ViolationTicketCount; + let violationTicketCount = this.form + .get('violationTicket') + .get('violationTicketCount' + i.toString()) + .value as ViolationTicketCount; violationTicketCount.countNo = i; - violationTicketCount.ticketedAmount = this.form.get('violationTicket').get('violationTicketCount' + i.toString()).get('ticketedAmount').value; - putDispute.violationTicket.violationTicketCounts = [...putDispute.violationTicket.violationTicketCounts, violationTicketCount]; + violationTicketCount.ticketedAmount = this.form + .get('violationTicket') + .get('violationTicketCount' + i.toString()) + .get('ticketedAmount').value; + putDispute.violationTicket.violationTicketCounts = [ + ...putDispute.violationTicket.violationTicketCounts, + violationTicketCount, + ]; } this.logger.log('TicketInfoComponent::putDispute', putDispute); this.lastUpdatedDispute = putDispute; - if(this.validateClicked) { + if (this.validateClicked) { this.validate(putDispute); - } - else { + } else { this.putDispute(putDispute); } } @@ -448,23 +644,37 @@ export class TicketInfoComponent implements OnInit { let putDispute = this.lastUpdatedDispute; putDispute.disputantSurname = this.form.get('disputantSurname').value; putDispute.disputantGivenNames = this.form.get('disputantGivenNames').value; - putDispute.driversLicenceNumber = this.form.get('driversLicenceNumber').value; - putDispute.driversLicenceProvince = this.form.get('driversLicenceProvince').value; - putDispute.driversLicenceIssuedCountryId = this.form.get('driversLicenceCountryId').value; - putDispute.driversLicenceIssuedProvinceSeqNo = this.form.get('driversLicenceProvinceSeqNo').value; + putDispute.driversLicenceNumber = this.form.get( + 'driversLicenceNumber' + ).value; + putDispute.driversLicenceProvince = this.form.get( + 'driversLicenceProvince' + ).value; + putDispute.driversLicenceIssuedCountryId = this.form.get( + 'driversLicenceCountryId' + ).value; + putDispute.driversLicenceIssuedProvinceSeqNo = this.form.get( + 'driversLicenceProvinceSeqNo' + ).value; putDispute.homePhoneNumber = this.form.get('homePhoneNumber').value; putDispute.emailAddress = this.form.get('emailAddress').value; putDispute.address = this.form.get('address').value; putDispute.addressCity = this.form.get('addressCity').value; putDispute.addressProvince = this.form.get('addressProvince').value; - putDispute.addressProvinceCountryId = this.form.get('addressProvinceCountryId').value; - putDispute.addressProvinceSeqNo = this.form.get('addressProvinceSeqNo').value; + putDispute.addressProvinceCountryId = this.form.get( + 'addressProvinceCountryId' + ).value; + putDispute.addressProvinceSeqNo = this.form.get( + 'addressProvinceSeqNo' + ).value; putDispute.addressCountryId = this.form.get('addressCountryId').value; putDispute.postalCode = this.form.get('postalCode').value; putDispute.rejectedReason = this.form.get('rejectedReason').value; // set dispute courtagenid from violation ticket courthouse location - let courtFound = this.lookupsService.courthouseAgencies.filter(x => x.name === putDispute.violationTicket.courtLocation).shift(); + let courtFound = this.lookupsService.courthouseAgencies + .filter((x) => x.name === putDispute.violationTicket.courtLocation) + .shift(); putDispute.courtAgenId = courtFound?.id; this.logger.log('TicketInfoComponent::putDispute', putDispute); @@ -474,25 +684,38 @@ export class TicketInfoComponent implements OnInit { } // decompose string into subparagraph, section, subsection, paragraph - public unLegalParagraph(statuteLegalParagraphing: string): { subparagraph: string, section: string, subsection: string, paragraph: string } { - let allParts = statuteLegalParagraphing.split("("); - let subparagraph = ""; - let section = ""; - let subsection = ""; - let paragraph = ""; + public unLegalParagraph(statuteLegalParagraphing: string): { + subparagraph: string; + section: string; + subsection: string; + paragraph: string; + } { + let allParts = statuteLegalParagraphing.split('('); + let subparagraph = ''; + let section = ''; + let subsection = ''; + let paragraph = ''; // parts are section(section)(subsection)(paragraph)(subparagraph) if all are present // extract substrings but dont include final ')' of each part - if (allParts.length > 0) section = allParts[0].substring(0, allParts[0].length); - if (allParts.length > 1) subsection = allParts[1].substring(0, allParts[1].length - 1); - if (allParts.length > 2) paragraph = allParts[2].substring(0, allParts[2].length - 1); - if (allParts.length > 3) subparagraph = allParts[3].substring(0, allParts[3].length - 1); - - return { subparagraph: subparagraph, section: section, subsection: subsection, paragraph: paragraph }; + if (allParts.length > 0) + section = allParts[0].substring(0, allParts[0].length); + if (allParts.length > 1) + subsection = allParts[1].substring(0, allParts[1].length - 1); + if (allParts.length > 2) + paragraph = allParts[2].substring(0, allParts[2].length - 1); + if (allParts.length > 3) + subparagraph = allParts[3].substring(0, allParts[3].length - 1); + + return { + subparagraph: subparagraph, + section: section, + subsection: subsection, + paragraph: paragraph, + }; } public enableNoticeOfDisputeSave(): boolean { - // check for fields invalid in contact information only if (this.form.get('emailAddress').invalid) return false; if (this.form.get('homePhoneNumber').invalid) return false; @@ -538,22 +761,32 @@ export class TicketInfoComponent implements OnInit { } public handleCollapse(name: string) { - this.collapseObj[name] = !this.collapseObj[name] + this.collapseObj[name] = !this.collapseObj[name]; } // get legal paragraphing for a particular count - public getCountLegalParagraphing(countNumber: number, violationTicket: ViolationTicket): string { - let violationTicketCount = violationTicket.violationTicketCounts?.filter(x => x.countNo == countNumber)[0]; + public getCountLegalParagraphing( + countNumber: number, + violationTicket: ViolationTicket + ): string { + let violationTicketCount = violationTicket.violationTicketCounts?.filter( + (x) => x.countNo == countNumber + )[0]; if (violationTicketCount) { - let desc = (this.violationTicketService - .getLegalParagraphing(violationTicketCount) + (violationTicketCount.description ? " " + violationTicketCount.description : "")); + let desc = + this.violationTicketService.getLegalParagraphing(violationTicketCount) + + (violationTicketCount.description + ? ' ' + violationTicketCount.description + : ''); return desc; - } - else return ""; + } else return ''; } // put dispute by id - putDispute(dispute: Dispute, isSubmittingNoticeOfDispute: boolean = false): void { + putDispute( + dispute: Dispute, + isSubmittingNoticeOfDispute: boolean = false + ): void { this.logger.log('TicketInfoComponent::putDispute', dispute); // no need to pass back byte array with image @@ -561,58 +794,69 @@ export class TicketInfoComponent implements OnInit { tempDispute.violationTicket.violationTicketImage = null; const data: DialogOptions = { - titleKey: "Enter File History Comment", - messageKey: "Please describe the changes you made to the dispute.", - actionTextKey: "Save", - actionType: "primary", - cancelTextKey: "Go back", - icon: "error_outline" + titleKey: 'Enter File History Comment', + messageKey: 'Please describe the changes you made to the dispute.', + actionTextKey: 'Save', + actionType: 'primary', + cancelTextKey: 'Go back', + icon: 'error_outline', }; - this.dialog.open(ConfirmReasonDialogComponent, { data }).afterClosed() + this.dialog + .open(ConfirmReasonDialogComponent, { data }) + .afterClosed() .subscribe((action?: any) => { if (action?.output?.response) { - this.disputeService.putDispute(dispute.disputeId, action?.output?.reason, tempDispute).subscribe((response: Dispute) => { - this.logger.info( - 'TicketInfoComponent::putDispute response', - response - ); - this.isViolationTicketCountDeleted = false; - if (!isSubmittingNoticeOfDispute) { - // markAsUntouched form group - this.form.get('violationTicket').markAsUntouched(); - } else { - // markAsUntouched notice of dispute fields - this.form.get('disputantSurname').markAsUntouched(); - this.form.get('disputantGivenNames').markAsUntouched(); - this.form.get('driversLicenceNumber').markAsUntouched(); - this.form.get('driversLicenceProvince').markAsUntouched(); - this.form.get('driversLicenceCountryId').markAsUntouched(); - this.form.get('driversLicenceProvinceSeqNo').markAsUntouched(); - this.form.get('driversLicenceProvinceProvId').markAsUntouched(); - this.form.get('homePhoneNumber').markAsUntouched(); - this.form.get('emailAddress').markAsUntouched(); - this.form.get('address').markAsUntouched(); - this.form.get('addressCity').markAsUntouched(); - this.form.get('addressProvince').markAsUntouched(); - this.form.get('addressProvinceSeqNo').markAsUntouched(); - this.form.get('addressProvinceCountryId').markAsUntouched(); - this.form.get('addressProvinceProvId').markAsUntouched(); - this.form.get('addressCountryId').markAsUntouched(); - this.form.get('postalCode').markAsUntouched(); - this.form.get('rejectedReason').markAsUntouched(); - } - }); + this.disputeService + .putDispute(dispute.disputeId, action?.output?.reason, tempDispute) + .subscribe((response: Dispute) => { + this.logger.info( + 'TicketInfoComponent::putDispute response', + response + ); + this.isViolationTicketCountDeleted = false; + if (!isSubmittingNoticeOfDispute) { + // markAsUntouched form group + this.form.get('violationTicket').markAsUntouched(); + } else { + // markAsUntouched notice of dispute fields + this.form.get('disputantSurname').markAsUntouched(); + this.form.get('disputantGivenNames').markAsUntouched(); + this.form.get('driversLicenceNumber').markAsUntouched(); + this.form.get('driversLicenceProvince').markAsUntouched(); + this.form.get('driversLicenceCountryId').markAsUntouched(); + this.form.get('driversLicenceProvinceSeqNo').markAsUntouched(); + this.form.get('driversLicenceProvinceProvId').markAsUntouched(); + this.form.get('homePhoneNumber').markAsUntouched(); + this.form.get('emailAddress').markAsUntouched(); + this.form.get('address').markAsUntouched(); + this.form.get('addressCity').markAsUntouched(); + this.form.get('addressProvince').markAsUntouched(); + this.form.get('addressProvinceSeqNo').markAsUntouched(); + this.form.get('addressProvinceCountryId').markAsUntouched(); + this.form.get('addressProvinceProvId').markAsUntouched(); + this.form.get('addressCountryId').markAsUntouched(); + this.form.get('postalCode').markAsUntouched(); + this.form.get('rejectedReason').markAsUntouched(); + } + }); } }); } // use violationTicket Service setFieldsFromJSON(dispute: Dispute): Dispute { - if (dispute.violationTicket?.ocrViolationTicket && dispute.violationTicket?.ocrViolationTicket?.fields) { + if ( + dispute.violationTicket?.ocrViolationTicket && + dispute.violationTicket?.ocrViolationTicket?.fields + ) { var fields = dispute.violationTicket?.ocrViolationTicket.fields; - dispute.violationTicket = this.violationTicketService.setViolationTicketFromJSON(dispute.violationTicket.ocrViolationTicket, dispute.violationTicket); + dispute.violationTicket = + this.violationTicketService.setViolationTicketFromJSON( + dispute.violationTicket.ocrViolationTicket, + dispute.violationTicket + ); } return dispute; @@ -624,42 +868,45 @@ export class TicketInfoComponent implements OnInit { let tempDispute = dispute; tempDispute.violationTicket.violationTicketImage = null; - this.disputeService.validateDispute(this.lastUpdatedDispute.disputeId, tempDispute).subscribe({ - next: response => { - this.lastUpdatedDispute.status = this.DispStatus.Validated; - this.form.controls.violationTicket.disable(); - }, - error: err => { }, - complete: () => { } - }); + this.disputeService + .validateDispute(this.lastUpdatedDispute.disputeId, tempDispute) + .subscribe({ + next: (response) => { + this.lastUpdatedDispute.status = this.DispStatus.Validated; + this.form.controls.violationTicket.disable(); + }, + error: (err) => {}, + complete: () => {}, + }); } // dialog, if ok then send to api, on return update status, return to TRM home public approve(): void { const data: DialogOptions = { - titleKey: "Approve ticket resolution request?", + titleKey: 'Approve ticket resolution request?', messageKey: - "Once you approve this request, the information will be sent to ICBC. Are you sure you are ready to approve and submit this request to ARC?", - actionTextKey: "Approve and send request", - actionType: "green", - cancelTextKey: "Go back", - icon: "error_outline", + 'Once you approve this request, the information will be sent to ICBC. Are you sure you are ready to approve and submit this request to ARC?', + actionTextKey: 'Approve and send request', + actionType: 'green', + cancelTextKey: 'Go back', + icon: 'error_outline', }; - this.dialog.open(ConfirmDialogComponent, { data }).afterClosed() + this.dialog + .open(ConfirmDialogComponent, { data }) + .afterClosed() .subscribe((action: any) => { if (action) { - // submit dispute and return to TRM home - this.disputeService.submitDispute(this.lastUpdatedDispute.disputeId).subscribe( - { - next: response => { + this.disputeService + .submitDispute(this.lastUpdatedDispute.disputeId) + .subscribe({ + next: (response) => { this.lastUpdatedDispute.status = this.DispStatus.Processing; this.onBack(); }, - error: err => { }, - complete: () => { } - } - ); + error: (err) => {}, + complete: () => {}, + }); } }); } @@ -667,31 +914,38 @@ export class TicketInfoComponent implements OnInit { // dialog, if ok then send to api, on return update status, return to TRM home public reject(): void { const data: DialogOptions = { - titleKey: "Reject ticket resolution request?", + titleKey: 'Reject ticket resolution request?', messageKey: - "Please enter the reason this request is being rejected. This information will be sent to the user in email notification.", - actionTextKey: "Send rejection notification", - actionType: "warn", - cancelTextKey: "Go back", - icon: "error_outline", - message: "" + 'Please enter the reason this request is being rejected. This information will be sent to the user in email notification.', + actionTextKey: 'Send rejection notification', + actionType: 'warn', + cancelTextKey: 'Go back', + icon: 'error_outline', + message: '', }; - this.dialog.open(ConfirmReasonDialogComponent, { data }).afterClosed() + this.dialog + .open(ConfirmReasonDialogComponent, { data }) + .afterClosed() .subscribe((action?: any) => { if (action?.output?.response) { this.form.get('rejectedReason').setValue(action.output.reason); // update on form for appearances this.lastUpdatedDispute.rejectedReason = action.output.reason; // update to send back on put // udate the reason entered, reject dispute and return to TRM home - this.disputeService.rejectDispute(this.lastUpdatedDispute.disputeId, this.lastUpdatedDispute.rejectedReason).subscribe({ - next: response => { - this.onBack(); - this.lastUpdatedDispute.status = this.DispStatus.Rejected; - this.lastUpdatedDispute.rejectedReason = action.output.reason; - }, - error: err => { }, - complete: () => { } - }); + this.disputeService + .rejectDispute( + this.lastUpdatedDispute.disputeId, + this.lastUpdatedDispute.rejectedReason + ) + .subscribe({ + next: (response) => { + this.onBack(); + this.lastUpdatedDispute.status = this.DispStatus.Rejected; + this.lastUpdatedDispute.rejectedReason = action.output.reason; + }, + error: (err) => {}, + complete: () => {}, + }); } }); } @@ -699,16 +953,18 @@ export class TicketInfoComponent implements OnInit { // dialog, if ok then send to api, on return update status, return to TRM home public cancel(): void { const data: DialogOptions = { - titleKey: "Cancel ticket resolution request?", + titleKey: 'Cancel ticket resolution request?', messageKey: - "Please enter the reason this request is being cancelled. This information will be sent to the user in email notification.", - actionTextKey: "Send cancellation notification", - actionType: "warn", - cancelTextKey: "Go back", - icon: "error_outline", - message: "" + 'Please enter the reason this request is being cancelled. This information will be sent to the user in email notification.', + actionTextKey: 'Send cancellation notification', + actionType: 'warn', + cancelTextKey: 'Go back', + icon: 'error_outline', + message: '', }; - this.dialog.open(ConfirmReasonDialogComponent, { data }).afterClosed() + this.dialog + .open(ConfirmReasonDialogComponent, { data }) + .afterClosed() .subscribe((action?: any) => { if (action?.output?.response) { this.form.get('rejectedReason').setValue(action.output.reason); // update on form for appearances @@ -719,35 +975,52 @@ export class TicketInfoComponent implements OnInit { delete tempDispute.violationTicket.violationTicketImage; // udate the reason entered, cancel dispute and return to TRM home since this will be filtered out - this.disputeService.cancelDispute(this.lastUpdatedDispute.disputeId, action.output.reason).subscribe({ - next: response => { - this.lastUpdatedDispute.status = this.DispStatus.Cancelled; - this.lastUpdatedDispute.rejectedReason = action.output.reason; - this.onBack(); - }, - error: err => { }, - complete: () => { } - }); + this.disputeService + .cancelDispute( + this.lastUpdatedDispute.disputeId, + action.output.reason + ) + .subscribe({ + next: (response) => { + this.lastUpdatedDispute.status = this.DispStatus.Cancelled; + this.lastUpdatedDispute.rejectedReason = action.output.reason; + this.onBack(); + }, + error: (err) => {}, + complete: () => {}, + }); } }); } // count description changed in form onChangeCount(countNo: number, fullDescription: string) { - let countForm = this.form.get('violationTicket').get('violationTicketCount' + countNo.toString()); - let parts = fullDescription.split(" "); // act/code fullsection description + let countForm = this.form + .get('violationTicket') + .get('violationTicketCount' + countNo.toString()); + let parts = fullDescription.split(' '); // act/code fullsection description // lookup legal statute from part[0] which should be in legal paragraph form if (parts && parts.length > 1) { - let foundStatute = this.lookupsService.statutes?.find(x => StringUtils.nullSafeCompare(x.actCode, parts[0]) && StringUtils.nullSafeCompare(x.code, parts[1])); + let foundStatute = this.lookupsService.statutes?.find( + (x) => + StringUtils.nullSafeCompare(x.actCode, parts[0]) && + StringUtils.nullSafeCompare(x.code, parts[1]) + ); if (foundStatute) { countForm.get('actOrRegulationNameCode').setValue(foundStatute.actCode); countForm.get('section').setValue(foundStatute.sectionText); countForm.get('subsection').setValue(foundStatute.subsectionText); countForm.get('paragraph').setValue(foundStatute.paragraphText); countForm.get('subparagraph').setValue(foundStatute.subparagraphText); - countForm.get('description').setValue(foundStatute.shortDescriptionText); - countForm.get('fullDescription').setValue(`${foundStatute.actCode} ${foundStatute.code} ${foundStatute.shortDescriptionText}`); + countForm + .get('description') + .setValue(foundStatute.shortDescriptionText); + countForm + .get('fullDescription') + .setValue( + `${foundStatute.actCode} ${foundStatute.code} ${foundStatute.shortDescriptionText}` + ); } else { countForm.get('actOrRegulationNameCode').setValue(undefined); countForm.get('section').setValue(undefined); @@ -768,13 +1041,10 @@ export class TicketInfoComponent implements OnInit { this.initialDisputeValues = null; this.lastUpdatedDispute = null; - this.disputeService.getDispute(this.disputeInfo.disputeId) - .subscribe((response: Dispute) => { + this.disputeService.getDispute(this.disputeInfo.disputeId).subscribe( + (response: Dispute) => { this.retrieving = false; - this.logger.info( - 'TicketInfoComponent::getDispute response', - response - ); + this.logger.info('TicketInfoComponent::getDispute response', response); // If disputant surname is filled in, then this is not the first time this ticket has been opened, only call setFieldsFromJSON the first time if (response.violationTicket.disputantSurname) { @@ -784,63 +1054,144 @@ export class TicketInfoComponent implements OnInit { } // set court agency id if possible - let courtFound = this.lookupsService.courthouseAgencies.filter(x => x.name === this.initialDisputeValues.violationTicket.courtLocation); - if (courtFound?.length > 0) this.initialDisputeValues.courtAgenId = courtFound[0].id; + let courtFound = this.lookupsService.courthouseAgencies.filter( + (x) => + x.name === this.initialDisputeValues.violationTicket.courtLocation + ); + if (courtFound?.length > 0) + this.initialDisputeValues.courtAgenId = courtFound[0].id; - this.lastUpdatedDispute = JSON.parse(JSON.stringify(this.initialDisputeValues)); + this.lastUpdatedDispute = JSON.parse( + JSON.stringify(this.initialDisputeValues) + ); this.form.patchValue(this.initialDisputeValues); - this.form.get('driversLicenceProvinceSeqNo').setValue(this.initialDisputeValues.driversLicenceIssuedProvinceSeqNo); - this.form.get('driversLicenceCountryId').setValue(this.initialDisputeValues.driversLicenceIssuedCountryId); + this.form + .get('driversLicenceProvinceSeqNo') + .setValue( + this.initialDisputeValues.driversLicenceIssuedProvinceSeqNo + ); + this.form + .get('driversLicenceCountryId') + .setValue(this.initialDisputeValues.driversLicenceIssuedCountryId); // set provId for drivers Licence and address this field is only good client side as angular dropdown needs a single value key to behave well, doesnt like two part key of ctryid & seqno - let provFound = this.config.provincesAndStates.filter(x => x.ctryId === this.initialDisputeValues.driversLicenceIssuedCountryId && x.provSeqNo === this.initialDisputeValues.driversLicenceIssuedProvinceSeqNo).shift(); - if (provFound) this.form.get('driversLicenceProvinceProvId').setValue(provFound.provId); + let provFound = this.config.provincesAndStates + .filter( + (x) => + x.ctryId === + this.initialDisputeValues.driversLicenceIssuedCountryId && + x.provSeqNo === + this.initialDisputeValues.driversLicenceIssuedProvinceSeqNo + ) + .shift(); + if (provFound) + this.form + .get('driversLicenceProvinceProvId') + .setValue(provFound.provId); // set violation date and time using violation ticket issuedTs as source of truth - if (!this.initialDisputeValues.violationTicket.issuedTs) this.initialDisputeValues.violationTicket.issuedTs = this.initialDisputeValues.issuedTs; - let violationDate = this.initialDisputeValues.violationTicket.issuedTs?.split("T"); + if (!this.initialDisputeValues.violationTicket.issuedTs) + this.initialDisputeValues.violationTicket.issuedTs = + this.initialDisputeValues.issuedTs; + let violationDate = + this.initialDisputeValues.violationTicket.issuedTs?.split('T'); if (violationDate && violationDate.length > 1) { - this.form.get('violationTicket').get('issuedTs').setValue(this.initialDisputeValues.violationTicket.issuedTs); - this.form.get('violationTicket').get('violationDate').setValue(violationDate[0]); - this.form.get('violationTicket').get('violationTime').setValue(violationDate[1].split(":")[0] + violationDate[1].split(":")[1]); - this.initialDisputeValues.issuedTs = this.initialDisputeValues.violationTicket.issuedTs; - this.lastUpdatedDispute.issuedTs = this.initialDisputeValues.violationTicket.issuedTs; + this.form + .get('violationTicket') + .get('issuedTs') + .setValue(this.initialDisputeValues.violationTicket.issuedTs); + this.form + .get('violationTicket') + .get('violationDate') + .setValue(violationDate[0]); + this.form + .get('violationTicket') + .get('violationTime') + .setValue( + violationDate[1].split(':')[0] + violationDate[1].split(':')[1] + ); + this.initialDisputeValues.issuedTs = + this.initialDisputeValues.violationTicket.issuedTs; + this.lastUpdatedDispute.issuedTs = + this.initialDisputeValues.violationTicket.issuedTs; } // ticket image - if (this.initialDisputeValues?.violationTicket?.violationTicketImage?.mimeType) { - this.imageToShow = "data:" + this.initialDisputeValues.violationTicket.violationTicketImage.mimeType + ";base64," + this.initialDisputeValues.violationTicket.violationTicketImage.image; - } else if (this.initialDisputeValues?.violationTicket?.violationTicketImage?.image) { - this.imageToShow = 'data:image/png;base64,' + this.initialDisputeValues?.violationTicket?.violationTicketImage?.image; + if ( + this.initialDisputeValues?.violationTicket?.violationTicketImage + ?.mimeType + ) { + this.imageToShow = + 'data:' + + this.initialDisputeValues.violationTicket.violationTicketImage + .mimeType + + ';base64,' + + this.initialDisputeValues.violationTicket.violationTicketImage + .image; + } else if ( + this.initialDisputeValues?.violationTicket?.violationTicketImage + ?.image + ) { + this.imageToShow = + 'data:image/png;base64,' + + this.initialDisputeValues?.violationTicket?.violationTicketImage + ?.image; } // set disputant detected ocr issues - this.flagsForm.get('disputantOcrIssues').setValue(response.disputantOcrIssues); + this.flagsForm + .get('disputantOcrIssues') + .setValue(response.disputantOcrIssues); // set counts 1,2,3 of violation ticket this.assignViolationTicketCountForm(); - this.violationTicketService.getAllOCRMessages(this.lastUpdatedDispute.violationTicket.ocrViolationTicket); + this.violationTicketService.getAllOCRMessages( + this.lastUpdatedDispute.violationTicket.ocrViolationTicket + ); // set system flags for provincial court hearing location this.courtLocationFlag = { - heading: "Court Location", - key: "court_location", - fieldConfidence: this.lastUpdatedDispute.violationTicket.ocrViolationTicket?.fields["court_location"]?.fieldConfidence + heading: 'Court Location', + key: 'court_location', + fieldConfidence: + this.lastUpdatedDispute.violationTicket.ocrViolationTicket?.fields[ + 'court_location' + ]?.fieldConfidence, }; // update address field validators - provFound = this.config.provincesAndStates.filter(x => x.ctryId === this.initialDisputeValues.addressProvinceCountryId && x.provSeqNo === this.initialDisputeValues.addressProvinceSeqNo).shift(); - if (provFound) this.form.get('addressProvinceProvId').setValue(provFound.provId); - this.form.get('addressProvince').setValidators([Validators.maxLength(30)]); - this.form.get('homePhoneNumber').setValidators([Validators.maxLength(20)]); - this.form.get('driversLicenceProvince').setValidators([Validators.maxLength(30)]); - this.form.get("driversLicenceProvinceSeqNo").setValidators(null); - - if (this.form.get('addressCountryId').value === this.canada.ctryId || this.form.get('addressCountryId').value === this.usa.ctryId) { - this.form.get('addressProvinceSeqNo').addValidators([Validators.required]); + provFound = this.config.provincesAndStates + .filter( + (x) => + x.ctryId === this.initialDisputeValues.addressProvinceCountryId && + x.provSeqNo === this.initialDisputeValues.addressProvinceSeqNo + ) + .shift(); + if (provFound) + this.form.get('addressProvinceProvId').setValue(provFound.provId); + this.form + .get('addressProvince') + .setValidators([Validators.maxLength(30)]); + this.form + .get('homePhoneNumber') + .setValidators([Validators.maxLength(20)]); + this.form + .get('driversLicenceProvince') + .setValidators([Validators.maxLength(30)]); + this.form.get('driversLicenceProvinceSeqNo').setValidators(null); + + if ( + this.form.get('addressCountryId').value === this.canada.ctryId || + this.form.get('addressCountryId').value === this.usa.ctryId + ) { + this.form + .get('addressProvinceSeqNo') + .addValidators([Validators.required]); this.form.get('postalCode').addValidators([Validators.required]); - this.form.get('homePhoneNumber').addValidators([FormControlValidators.phone]); + this.form + .get('homePhoneNumber') + .addValidators([FormControlValidators.phone]); } if (this.form.get('addressCountryId').value == this.canada.ctryId) { @@ -848,11 +1199,11 @@ export class TicketInfoComponent implements OnInit { } this.form.get('postalCode').updateValueAndValidity(); this.form.get('addressProvince').updateValueAndValidity(); - this.form.get("addressProvinceSeqNo").updateValueAndValidity(); - this.form.get("addressProvinceProvId").updateValueAndValidity(); + this.form.get('addressProvinceSeqNo').updateValueAndValidity(); + this.form.get('addressProvinceProvId').updateValueAndValidity(); this.form.get('homePhoneNumber').updateValueAndValidity(); this.form.get('driversLicenceProvince').updateValueAndValidity(); - this.form.get("driversLicenceProvinceSeqNo").updateValueAndValidity(); + this.form.get('driversLicenceProvinceSeqNo').updateValueAndValidity(); if (this.lastUpdatedDispute.status !== this.DispStatus.New) { this.form.controls.violationTicket.disable(); @@ -860,52 +1211,73 @@ export class TicketInfoComponent implements OnInit { this.form.get('violationTicket').updateValueAndValidity(); // TCVP-2554 make a static variable to indicate if the TicketInformation section is editable or not. - this.isTicketInformationReadOnly = this.lastUpdatedDispute.status === this.DispStatus.Validated; - }, (error: any) => { + this.isTicketInformationReadOnly = + this.lastUpdatedDispute.status === this.DispStatus.Validated; + }, + (error: any) => { this.retrieving = false; if (error.status == 409) this.conflict = true; - }); + } + ); } - assignViolationTicketCountForm(){ - this.initialDisputeValues.violationTicket.violationTicketCounts.forEach(violationTicketCount => { - let countForm = this.form.get('violationTicket').get('violationTicketCount' + violationTicketCount.countNo.toString()); - countForm.markAsUntouched(); - countForm.get('ticketedAmount').setValue(violationTicketCount.ticketedAmount); - let fullDesc = this.getCountLegalParagraphing(violationTicketCount.countNo, this.initialDisputeValues.violationTicket); - countForm - .get('fullDescription') - .setValue(fullDesc); - countForm.get('description').setValue(violationTicketCount.description); - - // lookup legal statute - let actCode = violationTicketCount.actOrRegulationNameCode; - if (!actCode) { - actCode = violationTicketCount.isAct === ViolationTicketCountIsAct.Y ? "MVA" : "MVR"; - } - const sectionCode = this.getSectionText(violationTicketCount); - let foundStatute = this.lookupsService.statutes?.find(x => StringUtils.nullSafeCompare(x.actCode, actCode) && StringUtils.nullSafeCompare(x.code, sectionCode)); - if (foundStatute) { - countForm.get('actOrRegulationNameCode').setValue(foundStatute.actCode); - countForm.get('section').setValue(foundStatute.sectionText); - countForm.get('subsection').setValue(foundStatute.subsectionText); - countForm.get('paragraph').setValue(foundStatute.paragraphText); - countForm.get('subparagraph').setValue(foundStatute.subparagraphText); + assignViolationTicketCountForm() { + this.initialDisputeValues.violationTicket.violationTicketCounts.forEach( + (violationTicketCount) => { + let countForm = this.form + .get('violationTicket') + .get( + 'violationTicketCount' + violationTicketCount.countNo.toString() + ); + countForm.markAsUntouched(); + countForm + .get('ticketedAmount') + .setValue(violationTicketCount.ticketedAmount); + let fullDesc = this.getCountLegalParagraphing( + violationTicketCount.countNo, + this.initialDisputeValues.violationTicket + ); + countForm.get('fullDescription').setValue(fullDesc); + countForm.get('description').setValue(violationTicketCount.description); + + // lookup legal statute + let actCode = violationTicketCount.actOrRegulationNameCode; + if (!actCode) { + actCode = + violationTicketCount.isAct === ViolationTicketCountIsAct.Y + ? 'MVA' + : 'MVR'; + } + const sectionCode = this.getSectionText(violationTicketCount); + let foundStatute = this.lookupsService.statutes?.find( + (x) => + StringUtils.nullSafeCompare(x.actCode, actCode) && + StringUtils.nullSafeCompare(x.code, sectionCode) + ); + if (foundStatute) { + countForm + .get('actOrRegulationNameCode') + .setValue(foundStatute.actCode); + countForm.get('section').setValue(foundStatute.sectionText); + countForm.get('subsection').setValue(foundStatute.subsectionText); + countForm.get('paragraph').setValue(foundStatute.paragraphText); + countForm.get('subparagraph').setValue(foundStatute.subparagraphText); + } + countForm.updateValueAndValidity(); } - countForm.updateValueAndValidity(); - }); + ); } /** * Returns the full section text from a ViolationTicketCount, ie 44(3)(a)(iii) - * @param vtc - * @returns + * @param vtc + * @returns */ private getSectionText(vtc: ViolationTicketCount): string { - let sectionText = vtc.section ?? ""; - sectionText += vtc.subsection ? '(' + vtc.subsection + ')' : ""; - sectionText += vtc.paragraph ? '(' + vtc.paragraph + ')' : ""; - sectionText += vtc.subparagraph ? '(' + vtc.subparagraph + ')' : ""; + let sectionText = vtc.section ?? ''; + sectionText += vtc.subsection ? '(' + vtc.subsection + ')' : ''; + sectionText += vtc.paragraph ? '(' + vtc.paragraph + ')' : ''; + sectionText += vtc.subparagraph ? '(' + vtc.subparagraph + ')' : ''; return sectionText; } @@ -915,32 +1287,40 @@ export class TicketInfoComponent implements OnInit { onPrint() { var type = DcfTemplateType.DcfTemplate; - - this.disputeService.apiTicketValidationPrintGet(this.lastUpdatedDispute.disputeId, type).subscribe(result => { - if (result) { - var url = URL.createObjectURL(result); - window.open(url); - } else { - alert("File contents not found"); - } - }); + + this.disputeService + .apiTicketValidationPrintGet(this.lastUpdatedDispute.disputeId, type) + .subscribe((result) => { + if (result) { + var url = URL.createObjectURL(result); + window.open(url); + } else { + alert('File contents not found'); + } + }); } onDeleteViolationTicketCount(countNumber: number) { - let violationTicketCounts = this.lastUpdatedDispute.violationTicket.violationTicketCounts; - let count = violationTicketCounts.find(x => x.countNo == countNumber); + let violationTicketCounts = + this.lastUpdatedDispute.violationTicket.violationTicketCounts; + let count = violationTicketCounts.find((x) => x.countNo == countNumber); const data: DialogOptions = { - titleKey: "Delete Violation Ticket Count?", - messageKey: "Are you sure you want to delete this violation ticket count?", - actionTextKey: "Delete", - actionType: "warn", - cancelTextKey: "Cancel", - icon: "delete" + titleKey: 'Delete Violation Ticket Count?', + messageKey: + 'Are you sure you want to delete this violation ticket count?', + actionTextKey: 'Delete', + actionType: 'warn', + cancelTextKey: 'Cancel', + icon: 'delete', }; - this.dialog.open(ConfirmDialogComponent, { data }).afterClosed() + this.dialog + .open(ConfirmDialogComponent, { data }) + .afterClosed() .subscribe((action: any) => { if (action) { - var countForm = this.form.get('violationTicket').get('violationTicketCount' + countNumber.toString()); + var countForm = this.form + .get('violationTicket') + .get('violationTicketCount' + countNumber.toString()); countForm.reset(); countForm.get('ticketedAmount').reset(); countForm.get('fullDescription').reset(); @@ -959,8 +1339,13 @@ export class TicketInfoComponent implements OnInit { count.subsection = null; count.paragraph = null; count.subparagraph = null; - this.lastUpdatedDispute.violationTicket.violationTicketCounts = violationTicketCounts.filter(x => x.countNo != countNumber); - this.lastUpdatedDispute.violationTicket.violationTicketCounts.splice(countNumber - 1, 0, count); + this.lastUpdatedDispute.violationTicket.violationTicketCounts = + violationTicketCounts.filter((x) => x.countNo != countNumber); + this.lastUpdatedDispute.violationTicket.violationTicketCounts.splice( + countNumber - 1, + 0, + count + ); this.isViolationTicketCountDeleted = true; this.lastUpdatedDispute = { ...this.lastUpdatedDispute }; } @@ -969,8 +1354,11 @@ export class TicketInfoComponent implements OnInit { onCancelChanges() { this.assignViolationTicketCountForm(); - this.lastUpdatedDispute.violationTicket.violationTicketCounts = - JSON.parse(JSON.stringify(this.initialDisputeValues.violationTicket.violationTicketCounts)); + this.lastUpdatedDispute.violationTicket.violationTicketCounts = JSON.parse( + JSON.stringify( + this.initialDisputeValues.violationTicket.violationTicketCounts + ) + ); this.lastUpdatedDispute = { ...this.lastUpdatedDispute }; this.validateClicked = false; this.isViolationTicketCountDeleted = false; From 28adfd9c942cd88d95a4d273f89ab737f88aed04 Mon Sep 17 00:00:00 2001 From: Emad Date: Thu, 6 Feb 2025 17:36:32 -0800 Subject: [PATCH 20/20] Update request set default status option 'new' --- .../update-request-inbox.component.html | 2 +- .../update-request-inbox.component.ts | 5 +++-- .../components/table-filters/table-filters.component.ts | 6 +++--- .../src/app/services/table-filter.service.ts | 9 +++++---- .../src/app/shared/models/table-filter-options.model.ts | 3 ++- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.html b/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.html index bb2ac2ecd..37453b0ea 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.html +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.html @@ -1,5 +1,5 @@ + [defaultStatusFilter]="defaultStatusFilter" (onFilterChanged)="onApplyFilter($event)">
    diff --git a/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts b/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts index 2d04fdc39..a3d51518d 100644 --- a/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts +++ b/src/frontend/staff-portal/src/app/components/staff-workbench/update-request-inbox/update-request-inbox.component.ts @@ -6,7 +6,7 @@ import { Dispute, DisputeStatus } from 'app/api'; import { LoggerService } from '@core/services/logger.service'; import { AuthService, KeycloakProfile } from 'app/services/auth.service'; import { DateUtil } from '@shared/utils/date-util'; -import { TableFilter, TableFilterKeys, TableFilterStatus, TableFilterStatusOptions } from '@shared/models/table-filter-options.model'; +import { TableFilter, TableFilterKeys, TableFilterStatus, TableFilterStatusOptions, UpdateRequestTableStatusDefault } from '@shared/models/table-filter-options.model'; import { TableFilterService } from 'app/services/table-filter.service'; @Component({ @@ -21,6 +21,7 @@ export class UpdateRequestInboxComponent implements OnInit, AfterViewInit { dataSource = new MatTableDataSource(); tableFilterKeys: TableFilterKeys[] = ["dateSubmittedFrom", "dateSubmittedTo", "disputantSurname", "status", "ticketNumber"]; statusFilterOptions = TableFilterStatusOptions; + defaultStatusFilter = UpdateRequestTableStatusDefault; displayedColumns: string[] = [ 'submittedTs', 'ticketNumber', @@ -52,7 +53,7 @@ export class UpdateRequestInboxComponent implements OnInit, AfterViewInit { this.userProfile = userProfile; } }) - + // when authentication token available, get data this.getAllDisputesWithPendingUpdates(); } diff --git a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts index ea25fa362..46a4b0718 100644 --- a/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts +++ b/src/frontend/staff-portal/src/app/components/table-filters/table-filters.component.ts @@ -14,7 +14,7 @@ export class TableFiltersComponent implements OnInit { @Input() tabIndex: number; @Input() tableFilterKeys: TableFilterKeys[] = []; @Input() statusFilterOptions: DisputeStatus[] = []; - @Input() statusFilterDefaultText: string = 'ALL'; + @Input() defaultStatusFilter: TableFilterStatus = TableFilterStatusDefault; @Input() courthouseTeamNames: string[] = []; @Output() onFilterChanged: EventEmitter = new EventEmitter(); @@ -42,17 +42,17 @@ export class TableFiltersComponent implements OnInit { this.tableFilterConfigs[key] = true; }) this.dataFilters = this.tableFilterService.tableFilters[this.tabIndex]; - this.dataFilters.status = this.dataFilters.status ?? TableFilterStatusDefault; + this.dataFilters.status = this.dataFilters.status ?? this.defaultStatusFilter; } resetSearchFilters() { // Will update search filters in UI this.dataFilters = new TableFilter(); + this.dataFilters.status = this.defaultStatusFilter; // Will re-execute the filter function, but will block UI rendering // Put this call in a Timeout to keep UI responsive. setTimeout(() => { this.tableFilterService.tableFilters[this.tabIndex] = this.dataFilters; - //this.dataFilters.status = this.dataFilters.status ?? []; this.onFilterChanged.emit(this.dataFilters); }, 100); } diff --git a/src/frontend/staff-portal/src/app/services/table-filter.service.ts b/src/frontend/staff-portal/src/app/services/table-filter.service.ts index 24e8db733..f950785f2 100644 --- a/src/frontend/staff-portal/src/app/services/table-filter.service.ts +++ b/src/frontend/staff-portal/src/app/services/table-filter.service.ts @@ -1,13 +1,14 @@ import { Injectable } from '@angular/core'; -import { TableFilter } from '@shared/models/table-filter-options.model'; +import { TableFilter, UpdateRequestTableStatusDefault} from '@shared/models/table-filter-options.model'; @Injectable({ providedIn: 'root', }) export class TableFilterService { // Temp - tableFilters: TableFilter[] = new Array(4).fill(new TableFilter()); + tableFilters: TableFilter[] = Array.from({ length: 4 }, () => new TableFilter()); currentPage: number[] = new Array(4).fill(1); - constructor( - ) { + constructor() { + //default status for Update Request inbox set to 'New' + this.tableFilters[2].status = UpdateRequestTableStatusDefault; } } \ No newline at end of file diff --git a/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts b/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts index e7049c2ec..6fb143bdf 100644 --- a/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts +++ b/src/frontend/staff-portal/src/app/shared/models/table-filter-options.model.ts @@ -36,7 +36,8 @@ export const TableFilterStatusOptions = [{ }, ]; -export const TableFilterStatusDefault = TableFilterStatusOptions[0]; +export const TableFilterStatusDefault: TableFilterStatus = TableFilterStatusOptions[0]; +export const UpdateRequestTableStatusDefault: TableFilterStatus = TableFilterStatusOptions[1]; export class TableFilter { dateSubmittedFrom?: string;