From 4e5e5d937a4bf994d71ab3199f990bed33757631 Mon Sep 17 00:00:00 2001 From: toddlees Date: Tue, 18 Oct 2022 14:58:04 -0400 Subject: [PATCH 1/3] define contact fields --- .../src/app/shared/models/contact.model.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/front-end/src/app/shared/models/contact.model.ts b/front-end/src/app/shared/models/contact.model.ts index 3e37ac0012..07f294456b 100644 --- a/front-end/src/app/shared/models/contact.model.ts +++ b/front-end/src/app/shared/models/contact.model.ts @@ -40,6 +40,30 @@ export const CandidateOfficeTypeLabels = [ [CandidateOfficeTypes.SENATE, 'Senate'], ]; +export enum ContactFields { + type = 'Type', + candidate_id = 'Candidate Id', + committee_id = 'Committee Id', + name = 'Name', + last_name = 'Last Name', + first_name = 'First Name', + middle_name = 'Middle Name', + prefix = 'Prefix', + suffix = 'Suffix', + street_1 = 'Street Address', + street_2 = 'Apartment, Suite, Etc.', + city = 'City', + state = 'State/Province', + zip = 'Zip/Postal Code', + employer = 'Employer', + occupation = 'Occupation', + candidate_office = 'Candidate Office', + candidate_state = 'Candidate State', + candidate_district = 'Candidate District', + telephone = 'Telephone', + country = 'Country', +} + export class Contact extends BaseModel { id: string | undefined; type: ContactType = ContactTypes.INDIVIDUAL; From 9417fa5b28284816171f4a623d41c8d23a574de1 Mon Sep 17 00:00:00 2001 From: toddlees Date: Tue, 18 Oct 2022 16:17:16 -0400 Subject: [PATCH 2/3] handle case where contact fields aren't in form --- .../transaction-type-base.component.ts | 118 ++++-------------- 1 file changed, 26 insertions(+), 92 deletions(-) diff --git a/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts b/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts index 5dbb120e02..cd20119af0 100644 --- a/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts +++ b/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts @@ -12,7 +12,7 @@ import { ValidateService } from 'app/shared/services/validate.service'; import { LabelUtils, PrimeOptions } from 'app/shared/utils/label.utils'; import { ConfirmationService, MessageService, SelectItem } from 'primeng/api'; import { BehaviorSubject, combineLatestWith, Observable, of, startWith, Subject, switchMap, takeUntil } from 'rxjs'; -import { Contact, ContactTypeLabels, ContactTypes } from '../../models/contact.model'; +import { Contact, ContactFields, ContactTypeLabels, ContactTypes } from '../../models/contact.model'; @Component({ template: '', @@ -63,8 +63,8 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy protected confirmationService: ConfirmationService, protected fb: FormBuilder, protected router: Router, - protected fecDatePipe: FecDatePipe, - ) { } + protected fecDatePipe: FecDatePipe + ) {} ngOnInit(): void { // Intialize FormGroup, this must be done here. Not working when initialized only above the constructor(). @@ -163,8 +163,7 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy if (payload.contact_id && this.contact) { const transactionContactChanges = this.getFormChangesToTransactionContact(); if (transactionContactChanges?.length) { - const confirmationMessage = this.getEditTransactionContactConfirmationMessage( - transactionContactChanges); + const confirmationMessage = this.getEditTransactionContactConfirmationMessage(transactionContactChanges); this.confirmationService.confirm({ header: 'Confirm', icon: 'pi pi-info-circle', @@ -183,7 +182,8 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy } } else { const confirmationMessage = this.getCreateTransactionContactConfirmationMessage( - payload.entity_type as ContactTypes); + payload.entity_type as ContactTypes + ); this.confirmationService.confirm({ header: 'Confirm', icon: 'pi pi-info-circle', @@ -203,17 +203,19 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy getEditTransactionContactConfirmationMessage(contactChanges: string[]) { if (this.contact) { const changesMessage = 'Change(s): ')); + ...contactChanges.map((change) => `
  • ${change}
  • `, '') + ); let contactName = this.contact.name; if (this.contact.type === ContactTypes.INDIVIDUAL) { contactName = `${this.contact.last_name}, ${this.contact.first_name}`; contactName += this.contact.middle_name ? ' ' + this.contact.middle_name : ''; } - const dateReceived = this.fecDatePipe.transform( - this.form.get('contribution_date')?.value); - return `By saving this transaction, you are also updating the contact for ` + + const dateReceived = this.fecDatePipe.transform(this.form.get('contribution_date')?.value); + return ( + `By saving this transaction, you are also updating the contact for ` + `${contactName}. This change will only affect transactions with ` + - `receipt date on or after ${dateReceived}.

    ${changesMessage}`; + `receipt date on or after ${dateReceived}.

    ${changesMessage}` + ); } return undefined; } @@ -236,97 +238,29 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy `organization contact for ` + `${this.form.get('contributor_organization_name')?.value}`; break; } - return `By saving this transaction, you're also creating a new ${confirmationContactTitle}.` + return `By saving this transaction, you're also creating a new ${confirmationContactTitle}.`; } /** * This method returns the differences between the transaction - * form's contact section and its database contact in prose + * form's contact section and its database contact in prose * for the UI as a string[] (one entry for each change). * @returns string[] containing the changes in prose for the UI. */ getFormChangesToTransactionContact() { - const retval: string[] = []; - if (this.contact) { - switch (this.contact.type) { - case ContactTypes.INDIVIDUAL: - retval.push(...this.getIndFormChangesToTransactionContact()); - break; - case ContactTypes.COMMITTEE: - retval.push(...this.getComFormChangesToTransactionContact()); - break; - case ContactTypes.ORGANIZATION: - retval.push(...this.getOrgFormChangesToTransactionContact()); - break; - } - if (this.form.get('contributor_street_1')?.value !== this.contact.street_1) - retval.push('Updated street address to ' + - this.form.get('contributor_street_1')?.value); - if (this.form.get('contributor_street_2')?.value !== this.contact.street_2) - retval.push('Updated apartment, suite, etc. to ' + - this.form.get('contributor_street_2')?.value); - if (this.form.get('contributor_city')?.value !== this.contact.city) - retval.push('Updated city to ' + - this.form.get('contributor_city')?.value); - if (this.form.get('contributor_state')?.value !== this.contact.state) - retval.push('Updated state to ' + - this.form.get('contributor_state')?.value); - if (this.form.get('contributor_zip')?.value !== this.contact.zip) - retval.push('Updated zip to ' + - this.form.get('contributor_zip')?.value); - } - return retval; - } - - getIndFormChangesToTransactionContact() { - const retval: string[] = []; - if (this.contact) { - if (this.form.get('contributor_last_name')?.value !== this.contact.last_name) - retval.push('Updated last name to ' + - this.form.get('contributor_last_name')?.value); - if (this.form.get('contributor_first_name')?.value !== this.contact.first_name) - retval.push('Updated first name to ' + - this.form.get('contributor_first_name')?.value); - if (this.form.get('contributor_middle_name')?.value !== this.contact.middle_name) - retval.push('Updated middle name to ' + - this.form.get('contributor_middle_name')?.value); - if (this.form.get('contributor_prefix')?.value !== this.contact.prefix) - retval.push('Updated prefix to ' + - this.form.get('contributor_prefix')?.value); - if (this.form.get('contributor_suffix')?.value !== this.contact.suffix) - retval.push('Updated suffix to ' + - this.form.get('contributor_suffix')?.value); - if (this.form.get('contributor_employer')?.value !== this.contact.employer) - retval.push('Updated employer to ' + - this.form.get('contributor_employer')?.value); - if (this.form.get('contributor_occupation')?.value !== this.contact.occupation) - retval.push('Updated occupation to ' + - this.form.get('contributor_occupation')?.value); - } - return retval; - } - - getComFormChangesToTransactionContact() { - const retval: string[] = []; if (this.contact) { - if (this.form.get('donor_committee_fec_id')?.value !== this.contact.committee_id) - retval.push('Updated committee id to ' + - this.form.get('donor_committee_fec_id')?.value); - if (this.form.get('contributor_organization_name')?.value !== this.contact.name) - retval.push('Updated committee name to ' + - this.form.get('contributor_organization_name')?.value); - } - return retval; - } - - getOrgFormChangesToTransactionContact() { - const retval: string[] = []; - if (this.contact) { - if (this.form.get('contributor_organization_name')?.value !== this.contact.name) - retval.push('Updated organization name to ' + - this.form.get('contributor_organization_name')?.value); + return Object.entries(ContactFields) + .map(([field, label]: string[]) => { + const contactValue = (this.contact as Contact)[field as keyof typeof this.contact]; + const formField = this.form.get(`contributor_${field}`); + if (formField && formField?.value !== contactValue) { + return `Updated ${label.toLowerCase()} to ${formField.value || ''}`; + } + return ''; + }) + .filter((change) => change); } - return retval; + return []; } doSave(navigateTo: 'list' | 'add another' | 'add-sub-tran', payload: SchATransaction, transactionTypeToAdd?: string) { From 0dcb1c4d9ae6fa73e62229acc53074d8cc4b70e8 Mon Sep 17 00:00:00 2001 From: toddlees Date: Tue, 18 Oct 2022 17:46:54 -0400 Subject: [PATCH 3/3] handle donor_committee_fec_id --- .../transaction-type-base.component.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts b/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts index cd20119af0..9d0d83b16d 100644 --- a/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts +++ b/front-end/src/app/shared/components/transaction-type-base/transaction-type-base.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { FormBuilder, FormGroup } from '@angular/forms'; +import { AbstractControl, FormBuilder, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { JsonSchema } from 'app/shared/interfaces/json-schema.interface'; import { TransactionType } from 'app/shared/interfaces/transaction-type.interface'; @@ -252,7 +252,8 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy return Object.entries(ContactFields) .map(([field, label]: string[]) => { const contactValue = (this.contact as Contact)[field as keyof typeof this.contact]; - const formField = this.form.get(`contributor_${field}`); + const formField = this.getFormField(field); + if (formField && formField?.value !== contactValue) { return `Updated ${label.toLowerCase()} to ${formField.value || ''}`; } @@ -263,6 +264,13 @@ export abstract class TransactionTypeBaseComponent implements OnInit, OnDestroy return []; } + getFormField(field: string): AbstractControl | null { + if (field == 'committee_id') { + return this.form.get('donor_committee_fec_id'); + } + return this.form.get(`contributor_${field}`) || this.form.get(`contributor_organization_${field}`); + } + doSave(navigateTo: 'list' | 'add another' | 'add-sub-tran', payload: SchATransaction, transactionTypeToAdd?: string) { if (this.transaction?.transaction_type_identifier) { let fieldsToValidate: string[] = this.validateService.getSchemaProperties(this.schema);