Skip to content

Commit ffac6e4

Browse files
authored
2466 feat: discard and save and exit c & e draft functionality (#2485)
* feat: added cancel and discard functionality as well as save and exit * chore: updated test
1 parent 7b9f38f commit ffac6e4

File tree

6 files changed

+105
-18
lines changed

6 files changed

+105
-18
lines changed

alcs-frontend/src/app/features/compliance-and-enforcement/draft/draft.component.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,14 @@ <h2>C&E File ID: {{ file?.fileNumber }}</h2>
3939
/>
4040
</section>
4141

42-
<div class="button-container">
43-
<button type="button" mat-stroked-button color="primary" (click)="onSaveDraftClicked()">Save Draft</button>
42+
<div class="button-row">
43+
<div class="left-actions">
44+
<button type="button" mat-stroked-button color="warn" (click)="onCancelDiscardClicked()">Cancel & Discard</button>
45+
</div>
46+
<div class="right-actions">
47+
<button type="button" mat-stroked-button color="primary" (click)="onSaveDraftClicked()">Save Draft & Exit</button>
48+
<button type="button" mat-flat-button color="primary">Finish & Create File</button>
49+
</div>
4450
</div>
4551
</form>
4652
</div>

alcs-frontend/src/app/features/compliance-and-enforcement/draft/draft.component.scss

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ section.form-section {
1414
margin: 32px 0;
1515
}
1616

17-
.button-container {
17+
.button-row {
1818
display: flex;
19-
justify-content: flex-end;
19+
justify-content: space-between;
20+
align-items: center;
2021
}
22+
.left-actions { display: flex; }
23+
.right-actions { display: flex; gap: 12px; }

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
2-
import { ActivatedRoute } from '@angular/router';
2+
import { ActivatedRoute, Router } from '@angular/router';
33
import {
44
catchError,
55
debounceTime,
@@ -103,6 +103,7 @@ export class DraftComponent implements OnInit, AfterViewInit, OnDestroy {
103103
private readonly toastService: ToastService,
104104
private readonly propertyService: ComplianceAndEnforcementPropertyService,
105105
private readonly responsiblePartyService: ResponsiblePartiesService,
106+
private readonly router: Router,
106107
) {}
107108

108109
ngOnInit(): void {
@@ -329,12 +330,30 @@ export class DraftComponent implements OnInit, AfterViewInit, OnDestroy {
329330
}
330331

331332
this.toastService.showSuccessToast('C&E file draft saved');
333+
await this.router.navigate(['/home']);
332334
} catch (error) {
333335
console.error('Error saving C&E file draft', error);
334336
this.toastService.showErrorToast('Failed to save C&E file draft');
335337
}
336338
}
337339

340+
async onCancelDiscardClicked() {
341+
if (!this.file?.uuid) {
342+
await this.router.navigate(['/home']);
343+
return;
344+
}
345+
346+
try {
347+
await this.complianceAndEnforcementService.delete(this.file.uuid);
348+
this.toastService.showSuccessToast('Draft discarded');
349+
} catch (error) {
350+
console.error('Error discarding C&E draft', error);
351+
this.toastService.showErrorToast('Failed to discard draft');
352+
} finally {
353+
await this.router.navigate(['/home']);
354+
}
355+
}
356+
338357
ngOnDestroy(): void {
339358
this.$destroy.next();
340359
this.$destroy.complete();

services/apps/alcs/src/alcs/compliance-and-enforcement/compliance-and-enforcement.service.ts

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Injectable } from '@nestjs/common';
2-
import { DeleteResult, Repository } from 'typeorm';
2+
import { DeleteResult, In, Repository } from 'typeorm';
33
import { InjectRepository } from '@nestjs/typeorm';
44
import { AllegedActivity, ComplianceAndEnforcement, InitialSubmissionType } from './compliance-and-enforcement.entity';
55
import { ComplianceAndEnforcementDto, UpdateComplianceAndEnforcementDto } from './compliance-and-enforcement.dto';
@@ -11,6 +11,7 @@ import {
1111
} from '../../../../../libs/common/src/exceptions/base.exception';
1212
import { ComplianceAndEnforcementSubmitterService } from './submitter/submitter.service';
1313
import { ComplianceAndEnforcementPropertyService } from './property/property.service';
14+
import { ComplianceAndEnforcementDocument } from './document/document.entity';
1415

1516
@Injectable()
1617
export class ComplianceAndEnforcementService {
@@ -117,11 +118,63 @@ export class ComplianceAndEnforcementService {
117118
}
118119

119120
async delete(uuid: string): Promise<DeleteResult> {
120-
const entity = await this.repository.findOneBy({ uuid });
121-
if (entity === null) {
122-
throw new ServiceNotFoundException('A C&E file with this UUID does not exist. Unable to delete.');
121+
const manager: any = this.repository.manager as any;
122+
123+
if (!manager || typeof manager.transaction !== 'function') {
124+
const entity = await this.repository.findOneBy({ uuid });
125+
if (!entity) {
126+
throw new ServiceNotFoundException('A C&E file with this UUID does not exist. Unable to delete.');
127+
}
128+
return await this.repository.delete(uuid);
123129
}
124130

125-
return await this.repository.delete(uuid);
131+
return await this.repository.manager.transaction(async (manager) => {
132+
const file = await manager.findOne(ComplianceAndEnforcement, {
133+
where: { uuid },
134+
});
135+
136+
if (!file) {
137+
throw new ServiceNotFoundException('A C&E file with this UUID does not exist. Unable to delete.');
138+
}
139+
140+
// Delete C&E document link records for this file
141+
const ceDocuments = await manager.find(ComplianceAndEnforcementDocument, {
142+
where: { file: { uuid: file.uuid } },
143+
relations: ['document', 'type'],
144+
});
145+
if (ceDocuments.length > 0) {
146+
await manager.delete(ComplianceAndEnforcementDocument, { uuid: In(ceDocuments.map((d) => d.uuid)) });
147+
}
148+
149+
// Delete Responsible Party Directors, then Parties
150+
const parties = await manager.find(
151+
(await import('./responsible-parties/responsible-party.entity')).ComplianceAndEnforcementResponsibleParty,
152+
{ where: { fileUuid: file.uuid }, relations: ['directors'] },
153+
);
154+
const directorUuids = parties.flatMap((p: any) => (p.directors ? p.directors.map((d: any) => d.uuid) : []));
155+
if (directorUuids.length > 0) {
156+
const Director = (await import('./responsible-parties/responsible-party-director.entity'))
157+
.ComplianceAndEnforcementResponsiblePartyDirector;
158+
await manager.delete(Director, { uuid: In(directorUuids) });
159+
}
160+
if (parties.length > 0) {
161+
const Party = (await import('./responsible-parties/responsible-party.entity')).ComplianceAndEnforcementResponsibleParty;
162+
await manager.delete(Party, { fileUuid: file.uuid });
163+
}
164+
165+
// Delete Properties
166+
const Property = (await import('./property/property.entity')).ComplianceAndEnforcementProperty;
167+
await manager.delete(Property, { fileUuid: file.uuid });
168+
169+
// Delete Submitters (filter by file relation)
170+
const Submitter = (await import('./submitter/submitter.entity')).ComplianceAndEnforcementSubmitter;
171+
const submitters = await manager.find(Submitter, { where: { file: { uuid: file.uuid } } });
172+
if (submitters.length > 0) {
173+
await manager.delete(Submitter, { uuid: In(submitters.map((s: any) => s.uuid)) });
174+
}
175+
176+
// Finally delete the C&E File at the end of all the other deletions
177+
return await manager.delete(ComplianceAndEnforcement, { uuid: file.uuid });
178+
});
126179
}
127180
}

services/apps/alcs/src/alcs/compliance-and-enforcement/document/document.service.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Injectable } from '@nestjs/common';
2-
import { DeleteResult, In, Repository } from 'typeorm';
2+
import { DeleteResult, In, Repository, FindOptionsWhere } from 'typeorm';
33
import { InjectRepository } from '@nestjs/typeorm';
44
import { ComplianceAndEnforcementDocument, Section } from './document.entity';
55
import { ComplianceAndEnforcementDocumentDto, UpdateComplianceAndEnforcementDocumentDto } from './document.dto';
@@ -34,13 +34,18 @@ export class ComplianceAndEnforcementDocumentService {
3434
) {}
3535

3636
async list(fileNumber?: string, section?: Section): Promise<ComplianceAndEnforcementDocumentDto[]> {
37+
const criteria: FindOptionsWhere<ComplianceAndEnforcementDocument> = {};
38+
39+
if (fileNumber !== undefined) {
40+
criteria.file = { fileNumber } as any;
41+
}
42+
43+
if (section !== undefined) {
44+
criteria.section = section;
45+
}
46+
3747
const entities = await this.repository.find({
38-
where: {
39-
file: {
40-
fileNumber: fileNumber,
41-
},
42-
section,
43-
},
48+
where: criteria,
4449
relations: ['type', 'document'],
4550
order: {
4651
document: {

services/apps/alcs/src/alcs/compliance-and-enforcement/responsible-parties/responsible-parties.dto.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,9 @@ export class CreateComplianceAndEnforcementResponsiblePartyDto {
173173
@IsNumber()
174174
ownerSince?: number | null;
175175

176+
@IsOptional()
176177
@IsString()
177-
corporateSummaryUuid: string | null;
178+
corporateSummaryUuid?: string | null;
178179
}
179180

180181
export class UpdateComplianceAndEnforcementResponsiblePartyDto {

0 commit comments

Comments
 (0)