diff --git a/front-end/src/app/layout/sidebar/menus/f3x/f3x-menu.component.html b/front-end/src/app/layout/sidebar/menus/f3x/f3x-menu.component.html index fd0988017a..7cf94e7a3d 100644 --- a/front-end/src/app/layout/sidebar/menus/f3x/f3x-menu.component.html +++ b/front-end/src/app/layout/sidebar/menus/f3x/f3x-menu.component.html @@ -3,7 +3,7 @@
REPORT PROGRESS
{{ formLabel }}
-
{{ report_code | reportCodeLabel }}
+
{{ subLabel }}
{{ coverage_from_date | fecDate }} — {{ coverage_through_date | fecDate }} diff --git a/front-end/src/app/layout/sidebar/menus/f3x/f3x-menu.component.ts b/front-end/src/app/layout/sidebar/menus/f3x/f3x-menu.component.ts index 5ed553ada9..ee234680e2 100644 --- a/front-end/src/app/layout/sidebar/menus/f3x/f3x-menu.component.ts +++ b/front-end/src/app/layout/sidebar/menus/f3x/f3x-menu.component.ts @@ -4,7 +4,6 @@ import { MenuItem } from 'primeng/api'; import { Report } from '../../../../shared/models/report.model'; import { ReportService } from '../../../../shared/services/report.service'; import { ReportSidebarSection, SidebarState } from '../../sidebar.component'; -import { F3xReportCodes } from 'app/shared/utils/report-code.utils'; import { AbstractMenuComponent } from '../abstract-menu.component'; import { takeUntil } from 'rxjs'; import { Form3X } from '../../../../shared/models/form-3x.model'; @@ -17,7 +16,7 @@ import { Router } from '@angular/router'; }) export class F3XMenuComponent extends AbstractMenuComponent implements OnInit { formLabel?: string; - report_code?: F3xReportCodes; + subLabel?: string; coverage_from_date?: Date; coverage_through_date?: Date; @@ -31,7 +30,7 @@ export class F3XMenuComponent extends AbstractMenuComponent implements OnInit { if (!this.activeReport$) return; this.activeReport$.pipe(takeUntil(this.destroy$)).subscribe((report) => { this.formLabel = report?.formLabel; - this.report_code = (report as Form3X).report_code; + this.subLabel = report?.formSubLabel; this.coverage_from_date = (report as Form3X).coverage_from_date; this.coverage_through_date = (report as Form3X).coverage_through_date; }); diff --git a/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.html b/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.html index 90183f34e7..f3349d2395 100644 --- a/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.html +++ b/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.html @@ -74,7 +74,7 @@

Report type

[inputId]="reportCode" name="report_code" [value]="reportCode" - label="{{ reportCode | reportCodeLabel }}" + label="{{ reportCodeLabelMap ? reportCodeLabelMap[reportCode] : '' }}" [class]=" usedReportCodes?.includes(reportCode) ? 'p-disabled border-none bg-transparent aria-disabled="true"' diff --git a/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.spec.ts b/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.spec.ts index 7373e13f5a..53c76ed185 100644 --- a/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.spec.ts +++ b/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.spec.ts @@ -18,9 +18,9 @@ import { FecDatePipe } from 'app/shared/pipes/fec-date.pipe'; import { F3xCoverageDates } from '../../../shared/models/form-3x.model'; import { ReportService } from '../../../shared/services/report.service'; import { ListRestResponse } from '../../../shared/models/rest-api.model'; -import { F3xReportCodes } from 'app/shared/utils/report-code.utils'; -import { of } from 'rxjs'; +import { firstValueFrom, of } from 'rxjs'; import { buildNonOverlappingCoverageValidator } from 'app/shared/utils/validators.utils'; +import { F3xReportCodes } from 'app/shared/utils/report-code.utils'; describe('CreateF3XStep1Component', () => { let component: CreateF3XStep1Component; @@ -47,16 +47,22 @@ describe('CreateF3XStep1Component', () => { const ninth = new Date('01/09/2024'); const eighth = new Date('01/08/2024'); const tenth = new Date('01/10/2024'); - const thirdThroughFifth = F3xCoverageDates.fromJSON({ - report_code: 'Q1', - coverage_from_date: third, - coverage_through_date: fifth, - }); - const seventhThroughNinth = F3xCoverageDates.fromJSON({ - report_code: 'Q2', - coverage_from_date: seventh, - coverage_through_date: ninth, - }); + const thirdThroughFifth = F3xCoverageDates.fromJSON( + { + report_code: 'Q1', + coverage_from_date: third, + coverage_through_date: fifth, + }, + 'APRIL 15 QUARTERLY REPORT (Q1)', + ); + const seventhThroughNinth = F3xCoverageDates.fromJSON( + { + report_code: 'Q2', + coverage_from_date: seventh, + coverage_through_date: ninth, + }, + 'JULY 15 QUARTERLY REPORT (Q2)', + ); beforeEach(async () => { await TestBed.configureTestingModule({ @@ -75,7 +81,7 @@ describe('CreateF3XStep1Component', () => { router = TestBed.inject(Router); form3XService = TestBed.inject(Form3XService); - form3XService.getF3xCoverageDates = () => of([]); + form3XService.getF3xCoverageDates = () => firstValueFrom(of([])); reportService = TestBed.inject(ReportService); fixture = TestBed.createComponent(CreateF3XStep1Component); component = fixture.componentInstance; @@ -104,7 +110,7 @@ describe('CreateF3XStep1Component', () => { beforeEach(async () => { router = TestBed.inject(Router); form3XService = TestBed.inject(Form3XService); - form3XService.getF3xCoverageDates = () => of([thirdThroughFifth]); + form3XService.getF3xCoverageDates = () => firstValueFrom(of([thirdThroughFifth])); reportService = TestBed.inject(ReportService); fixture = TestBed.createComponent(CreateF3XStep1Component); component = fixture.componentInstance; @@ -169,6 +175,7 @@ describe('CreateF3XStep1Component', () => { coverage_through_date: new FormControl(controlThroughDate), }); validator(group); + console.log(group.get('coverage_from_date')?.errors); expect(group.get('coverage_from_date')?.errors).toEqual( expectedFromMessage ? { invaliddate: { msg: expectedFromMessage } } : null, ); diff --git a/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.ts b/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.ts index 7bf115b889..db70ec9517 100644 --- a/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.ts +++ b/front-end/src/app/reports/f3x/create-workflow/create-f3x-step1.component.ts @@ -7,12 +7,12 @@ import { Form3XService } from 'app/shared/services/form-3x.service'; import { LabelUtils, PrimeOptions, StatesCodeLabels } from 'app/shared/utils/label.utils'; import { electionReportCodes, - F3X_REPORT_CODE_MAP, F3xReportCodes, monthlyElectionYearReportCodes, monthlyNonElectionYearReportCodes, quarterlyElectionYearReportCodes, quarterlyNonElectionYearReportCodes, + getCoverageDatesFunction, } from 'app/shared/utils/report-code.utils'; import { SchemaUtils } from 'app/shared/utils/schema.utils'; import { selectActiveReport } from 'app/store/active-report.selectors'; @@ -51,6 +51,7 @@ export class CreateF3XStep1Component extends DestroyerComponent implements OnIni public usedReportCodes?: F3xReportCodes[]; public thisYear = new Date().getFullYear(); committeeAccount?: CommitteeAccount; + reportCodeLabelMap?: { [key in F3xReportCodes]: string }; constructor( private store: Store, @@ -65,6 +66,7 @@ export class CreateF3XStep1Component extends DestroyerComponent implements OnIni ngOnInit(): void { const reportId = this.activatedRoute.snapshot.data['reportId']; + this.form3XService.getReportCodeLabelMap().then((map) => (this.reportCodeLabelMap = map)); this.store .select(selectActiveReport) .pipe(takeUntil(this.destroy$)) @@ -121,7 +123,7 @@ export class CreateF3XStep1Component extends DestroyerComponent implements OnIni startWith(this.form.controls['report_type_category'].value), ), ]).subscribe(([reportCode, filingFrequency, reportTypeCategory]) => { - const coverageDatesFunction = F3X_REPORT_CODE_MAP.get(reportCode)?.coverageDatesFunction; + const coverageDatesFunction = getCoverageDatesFunction(reportCode); if (coverageDatesFunction) { const isElectionYear = F3xReportTypeCategories.ELECTION_YEAR === reportTypeCategory; const [coverage_from_date, coverage_through_date] = coverageDatesFunction( diff --git a/front-end/src/app/reports/submission-workflow/submit-report-status.component.html b/front-end/src/app/reports/submission-workflow/submit-report-status.component.html index ed2566371b..f60edb34fb 100644 --- a/front-end/src/app/reports/submission-workflow/submit-report-status.component.html +++ b/front-end/src/app/reports/submission-workflow/submit-report-status.component.html @@ -38,7 +38,7 @@

YOUR REPORT TYPE:

- {{ reportCode | reportCodeLabel }} + {{ reportCodeLabelMap ? reportCodeLabelMap[reportCode] : '' }}


diff --git a/front-end/src/app/reports/submission-workflow/submit-report-status.component.spec.ts b/front-end/src/app/reports/submission-workflow/submit-report-status.component.spec.ts index 66e867ac02..25774c7f4a 100644 --- a/front-end/src/app/reports/submission-workflow/submit-report-status.component.spec.ts +++ b/front-end/src/app/reports/submission-workflow/submit-report-status.component.spec.ts @@ -1,6 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, provideRouter } from '@angular/router'; import { provideMockStore } from '@ngrx/store/testing'; import { testMockStore } from 'app/shared/utils/unit-test.utils'; import { Form3X } from 'app/shared/models/form-3x.model'; @@ -8,8 +7,11 @@ import { SharedModule } from 'app/shared/shared.module'; import { CardModule } from 'primeng/card'; import { DividerModule } from 'primeng/divider'; import { SubmitReportStatusComponent } from './submit-report-status.component'; +import { Form3XService } from 'app/shared/services/form-3x.service'; +import { ApiService } from 'app/shared/services/api.service'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; -describe('ReportSummaryComponent', () => { +describe('SubmitReportStatusComponent', () => { let component: SubmitReportStatusComponent; let fixture: ComponentFixture; const f3x: Form3X = Form3X.fromJSON({ @@ -21,10 +23,11 @@ describe('ReportSummaryComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [SharedModule, DividerModule, CardModule, RouterTestingModule.withRoutes([])], + imports: [SharedModule, DividerModule, CardModule, HttpClientTestingModule], declarations: [SubmitReportStatusComponent], providers: [ provideMockStore(testMockStore), + provideRouter([]), { provide: ActivatedRoute, useValue: { @@ -35,6 +38,8 @@ describe('ReportSummaryComponent', () => { }, }, }, + Form3XService, + ApiService, ], }).compileComponents(); }); diff --git a/front-end/src/app/reports/submission-workflow/submit-report-status.component.ts b/front-end/src/app/reports/submission-workflow/submit-report-status.component.ts index 638ffc4329..6ed48cb4fe 100644 --- a/front-end/src/app/reports/submission-workflow/submit-report-status.component.ts +++ b/front-end/src/app/reports/submission-workflow/submit-report-status.component.ts @@ -6,6 +6,7 @@ import { selectActiveReport } from 'app/store/active-report.selectors'; import { DestroyerComponent } from 'app/shared/components/app-destroyer.component'; import { Report } from 'app/shared/models/report.model'; import { F3xReportCodes } from 'app/shared/utils/report-code.utils'; +import { Form3XService } from 'app/shared/services/form-3x.service'; @Component({ selector: 'app-report-summary', @@ -16,21 +17,24 @@ export class SubmitReportStatusComponent extends DestroyerComponent implements O report?: Report; reportCode?: F3xReportCodes; coverageDates?: { [key: string]: Date | undefined }; + reportCodeLabelMap?: { [key in F3xReportCodes]: string }; constructor( private store: Store, public router: Router, + private form3XService: Form3XService, ) { super(); } ngOnInit(): void { + this.form3XService.getReportCodeLabelMap().then((map) => (this.reportCodeLabelMap = map)); this.store .select(selectActiveReport) .pipe(takeUntil(this.destroy$)) .subscribe((report) => { this.report = report; - this.reportCode = report.reportCode; + this.reportCode = report.report_code as F3xReportCodes; this.coverageDates = report.coverageDates; }); } diff --git a/front-end/src/app/shared/components/contact-dialog/contact-dialog.component.ts b/front-end/src/app/shared/components/contact-dialog/contact-dialog.component.ts index 78be808539..38788554aa 100644 --- a/front-end/src/app/shared/components/contact-dialog/contact-dialog.component.ts +++ b/front-end/src/app/shared/components/contact-dialog/contact-dialog.component.ts @@ -54,7 +54,7 @@ export class TransactionData { const report = getReportFromJSON(r); if (report.report_type === ReportTypes.F24) return; // We will display the Form 3X version of the transaction #1977 this.form_type = report.formLabel; - this.report_code_label = report.reportLabel; + this.report_code_label = report.report_code_label ?? ''; }); } } diff --git a/front-end/src/app/shared/components/inputs/linked-report-input/linked-report-input.component.spec.ts b/front-end/src/app/shared/components/inputs/linked-report-input/linked-report-input.component.spec.ts index c40125f5e0..5f644e6e9c 100644 --- a/front-end/src/app/shared/components/inputs/linked-report-input/linked-report-input.component.spec.ts +++ b/front-end/src/app/shared/components/inputs/linked-report-input/linked-report-input.component.spec.ts @@ -55,6 +55,7 @@ describe('LinkedReportInputComponent', () => { coverage_from_date: '2020-01-15', coverage_through_date: '2020-04-29', report_code: F3xReportCodes.Q1, + report_code_label: 'APRIL 15 (Q1)', }); component.committeeF3xReports = firstValueFrom(of([testF3X])); diff --git a/front-end/src/app/shared/components/inputs/linked-report-input/linked-report-input.component.ts b/front-end/src/app/shared/components/inputs/linked-report-input/linked-report-input.component.ts index 313e9b8df0..ce9385dc4e 100644 --- a/front-end/src/app/shared/components/inputs/linked-report-input/linked-report-input.component.ts +++ b/front-end/src/app/shared/components/inputs/linked-report-input/linked-report-input.component.ts @@ -4,7 +4,6 @@ import { BaseInputComponent } from '../base-input.component'; import { Report, ReportTypes } from 'app/shared/models/report.model'; import { ReportService } from 'app/shared/services/report.service'; import { Form3X } from 'app/shared/models/form-3x.model'; -import { getReportCodeLabel } from 'app/shared/utils/report-code.utils'; import { FecDatePipe } from 'app/shared/pipes/fec-date.pipe'; import { FormControl } from '@angular/forms'; import { buildCorrespondingForm3XValidator } from 'app/shared/utils/validators.utils'; @@ -79,7 +78,7 @@ export class LinkedReportInputComponent extends BaseInputComponent implements On getForm3XLabel(report: Form3X | undefined): string { if (!report) return ''; - let label = getReportCodeLabel(report.report_code); + let label = report.report_code_label ?? ''; const stringsToRemove = [' MID-YEAR-REPORT', ' YEAR-END', ' QUARTERLY REPORT', ' MONTHLY REPORT']; for (const string of stringsToRemove) { label = label?.replaceAll(string, ''); diff --git a/front-end/src/app/shared/models/form-1m.model.ts b/front-end/src/app/shared/models/form-1m.model.ts index 84d36acfa4..be8e5c2146 100644 --- a/front-end/src/app/shared/models/form-1m.model.ts +++ b/front-end/src/app/shared/models/form-1m.model.ts @@ -31,10 +31,6 @@ export class Form1M extends Report { return 'NOTIFICATION OF MULTICANDIDATE STATUS'; } - get reportLabel(): string { - return ''; - } - committee_type?: CommitteeType; @Transform(BaseModel.dateTransform) affiliated_date_form_f1_filed?: Date; diff --git a/front-end/src/app/shared/models/form-24.model.spec.ts b/front-end/src/app/shared/models/form-24.model.spec.ts index cec50d87cc..61d1c82a46 100644 --- a/front-end/src/app/shared/models/form-24.model.spec.ts +++ b/front-end/src/app/shared/models/form-24.model.spec.ts @@ -46,12 +46,14 @@ describe('Form24', () => { committee_name: 'foo', report_version: undefined, report_type_24_48: '24', + report_code_label: '24 HOUR', }; const form = Form24.fromJSON(data); - expect(form.reportLabel).toBe('24 HOUR'); + expect(form.report_code_label).toBe('24 HOUR'); form.report_type_24_48 = '48'; - expect(form.reportLabel).toBe('48 HOUR'); + form.report_code_label = '48 HOUR'; + expect(form.report_code_label).toBe('48 HOUR'); }); }); diff --git a/front-end/src/app/shared/models/form-24.model.ts b/front-end/src/app/shared/models/form-24.model.ts index 3d07b0548d..8cce4f4fe0 100644 --- a/front-end/src/app/shared/models/form-24.model.ts +++ b/front-end/src/app/shared/models/form-24.model.ts @@ -23,10 +23,6 @@ export class Form24 extends Report { return ''; } - get reportLabel(): string { - return `${this.report_type_24_48} HOUR`; - } - override get canAmend(): boolean { return this.report_status === ReportStatus.SUBMIT_SUCCESS; } diff --git a/front-end/src/app/shared/models/form-3x.model.spec.ts b/front-end/src/app/shared/models/form-3x.model.spec.ts index dd3cb92002..e03db7500f 100644 --- a/front-end/src/app/shared/models/form-3x.model.spec.ts +++ b/front-end/src/app/shared/models/form-3x.model.spec.ts @@ -1,7 +1,7 @@ +import { F3xReportCodes } from '../utils/report-code.utils'; import { F3xFormTypes, Form3X } from './form-3x.model'; import { UploadSubmission } from './upload-submission.model'; import { WebPrintSubmission } from './webprint-submission.model'; -import { F3xReportCodes } from '../utils/report-code.utils'; describe('Form3X', () => { it('should create an instance', () => { @@ -75,6 +75,7 @@ describe('Form3X', () => { form_type: F3xFormTypes.F3XT, committee_name: 'foo', report_code: F3xReportCodes.Q1, + report_code_label: 'APRIL 15 QUARTERLY REPORT (Q1)', }; const form3X = Form3X.fromJSON(data); expect(form3X.formSubLabel).toEqual('APRIL 15 QUARTERLY REPORT (Q1)'); diff --git a/front-end/src/app/shared/models/form-3x.model.ts b/front-end/src/app/shared/models/form-3x.model.ts index e63f2a99ff..d81e5b88f3 100644 --- a/front-end/src/app/shared/models/form-3x.model.ts +++ b/front-end/src/app/shared/models/form-3x.model.ts @@ -1,8 +1,8 @@ import { plainToClass, plainToInstance, Transform } from 'class-transformer'; import { schema as f3xSchema } from 'fecfile-validate/fecfile_validate_js/dist/F3X'; -import { F3xReportCodes, getReportCodeLabel } from '../utils/report-code.utils'; import { BaseModel } from './base.model'; import { Report, ReportStatus, ReportTypes } from './report.model'; +import { F3xReportCodes } from '../utils/report-code.utils'; export enum F3xFormTypes { F3XN = 'F3XN', @@ -16,9 +16,11 @@ export class F3xCoverageDates { @Transform(BaseModel.dateTransform) coverage_from_date: Date | undefined; @Transform(BaseModel.dateTransform) coverage_through_date: Date | undefined; report_code: F3xReportCodes | undefined; + report_code_label?: string; // prettier-ignore - static fromJSON(json: any): F3xCoverageDates { // eslint-disable-line @typescript-eslint/no-explicit-any + static fromJSON(json: any, reportCodeLabel: string): F3xCoverageDates { // eslint-disable-line @typescript-eslint/no-explicit-any + json.report_code_label = reportCodeLabel; return plainToClass(F3xCoverageDates, json); } } @@ -31,7 +33,6 @@ export class Form3X extends Report { form_type = F3xFormTypes.F3XN; override hasChangeOfAddress = true; change_of_address: boolean | undefined; - report_code: F3xReportCodes | undefined; election_code: string | undefined; @Transform(BaseModel.dateTransform) date_of_election: Date | undefined; state_of_election: string | undefined; @@ -148,10 +149,6 @@ export class Form3X extends Report { L38_net_operating_expenditures_ytd: number | undefined; calculation_status: string | undefined; - override get reportCode(): F3xReportCodes | undefined { - return this.report_code; - } - override get coverageDates(): { [date: string]: Date | undefined } { return { coverage_from_date: this.coverage_from_date, coverage_through_date: this.coverage_through_date }; } @@ -165,11 +162,7 @@ export class Form3X extends Report { } get formSubLabel() { - return getReportCodeLabel(this.report_code) ?? ''; - } - - get reportLabel(): string { - return getReportCodeLabel(this.reportCode) ?? ''; + return this.report_code_label ?? ''; } static fromJSON(json: unknown): Form3X { diff --git a/front-end/src/app/shared/models/form-99.model.ts b/front-end/src/app/shared/models/form-99.model.ts index e1deacb8c9..d32e5c959d 100644 --- a/front-end/src/app/shared/models/form-99.model.ts +++ b/front-end/src/app/shared/models/form-99.model.ts @@ -24,10 +24,6 @@ export class Form99 extends Report { return textCodes.find(({ value }) => value === this.text_code)?.label ?? ''; } - get reportLabel(): string { - return ''; - } - treasurer_last_name: string | undefined; treasurer_first_name: string | undefined; treasurer_middle_name: string | undefined; diff --git a/front-end/src/app/shared/models/report.model.ts b/front-end/src/app/shared/models/report.model.ts index b692c902a7..061bb3ab4a 100644 --- a/front-end/src/app/shared/models/report.model.ts +++ b/front-end/src/app/shared/models/report.model.ts @@ -3,7 +3,6 @@ import { BaseModel } from './base.model'; import { UploadSubmission } from './upload-submission.model'; import { WebPrintSubmission } from './webprint-submission.model'; import { JsonSchema } from '../interfaces/json-schema.interface'; -import { F3xReportCodes } from '../utils/report-code.utils'; import { LabelList } from '../utils/label.utils'; export abstract class Report extends BaseModel { @@ -40,17 +39,13 @@ export abstract class Report extends BaseModel { updated: Date | undefined; can_delete = false; version_label?: string; + report_code?: string; + report_code_label?: string; abstract get formLabel(): string; abstract get formSubLabel(): string; - abstract get reportLabel(): string; - - get reportCode(): F3xReportCodes | undefined { - return; - } - get coverageDates(): { [date: string]: Date | undefined } | undefined { return; } diff --git a/front-end/src/app/shared/services/form-3x.service.ts b/front-end/src/app/shared/services/form-3x.service.ts index 20bee8d70a..b99ffaee4d 100644 --- a/front-end/src/app/shared/services/form-3x.service.ts +++ b/front-end/src/app/shared/services/form-3x.service.ts @@ -1,12 +1,13 @@ import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; +import { BehaviorSubject, Observable, firstValueFrom } from 'rxjs'; import { map } from 'rxjs/operators'; import { CommitteeAccount } from '../models/committee-account.model'; import { F3xCoverageDates, F3xQualifiedCommitteeTypeCodes, Form3X } from '../models/form-3x.model'; import { ApiService } from './api.service'; import { ReportService } from './report.service'; import { Report } from '../models/report.model'; +import { F3xReportCodes } from '../utils/report-code.utils'; @Injectable({ providedIn: 'root', @@ -14,6 +15,8 @@ import { Report } from '../models/report.model'; export class Form3XService extends ReportService { override apiEndpoint = '/reports/form-3x'; + f3xReportCodeLabelMap$ = new BehaviorSubject<{ [key in F3xReportCodes]: string } | undefined>(undefined); + constructor( override apiService: ApiService, override store: Store, @@ -21,10 +24,25 @@ export class Form3XService extends ReportService { super(apiService, store); } - public getF3xCoverageDates(): Observable { - return this.apiService - .get(`${this.apiEndpoint}/coverage_dates`) - .pipe(map((response) => response.map((fx3CoverageDate) => F3xCoverageDates.fromJSON(fx3CoverageDate)))); + public async getF3xCoverageDates(): Promise { + const [response, reportCodeLabelMap] = await Promise.all([ + firstValueFrom(this.apiService.get(`${this.apiEndpoint}/coverage_dates`)), + this.getReportCodeLabelMap(), + ]); + return response.map((fx3CoverageDate) => + F3xCoverageDates.fromJSON(fx3CoverageDate, reportCodeLabelMap[fx3CoverageDate.report_code!]), + ); + } + + public async getReportCodeLabelMap(): Promise<{ [key in F3xReportCodes]: string }> { + let map = this.f3xReportCodeLabelMap$.getValue(); + if (!map) { + map = await firstValueFrom( + this.apiService.get<{ [key in F3xReportCodes]: string }>(`${this.apiEndpoint}/report_code_map`), + ); + this.f3xReportCodeLabelMap$.next(map); + } + return map; } public getFutureReports(coverage_through_date: string): Observable { diff --git a/front-end/src/app/shared/shared.module.ts b/front-end/src/app/shared/shared.module.ts index 2c7d6090db..1c62745558 100644 --- a/front-end/src/app/shared/shared.module.ts +++ b/front-end/src/app/shared/shared.module.ts @@ -50,7 +50,6 @@ import { FecDatePipe } from './pipes/fec-date.pipe'; import { HighlightTermsPipe } from './pipes/highlight-terms.pipe'; import { LabelPipe } from './pipes/label.pipe'; import { LongDatePipe } from './pipes/long-date.pipe'; -import { ReportCodeLabelPipe } from './utils/report-code.utils'; import { SupportOpposeInputComponent } from './components/inputs/support-oppose-input/support-oppose-input.component'; import { SingleClickDirective } from './directives/single-click.directive'; import { RippleModule } from 'primeng/ripple'; @@ -102,7 +101,6 @@ import { SidebarModule } from 'primeng/sidebar'; LongDatePipe, DefaultZeroPipe, HighlightTermsPipe, - ReportCodeLabelPipe, FecInternationalPhoneInputComponent, NavigationControlComponent, NavigationControlBarComponent, @@ -146,7 +144,6 @@ import { SidebarModule } from 'primeng/sidebar'; ErrorMessagesComponent, DefaultZeroPipe, HighlightTermsPipe, - ReportCodeLabelPipe, FecInternationalPhoneInputComponent, NavigationControlComponent, NavigationControlBarComponent, diff --git a/front-end/src/app/shared/utils/reatt-redes/reattributed.utils.ts b/front-end/src/app/shared/utils/reatt-redes/reattributed.utils.ts index 8a398125e9..b2d6ab5898 100644 --- a/front-end/src/app/shared/utils/reatt-redes/reattributed.utils.ts +++ b/front-end/src/app/shared/utils/reatt-redes/reattributed.utils.ts @@ -1,6 +1,5 @@ import { ReattRedesTypes, ReattRedesUtils } from './reatt-redes.utils'; import { SchATransaction } from '../../models/scha-transaction.model'; -import { getReportCodeLabel } from '../report-code.utils'; export class ReattributedUtils { public static overlayTransactionProperties(transaction: SchATransaction, activeReportId?: string): SchATransaction { @@ -12,7 +11,7 @@ export class ReattributedUtils { if (transaction.report_ids?.includes(activeReportId as string)) { transaction.contribution_purpose_descrip = 'See reattribution below.'; } else { - transaction.contribution_purpose_descrip = `(Originally disclosed on ${getReportCodeLabel(transaction.getForm3X()?.report_code)}.) See reattribution below.`; + transaction.contribution_purpose_descrip = `(Originally disclosed on ${transaction.getForm3X()?.report_code_label ?? ''}.) See reattribution below.`; } transaction.reattribution_redesignation_tag = ReattRedesTypes.REATTRIBUTED; } diff --git a/front-end/src/app/shared/utils/reatt-redes/redesignated.utils.spec.ts b/front-end/src/app/shared/utils/reatt-redes/redesignated.utils.spec.ts index 2e5fd57dac..9f041574fc 100644 --- a/front-end/src/app/shared/utils/reatt-redes/redesignated.utils.spec.ts +++ b/front-end/src/app/shared/utils/reatt-redes/redesignated.utils.spec.ts @@ -20,7 +20,7 @@ describe('Redesignated Utils', () => { let data; it('should handle a different report', () => { if (!payload.reatt_redes || !(payload.reatt_redes instanceof SchBTransaction)) throw new Error('Bad test setup'); - expect(payload.reatt_redes.getForm3X()?.reportCode).toBe(F3xReportCodes.Q1); + expect(payload.reatt_redes.getForm3X()?.report_code).toBe(F3xReportCodes.Q1); const overlay = RedesignatedUtils.overlayTransactionProperties( payload.reatt_redes, 'not-the-same-report-as-orig', diff --git a/front-end/src/app/shared/utils/reatt-redes/redesignated.utils.ts b/front-end/src/app/shared/utils/reatt-redes/redesignated.utils.ts index 5756eb6ab2..3ca91cc736 100644 --- a/front-end/src/app/shared/utils/reatt-redes/redesignated.utils.ts +++ b/front-end/src/app/shared/utils/reatt-redes/redesignated.utils.ts @@ -1,6 +1,5 @@ import { ReattRedesTypes, ReattRedesUtils } from './reatt-redes.utils'; import { SchBTransaction } from '../../models/schb-transaction.model'; -import { getReportCodeLabel } from '../report-code.utils'; export class RedesignatedUtils { public static overlayTransactionProperties(transaction: SchBTransaction, activeReportId?: string): SchBTransaction { @@ -12,7 +11,7 @@ export class RedesignatedUtils { if (transaction.report_ids?.includes(activeReportId as string)) { transaction.expenditure_purpose_descrip = 'See redesignation below.'; } else { - transaction.expenditure_purpose_descrip = `(Originally disclosed on ${getReportCodeLabel(transaction.getForm3X()?.report_code)}.) See redesignation below.`; + transaction.expenditure_purpose_descrip = `(Originally disclosed on ${transaction.getForm3X()?.report_code_label ?? ''}.) See redesignation below.`; } transaction.reattribution_redesignation_tag = ReattRedesTypes.REDESIGNATED; } diff --git a/front-end/src/app/shared/utils/report-code.utils.spec.ts b/front-end/src/app/shared/utils/report-code.utils.spec.ts index 9bd403b869..7e44eac9d9 100644 --- a/front-end/src/app/shared/utils/report-code.utils.spec.ts +++ b/front-end/src/app/shared/utils/report-code.utils.spec.ts @@ -1,54 +1,3 @@ -import { F3xReportCode, F3xReportCodes, F3X_REPORT_CODE_MAP, getReportCodeLabel } from './report-code.utils'; +import { F3xReportCodes } from './report-code.utils'; -describe('ReportCodeUtils', () => { - describe('F3xReportCode', () => { - it('should carry properties', () => { - const coverageDateFunction = (year: number): [Date, Date] => { - return [new Date(year, 0, 1), new Date(year, 0, 2)]; - }; - const f3xReportCode = new F3xReportCode('MY', 'label for MY', coverageDateFunction); - expect(f3xReportCode.label).toBe('label for MY'); - expect(f3xReportCode.coverageDatesFunction).toEqual(coverageDateFunction); - }); - }); - - describe('F3X_REPORT_CODE_MAP', () => { - it('should have Q1', () => { - const Q1 = F3X_REPORT_CODE_MAP.get(F3xReportCodes.Q1); - expect(Q1).toBeTruthy(); - expect(Q1?.label).toEqual('APRIL 15 QUARTERLY REPORT (Q1)'); - if (Q1?.coverageDatesFunction) { - expect(Q1.coverageDatesFunction(2022, false, 'M')).toEqual([new Date(2022, 0, 1), new Date(2022, 2, 31)]); - } - }); - it('should have M3', () => { - const M3 = F3X_REPORT_CODE_MAP.get(F3xReportCodes.M3); - expect(M3).toBeTruthy(); - expect(M3?.label).toEqual('MARCH 20 MONTHLY REPORT (M3)'); - if (M3?.coverageDatesFunction) { - expect(M3.coverageDatesFunction(2022, false, 'M')).toEqual([new Date(2022, 1, 1), new Date(2022, 1, 28)]); - // test leap year - expect(M3.coverageDatesFunction(2020, false, 'M')).toEqual([new Date(2020, 1, 1), new Date(2020, 1, 29)]); - } - }); - it('should have YE', () => { - const YE = F3X_REPORT_CODE_MAP.get(F3xReportCodes.YE); - expect(YE).toBeTruthy(); - expect(YE?.label).toEqual('JANUARY 31 YEAR-END (YE)'); - if (YE?.coverageDatesFunction) { - expect(YE.coverageDatesFunction(2022, false, 'M')).toEqual([new Date(2021, 11, 1), new Date(2021, 11, 31)]); - // Quarterly non-election year - expect(YE.coverageDatesFunction(2022, false, 'Q')).toEqual([new Date(2021, 6, 1), new Date(2021, 11, 31)]); - // Quarterly election year - expect(YE.coverageDatesFunction(2022, true, 'Q')).toEqual([new Date(2021, 9, 1), new Date(2021, 11, 31)]); - } - }); - }); - - describe('getReportCodeLabel', () => { - it('should get label for report code', () => { - expect(getReportCodeLabel(F3xReportCodes.YE)).toEqual('JANUARY 31 YEAR-END (YE)'); - expect(getReportCodeLabel()).toEqual(undefined); - }); - }); -}); +describe('ReportCodeUtils', () => {}); diff --git a/front-end/src/app/shared/utils/report-code.utils.ts b/front-end/src/app/shared/utils/report-code.utils.ts index 29bcbab840..c2382bee18 100644 --- a/front-end/src/app/shared/utils/report-code.utils.ts +++ b/front-end/src/app/shared/utils/report-code.utils.ts @@ -1,5 +1,3 @@ -import { Pipe, PipeTransform } from '@angular/core'; - export enum F3xReportCodes { Q1 = 'Q1', Q2 = 'Q2', @@ -28,21 +26,60 @@ export enum F3xReportCodes { M12 = 'M12', } -export class F3xReportCode { - code: string; - label: string; - coverageDatesFunction: ((year: number, isElectionYear: boolean, filingFrequency: string) => [Date, Date]) | undefined; - - constructor( - code: string, - label: string, - coverageDatesFunction: - | ((year: number, isElectionYear: boolean, filingFrequency: string) => [Date, Date]) - | undefined, - ) { - this.code = code; - this.label = label; - this.coverageDatesFunction = coverageDatesFunction; +export function getCoverageDatesFunction( + reportCode: F3xReportCodes, +): ((year: number, isElectionYear: boolean, filingFrequency: string) => [Date, Date]) | undefined { + switch (reportCode) { + case F3xReportCodes.Q1: { + return createCoverageFunction(0, 1, 2, 31); + } + case F3xReportCodes.Q2: { + return createCoverageFunction(3, 1, 5, 30); + } + case F3xReportCodes.Q3: { + return createCoverageFunction(6, 1, 8, 30); + } + case F3xReportCodes.YE: { + return getYearEndCoverageDates; + } + case F3xReportCodes.MY: { + return createCoverageFunction(0, 1, 5, 30); + } + case F3xReportCodes.M2: { + return createCoverageFunction(0, 1, 0, 31); + } + case F3xReportCodes.M3: { + return createCoverageFunction(1, 1, 2, 0); + } + case F3xReportCodes.M4: { + return createCoverageFunction(2, 1, 2, 31); + } + case F3xReportCodes.M5: { + return createCoverageFunction(3, 1, 3, 30); + } + case F3xReportCodes.M6: { + return createCoverageFunction(4, 1, 4, 31); + } + case F3xReportCodes.M7: { + return createCoverageFunction(5, 1, 5, 30); + } + case F3xReportCodes.M8: { + return createCoverageFunction(6, 1, 6, 31); + } + case F3xReportCodes.M9: { + return createCoverageFunction(7, 1, 7, 31); + } + case F3xReportCodes.M10: { + return createCoverageFunction(8, 1, 8, 30); + } + case F3xReportCodes.M11: { + return createCoverageFunction(9, 1, 9, 31); + } + case F3xReportCodes.M12: { + return createCoverageFunction(10, 1, 10, 30); + } + default: + return undefined; } } @@ -66,98 +103,6 @@ function getYearEndCoverageDates(year: number, isElectionYear: boolean, filingFr return [new Date(year - 1, 11, 1), new Date(year - 1, 11, 31)]; } -/* - * These long-form labels include more detailed descriptions than the labels provided - * by the API and are used when creating a report and during the submission process. - */ -export const F3X_REPORT_CODE_MAP = new Map([ - [ - F3xReportCodes.Q1, - new F3xReportCode(F3xReportCodes.Q1, 'APRIL 15 QUARTERLY REPORT (Q1)', createCoverageFunction(0, 1, 2, 31)), - ], - [ - F3xReportCodes.Q2, - new F3xReportCode(F3xReportCodes.Q2, 'JULY 15 QUARTERLY REPORT (Q2)', createCoverageFunction(3, 1, 5, 30)), - ], - [ - F3xReportCodes.Q3, - new F3xReportCode(F3xReportCodes.Q3, 'OCTOBER 15 QUARTERLY REPORT (Q3)', createCoverageFunction(6, 1, 8, 30)), - ], - [F3xReportCodes.YE, new F3xReportCode(F3xReportCodes.YE, 'JANUARY 31 YEAR-END (YE)', getYearEndCoverageDates)], - [F3xReportCodes.TER, new F3xReportCode(F3xReportCodes.TER, 'TERMINATION REPORT (TER)', undefined)], - [ - F3xReportCodes.MY, - new F3xReportCode(F3xReportCodes.MY, 'JULY 31 MID-YEAR REPORT (MY)', createCoverageFunction(0, 1, 5, 30)), - ], - [F3xReportCodes.TwelveG, new F3xReportCode(F3xReportCodes.TwelveG, '12-DAY PRE-GENERAL (12G)', undefined)], - [F3xReportCodes.TwelveP, new F3xReportCode(F3xReportCodes.TwelveP, '12-DAY PRE-PRIMARY (12P)', undefined)], - [F3xReportCodes.TwelveR, new F3xReportCode(F3xReportCodes.TwelveR, '12-DAY PRE-RUNOFF (12R)', undefined)], - [F3xReportCodes.TwelveS, new F3xReportCode(F3xReportCodes.TwelveS, '12-DAY PRE-SPECIAL (12S)', undefined)], - [F3xReportCodes.TwelveC, new F3xReportCode(F3xReportCodes.TwelveC, '12-DAY PRE-CONVENTION (12C)', undefined)], - [F3xReportCodes.ThirtyG, new F3xReportCode(F3xReportCodes.ThirtyG, '30-DAY POST-GENERAL (30G)', undefined)], - [F3xReportCodes.ThirtyR, new F3xReportCode(F3xReportCodes.ThirtyR, '30-DAY POST-RUNOFF (30R)', undefined)], - [F3xReportCodes.ThirtyS, new F3xReportCode(F3xReportCodes.ThirtyS, '30-DAY POST-SPECIAL (30S)', undefined)], - [ - F3xReportCodes.M2, - new F3xReportCode(F3xReportCodes.M2, 'FEBRUARY 20 MONTHLY REPORT (M2)', createCoverageFunction(0, 1, 0, 31)), - ], - // Note that new Date(yyyy, 2, 0) returns the last day of february dynamically (handles leap years) - [ - F3xReportCodes.M3, - new F3xReportCode(F3xReportCodes.M3, 'MARCH 20 MONTHLY REPORT (M3)', createCoverageFunction(1, 1, 2, 0)), - ], - [ - F3xReportCodes.M4, - new F3xReportCode(F3xReportCodes.M4, 'APRIL 20 MONTHLY REPORT (M4)', createCoverageFunction(2, 1, 2, 31)), - ], - [ - F3xReportCodes.M5, - new F3xReportCode(F3xReportCodes.M5, 'MAY 20 MONTHLY REPORT (M5)', createCoverageFunction(3, 1, 3, 30)), - ], - [ - F3xReportCodes.M6, - new F3xReportCode(F3xReportCodes.M6, 'JUNE 20 MONTHLY REPORT (M6)', createCoverageFunction(4, 1, 4, 31)), - ], - [ - F3xReportCodes.M7, - new F3xReportCode(F3xReportCodes.M7, 'JULY 20 MONTHLY REPORT (M7)', createCoverageFunction(5, 1, 5, 30)), - ], - [ - F3xReportCodes.M8, - new F3xReportCode(F3xReportCodes.M8, 'AUGUST 20 MONTHLY REPORT (M8)', createCoverageFunction(6, 1, 6, 31)), - ], - [ - F3xReportCodes.M9, - new F3xReportCode(F3xReportCodes.M9, 'SEPTEMBER 20 MONTHLY REPORT (M9)', createCoverageFunction(7, 1, 7, 31)), - ], - [ - F3xReportCodes.M10, - new F3xReportCode(F3xReportCodes.M10, 'OCTOBER 20 MONTHLY REPORT (M10)', createCoverageFunction(8, 1, 8, 30)), - ], - [ - F3xReportCodes.M11, - new F3xReportCode(F3xReportCodes.M11, 'NOVEMBER 20 MONTHLY REPORT (M11)', createCoverageFunction(9, 1, 9, 31)), - ], - [ - F3xReportCodes.M12, - new F3xReportCode(F3xReportCodes.M12, 'DECEMBER 20 MONTHLY REPORT (M12)', createCoverageFunction(10, 1, 10, 30)), - ], -]); - -export function getReportCodeLabel(reportCode?: F3xReportCodes): string | undefined { - if (reportCode) return F3X_REPORT_CODE_MAP.get(reportCode)?.label; - else return undefined; -} - -@Pipe({ - name: 'reportCodeLabel', -}) -export class ReportCodeLabelPipe implements PipeTransform { - transform(reportCode: F3xReportCodes | undefined): string { - return getReportCodeLabel(reportCode) || ''; - } -} - export const monthlyElectionYearReportCodes: F3xReportCodes[] = [ F3xReportCodes.M2, F3xReportCodes.M3, diff --git a/front-end/src/app/shared/utils/unit-test.utils.ts b/front-end/src/app/shared/utils/unit-test.utils.ts index 85844216c9..c2701193ab 100644 --- a/front-end/src/app/shared/utils/unit-test.utils.ts +++ b/front-end/src/app/shared/utils/unit-test.utils.ts @@ -92,6 +92,7 @@ export const testActiveReport: Form3X = Form3X.fromJSON({ form_type: 'F3XN', report_type: 'F3X', report_code: 'Q1', + report_code_label: 'APRIL 15 QUARTERLY REPORT (Q1)', upload_submission: UploadSubmission.fromJSON({}), webprint_submission: { fec_email: 'test@test.com', @@ -208,7 +209,7 @@ export const testScheduleATransaction = SchATransaction.fromJSON({ { report_type: 'F3X', report_code: 'Q1', - reportCode: 'Q1', + report_code_label: 'APRIL 15 QUARTERLY REPORT (Q1)', coverage_through_date: '2024-04-20', }, ], @@ -233,7 +234,7 @@ export const testScheduleBTransaction = SchBTransaction.fromJSON({ { report_type: 'F3X', report_code: 'Q1', - reportCode: 'Q1', + report_code_label: 'APRIL 15 QUARTERLY REPORT (Q1)', }, ], }); diff --git a/front-end/src/app/shared/utils/validators.utils.ts b/front-end/src/app/shared/utils/validators.utils.ts index e361a9190e..2790070aa3 100644 --- a/front-end/src/app/shared/utils/validators.utils.ts +++ b/front-end/src/app/shared/utils/validators.utils.ts @@ -1,7 +1,6 @@ import { AbstractControl, AsyncValidator, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; import { F3xCoverageDates } from '../models/form-3x.model'; import { DateUtils } from './date.utils'; -import { getReportCodeLabel } from './report-code.utils'; import { FecDatePipe } from '../pipes/fec-date.pipe'; import * as _ from 'lodash'; import { SchATransaction } from '../models/scha-transaction.model'; @@ -118,7 +117,7 @@ function getCoverageOverlapError(collision: F3xCoverageDates): ValidationErrors const fecDatePipe = new FecDatePipe(); const message = `You have entered coverage dates that overlap ` + - `the coverage dates of the following report: ${getReportCodeLabel(collision.report_code)} ` + + `the coverage dates of the following report: ${collision.report_code_label} ` + ` ${fecDatePipe.transform(collision.coverage_from_date)} -` + ` ${fecDatePipe.transform(collision.coverage_through_date)}`; return { invaliddate: { msg: message } };