Skip to content

Commit 7dfa7c3

Browse files
authored
Merge pull request #2533 from bcgov/2417-add-many-submitters-edit-submitter-section
2417 add many submitters edit submitter section
2 parents 73e4a30 + 7a76c7d commit 7dfa7c3

23 files changed

+424
-114
lines changed

alcs-frontend/src/app/features/compliance-and-enforcement/compliance-and-enforcement.module.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { DetailsHeaderComponent } from './details/header/details-header.componen
1515
import { ComplaintReferralComponent } from './details/complaint-referral/complaint-referral.component';
1616
import { ComplaintReferralOverviewComponent } from './details/complaint-referral/overview/overview.component';
1717
import { ComplaintReferralSubmittersComponent } from './details/complaint-referral/submitters/submitters.component';
18+
import { AddSubmitterDialogComponent } from './details/complaint-referral/submitters/add-submitter-dialog/add-submitter-dialog.component';
1819

1920
export const detailsRoutes: (Route & { icon?: string; menuTitle?: string })[] = [
2021
{
@@ -38,6 +39,11 @@ export const detailsRoutes: (Route & { icon?: string; menuTitle?: string })[] =
3839
component: ComplaintReferralComponent,
3940
data: { editing: 'overview' },
4041
},
42+
{
43+
path: 'submitters/edit',
44+
component: ComplaintReferralComponent,
45+
data: { editing: 'submitters' },
46+
},
4147
],
4248
},
4349
];
@@ -68,6 +74,7 @@ const routes: Routes = [
6874
ComplaintReferralComponent,
6975
ComplaintReferralOverviewComponent,
7076
ComplaintReferralSubmittersComponent,
77+
AddSubmitterDialogComponent,
7178
],
7279
imports: [SharedModule.forRoot(), RouterModule.forChild(routes), MatMomentDateModule, CommonModule, SharedModule],
7380
})

alcs-frontend/src/app/features/compliance-and-enforcement/details/complaint-referral/complaint-referral.component.html

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<ng-container *ngIf="editing === null">
22
<section class="file-section">
3+
<h3>Complaint / Referral Overview</h3>
4+
35
<app-compliance-and-enforcement-complaint-referral-overview [file]="file" />
46

57
<div class="edit-section-button-container">
@@ -8,7 +10,16 @@
810
</section>
911

1012
<section class="file-section">
13+
<div class="submitters-header">
14+
<h3>Submitters</h3>
15+
<button mat-flat-button color="primary" type="button" (click)="openNewSubmitterDialog()">+ Submitter</button>
16+
</div>
17+
1118
<app-compliance-and-enforcement-complaint-referral-submitters [file]="file" />
19+
20+
<div class="edit-section-button-container">
21+
<a mat-flat-button color="accent" [routerLink]="'submitters/edit'" class="edit-section-button">Edit Section</a>
22+
</div>
1223
</section>
1324

1425
<section class="file-section">
@@ -32,7 +43,36 @@ <h3>Complaint / Referral > Edit Overview</h3>
3243

3344
<div class="button-container">
3445
<a mat-stroked-button color="warn" [routerLink]="'../..'">Cancel</a>
35-
<button mat-flat-button color="primary" (click)="save()">Save</button>
46+
<button mat-flat-button color="primary" (click)="saveOverview()">Save</button>
47+
</div>
48+
</form>
49+
</ng-container>
50+
51+
<ng-container *ngIf="editing === 'submitters'">
52+
<form [formGroup]="form">
53+
<section class="form-section">
54+
<h3>Complaint / Referral > Edit Submitters</h3>
55+
56+
<div class="submitter-container" *ngFor="let submitter of file?.submitters; let i = index">
57+
<app-compliance-and-enforcement-submitter
58+
#submitterComponents
59+
[title]="'#' + (i + 1)"
60+
[showDeleteButton]="true"
61+
[submitter]="submitter"
62+
[initialSubmissionType]="file?.initialSubmissionType ?? undefined"
63+
(deleteButtonClicked)="deleteSubmitter(submitter.uuid)"
64+
(formReady)="registerFormGroup('submitter-' + i, $event.formGroup)"
65+
/>
66+
</div>
67+
</section>
68+
69+
<button mat-flat-button color="accent" type="button" (click)="openNewSubmitterDialog()">
70+
+ Add another submitter
71+
</button>
72+
73+
<div class="button-container">
74+
<a mat-stroked-button color="warn" [routerLink]="'../..'">Cancel</a>
75+
<button mat-flat-button color="primary" [disabled]="form.invalid" (click)="saveSubmitters()">Save</button>
3676
</div>
3777
</form>
3878
</ng-container>

alcs-frontend/src/app/features/compliance-and-enforcement/details/complaint-referral/complaint-referral.component.scss

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ section {
88
margin: 32px 0;
99
}
1010

11+
.submitter-container {
12+
padding: 24px;
13+
border: 1px solid colors.$grey;
14+
border-radius: 5px;
15+
}
16+
1117
section.file-section {
1218
display: flex;
1319
flex-direction: column;
@@ -18,6 +24,12 @@ section.file-section {
1824
margin: 32px 0;
1925
}
2026

27+
.form-section {
28+
display: flex;
29+
flex-direction: column;
30+
gap: 24px;
31+
}
32+
2133
.button-container {
2234
display: flex;
2335
justify-content: space-between;
@@ -40,3 +52,9 @@ a[mat-stroked-button] {
4052
font-weight: 700 !important;
4153
text-transform: uppercase;
4254
}
55+
56+
.submitters-header {
57+
display: flex;
58+
justify-content: space-between;
59+
align-items: center;
60+
}

alcs-frontend/src/app/features/compliance-and-enforcement/details/complaint-referral/complaint-referral.component.spec.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ActivatedRoute, Router } from '@angular/router';
66
import { ToastService } from '../../../../services/toast/toast.service';
77
import { firstValueFrom, of, Subject } from 'rxjs';
88
import { ComplianceAndEnforcementDto } from '../../../../services/compliance-and-enforcement/compliance-and-enforcement.dto';
9+
import { HttpClient } from '@angular/common/http';
910

1011
describe('ComplaintReferralComponent', () => {
1112
let component: ComplaintReferralComponent;
@@ -14,12 +15,14 @@ describe('ComplaintReferralComponent', () => {
1415
let mockRouter: DeepMocked<Router>;
1516
let mockService: DeepMocked<ComplianceAndEnforcementService>;
1617
let mockToastService: DeepMocked<ToastService>;
18+
let mockHttpClient: DeepMocked<HttpClient>;
1719

1820
beforeEach(async () => {
1921
mockActivatedRoute = createMock<ActivatedRoute>();
2022
mockRouter = createMock<Router>();
2123
mockService = createMock<ComplianceAndEnforcementService>();
2224
mockToastService = createMock<ToastService>();
25+
mockHttpClient = createMock<HttpClient>();
2326

2427
TestBed.configureTestingModule({
2528
imports: [],
@@ -41,6 +44,10 @@ describe('ComplaintReferralComponent', () => {
4144
provide: ToastService,
4245
useValue: mockToastService,
4346
},
47+
{
48+
provide: HttpClient,
49+
useValue: mockHttpClient,
50+
},
4451
],
4552
});
4653

@@ -77,7 +84,7 @@ describe('ComplaintReferralComponent', () => {
7784
component.fileNumber = undefined;
7885
const toastSpy = jest.spyOn(mockToastService, 'showErrorToast');
7986

80-
await component.save();
87+
await component.saveOverview();
8188

8289
expect(toastSpy).toHaveBeenCalledWith('Error loading file');
8390
expect(mockService.update).not.toHaveBeenCalled();
@@ -92,10 +99,10 @@ describe('ComplaintReferralComponent', () => {
9299
const toastSpy = jest.spyOn(mockToastService, 'showSuccessToast');
93100
const navSpy = jest.spyOn(mockRouter, 'navigate');
94101

95-
await component.save();
102+
await component.saveOverview();
96103

97104
expect(mockService.update).toHaveBeenCalledWith('456', { foo: 'bar' }, { idType: 'fileNumber' });
98-
expect(toastSpy).toHaveBeenCalledWith('File updated successfully');
105+
expect(toastSpy).toHaveBeenCalledWith('Overview updated successfully');
99106
expect(navSpy).toHaveBeenCalled();
100107
});
101108

@@ -110,7 +117,7 @@ describe('ComplaintReferralComponent', () => {
110117
} as any);
111118
jest.spyOn({ firstValueFrom }, 'firstValueFrom').mockImplementation(() => Promise.reject(new Error('fail')));
112119

113-
await expect(component.save()).resolves.not.toThrow();
120+
await expect(component.saveOverview()).resolves.not.toThrow();
114121
});
115122

116123
it('should complete $destroy on ngOnDestroy', () => {

alcs-frontend/src/app/features/compliance-and-enforcement/details/complaint-referral/complaint-referral.component.ts

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
1+
import { Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
22
import { FormGroup } from '@angular/forms';
33
import { firstValueFrom, Subject, takeUntil } from 'rxjs';
44
import { ComplianceAndEnforcementService } from '../../../../services/compliance-and-enforcement/compliance-and-enforcement.service';
@@ -11,6 +11,12 @@ import { ActivatedRoute, Router } from '@angular/router';
1111
import { submissionDocumentOptions } from '../../draft/draft.component';
1212
import { OverviewComponent } from '../../overview/overview.component';
1313
import { ToastService } from '../../../../services/toast/toast.service';
14+
import { SubmitterComponent } from '../../submitter/submitter.component';
15+
import { UpdateComplianceAndEnforcementSubmitterDto } from '../../../../services/compliance-and-enforcement/submitter/submitter.dto';
16+
import { ComplianceAndEnforcementSubmitterService } from '../../../../services/compliance-and-enforcement/submitter/submitter.service';
17+
import { AddSubmitterDialogComponent } from './submitters/add-submitter-dialog/add-submitter-dialog.component';
18+
import { MatDialog } from '@angular/material/dialog';
19+
import { ConfirmationDialogService } from '../../../../shared/confirmation-dialog/confirmation-dialog.service';
1420

1521
@Component({
1622
selector: 'app-complaint-referral',
@@ -23,11 +29,12 @@ export class ComplaintReferralComponent implements OnInit, OnDestroy {
2329
Section = Section;
2430

2531
@ViewChild(OverviewComponent) overviewComponent?: OverviewComponent;
32+
@ViewChildren(SubmitterComponent) submitterComponents?: QueryList<SubmitterComponent>;
2633

2734
fileNumber?: string;
2835
file?: ComplianceAndEnforcementDto;
2936

30-
form = new FormGroup({ overview: new FormGroup({}), submitter: new FormGroup({}), property: new FormGroup({}) });
37+
form = new FormGroup({});
3138

3239
editing: string | null = null;
3340

@@ -37,7 +44,10 @@ export class ComplaintReferralComponent implements OnInit, OnDestroy {
3744
private readonly route: ActivatedRoute,
3845
private readonly router: Router,
3946
private readonly service: ComplianceAndEnforcementService,
47+
private readonly submitterService: ComplianceAndEnforcementSubmitterService,
4048
private readonly toastService: ToastService,
49+
private readonly confirmationService: ConfirmationDialogService,
50+
public dialog: MatDialog,
4151
) {}
4252

4353
ngOnInit(): void {
@@ -54,7 +64,7 @@ export class ComplaintReferralComponent implements OnInit, OnDestroy {
5464
});
5565
}
5666

57-
async save() {
67+
async saveOverview() {
5868
const updateDto: UpdateComplianceAndEnforcementDto = this.overviewComponent?.$changes.getValue() ?? {};
5969

6070
if (!this.fileNumber) {
@@ -65,15 +75,88 @@ export class ComplaintReferralComponent implements OnInit, OnDestroy {
6575

6676
try {
6777
await firstValueFrom(this.service.update(this.fileNumber, updateDto, { idType: 'fileNumber' }));
68-
this.toastService.showSuccessToast('File updated successfully');
78+
this.toastService.showSuccessToast('Overview updated successfully');
6979
this.router.navigate(['../..'], { relativeTo: this.route });
7080
} catch (error) {
71-
console.error('Error updating file:', error);
72-
this.toastService.showErrorToast('Error loading file');
81+
console.error('Error updating overview:', error);
82+
this.toastService.showErrorToast('Error updating overview');
83+
}
84+
}
85+
86+
async saveSubmitters() {
87+
if (!this.submitterComponents) {
88+
return;
89+
}
90+
91+
const submitters: { uuid: string; dto: UpdateComplianceAndEnforcementSubmitterDto }[] = this.submitterComponents
92+
.toArray()
93+
.flatMap((submitterComponent) => {
94+
const [uuid, dto] = submitterComponent.$changes.getValue();
95+
96+
return uuid ? [{ uuid, dto }] : [];
97+
});
98+
99+
try {
100+
await firstValueFrom(this.submitterService.bulkUpdate(submitters));
101+
this.toastService.showSuccessToast('Submitters updated successfully');
102+
this.router.navigate(['../..'], { relativeTo: this.route });
103+
} catch (error) {
104+
console.error('Error updating submitters:', error);
105+
this.toastService.showErrorToast('Error updating submitters');
73106
}
74107
}
75108

76-
async ngOnDestroy() {
109+
async openNewSubmitterDialog() {
110+
this.dialog
111+
.open(AddSubmitterDialogComponent, {
112+
minWidth: '600px',
113+
maxWidth: '800px',
114+
width: '70%',
115+
data: {
116+
fileUuid: this.file?.uuid,
117+
initialSubmissionType: this.file?.initialSubmissionType,
118+
service: this.submitterService,
119+
},
120+
})
121+
.afterClosed()
122+
.subscribe(async (saveSuccessful) => {
123+
if (saveSuccessful) {
124+
if (this.fileNumber) {
125+
await this.service.loadFile(this.fileNumber, { withSubmitters: true });
126+
}
127+
}
128+
});
129+
}
130+
131+
async deleteSubmitter(uuid: string) {
132+
this.confirmationService
133+
.openDialog({
134+
body: 'Are you sure you want to delete this submitter?',
135+
})
136+
.subscribe(async (isConfirmed) => {
137+
if (isConfirmed) {
138+
try {
139+
await this.submitterService.delete(uuid);
140+
this.toastService.showSuccessToast('Submitter deleted');
141+
142+
if (this.fileNumber) {
143+
this.service.loadFile(this.fileNumber, { withSubmitters: true });
144+
}
145+
} catch (error) {
146+
console.error(error);
147+
this.toastService.showErrorToast('Failed to delete submitter');
148+
}
149+
}
150+
});
151+
}
152+
153+
registerFormGroup(name: string, formGroup: FormGroup) {
154+
setTimeout(() => {
155+
this.form.addControl(name, formGroup);
156+
});
157+
}
158+
159+
ngOnDestroy() {
77160
this.$destroy.next();
78161
this.$destroy.complete();
79162
}

alcs-frontend/src/app/features/compliance-and-enforcement/details/complaint-referral/overview/overview.component.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
<h3>Complaint / Referral Overview</h3>
2-
31
<ng-template #noData>
42
<div class="no-data">No Data</div>
53
</ng-template>

alcs-frontend/src/app/features/compliance-and-enforcement/details/complaint-referral/overview/overview.component.scss

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
background-color: colors.$grey-light;
1313
padding: 24px;
14-
margin-top: 24px;
1514
}
1615

1716
.field {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<form [formGroup]="form">
2+
<app-compliance-and-enforcement-submitter
3+
#submitterComponent
4+
[title]="'Add Submitter'"
5+
[submitter]="undefined"
6+
[initialSubmissionType]="data?.initialSubmissionType"
7+
(formReady)="registerFormGroup($event)"
8+
/>
9+
10+
<div class="button-container">
11+
<button type="button" mat-stroked-button color="warn" (click)="close()">Cancel</button>
12+
<button type="button" mat-flat-button color="primary" (click)="addSubmitter()" [disabled]="form.invalid">
13+
Save
14+
</button>
15+
</div>
16+
</form>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
form {
2+
display: flex;
3+
flex-direction: column;
4+
gap: 24px;
5+
padding: 24px;
6+
}
7+
8+
.button-container {
9+
display: flex;
10+
}

0 commit comments

Comments
 (0)