From 594c408079da8fda8cd32c194f4f32337c40c1eb Mon Sep 17 00:00:00 2001 From: Todd Rizzolo Date: Wed, 27 Nov 2024 11:38:28 -0700 Subject: [PATCH 1/3] Add discontinued incomes section --- .../discontinuedIncomePages.js | 306 ++++++++++++++++++ .../chapters/11-discontinued-incomes/index.js | 6 + .../income-and-asset-statement/config/form.js | 2 + .../income-and-asset-statement/labels.jsx | 6 + 4 files changed, 320 insertions(+) create mode 100644 src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/discontinuedIncomePages.js create mode 100644 src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/index.js diff --git a/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/discontinuedIncomePages.js b/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/discontinuedIncomePages.js new file mode 100644 index 000000000000..10f39f4ef49b --- /dev/null +++ b/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/discontinuedIncomePages.js @@ -0,0 +1,306 @@ +import React from 'react'; +import merge from 'lodash/merge'; +import { + arrayBuilderItemFirstPageTitleUI, + arrayBuilderItemSubsequentPageTitleUI, + arrayBuilderYesNoSchema, + arrayBuilderYesNoUI, + currentOrPastDateUI, + currentOrPastDateSchema, + radioUI, + radioSchema, + textUI, + textSchema, +} from '~/platform/forms-system/src/js/web-component-patterns'; +import currencyUI from 'platform/forms-system/src/js/definitions/currency'; +import { VaTextInputField } from 'platform/forms-system/src/js/web-component-fields'; +import { arrayBuilderPages } from '~/platform/forms-system/src/js/patterns/array-builder'; +import { + formatCurrency, + otherRecipientRelationshipExplanationRequired, + recipientNameRequired, + showRecipientName, +} from '../../../helpers'; +import { incomeFrequencyLabels, relationshipLabels } from '../../../labels'; + +/** @type {ArrayBuilderOptions} */ +const options = { + arrayPath: 'discontinuedIncomes', + nounSingular: 'discontinued income', + nounPlural: 'discontinued incomes', + required: false, + isItemIncomplete: item => + !item?.recipientRelationship || + !item.payer || + !item.incomeType || + !item.incomeFrequency || + !item.incomeLastReceivedDate || + !item.grossAnnualAmount, // include all required fields here + maxItems: 5, + text: { + getItemName: () => 'Discontinued income', + cardDescription: item => + item?.grossAnnualAmount && ( + + ), + reviewAddButtonText: 'Add another discontinued income', + alertMaxItems: + 'You have added the maximum number of allowed discontinued incomes for this application. You may edit or delete an discontinued income or choose to continue the application.', + alertItemUpdated: 'Your discontinued income information has been updated', + alertItemDeleted: 'Your discontinued income information has been deleted', + cancelAddTitle: 'Cancel adding this discontinued income', + cancelAddButtonText: 'Cancel adding this discontinued income', + cancelAddYes: 'Yes, cancel adding this discontinued income', + cancelAddNo: 'No', + cancelEditTitle: 'Cancel editing this discontinued income', + cancelEditYes: 'Yes, cancel editing this discontinued income', + cancelEditNo: 'No', + deleteTitle: 'Delete this discontinued income', + deleteYes: 'Yes, delete this discontinued income', + deleteNo: 'No', + }, +}; + +/** + * Cards are populated on this page above the uiSchema if items are present + * + * @returns {PageSchema} + */ +const summaryPage = { + uiSchema: { + 'view:isAddingDiscontinuedIncomes': arrayBuilderYesNoUI( + options, + { + title: + 'Did you or your dependents receive income that has stopped or is no longer being received within the last calendar year?', + labels: { + Y: 'Yes, I have a discontinued income to report', + N: 'No, I don’t have any discontinued incomes to report', + }, + }, + { + title: 'Do you have any more discontinued incomes to report?', + labels: { + Y: 'Yes, I have another discontinued income to report', + N: 'No, I don’t have anymore discontinued incomes to report', + }, + }, + ), + }, + schema: { + type: 'object', + properties: { + 'view:isAddingDiscontinuedIncomes': arrayBuilderYesNoSchema, + }, + required: ['view:isAddingDiscontinuedIncomes'], + }, +}; + +/** @returns {PageSchema} */ +const relationshipPage = { + uiSchema: { + ...arrayBuilderItemFirstPageTitleUI({ + title: 'Discontinued income', + nounSingular: options.nounSingular, + }), + recipientRelationship: radioUI({ + title: 'What is the income recipient’s relationship to the Veteran?', + labels: relationshipLabels, + }), + otherRecipientRelationshipType: { + 'ui:title': 'Tell us the type of relationship', + 'ui:webComponentField': VaTextInputField, + 'ui:options': { + expandUnder: 'recipientRelationship', + expandUnderCondition: 'OTHER', + }, + 'ui:required': (formData, index) => + otherRecipientRelationshipExplanationRequired( + formData, + index, + 'discontinuedIncomes', + ), + }, + recipientName: { + 'ui:title': 'Tell us the income recipient’s name', + 'ui:webComponentField': VaTextInputField, + 'ui:options': { + hint: 'Only needed if child, parent, custodian of child, or other', + expandUnder: 'recipientRelationship', + expandUnderCondition: showRecipientName, + }, + 'ui:required': (formData, index) => + recipientNameRequired(formData, index, 'discontinuedIncomes'), + }, + }, + schema: { + type: 'object', + properties: { + recipientRelationship: radioSchema(Object.keys(relationshipLabels)), + otherRecipientRelationshipType: { type: 'string' }, + recipientName: textSchema, + }, + required: ['recipientRelationship'], + }, +}; + +/** @returns {PageSchema} */ +const incomePayerPage = { + uiSchema: { + ...arrayBuilderItemSubsequentPageTitleUI( + 'Discontinued income relationship', + ), + payer: textUI({ + title: 'Income payer name', + hint: 'Name of business, financial institution, etc.', + }), + }, + schema: { + type: 'object', + properties: { + payer: textSchema, + }, + required: ['payer'], + }, +}; + +/** @returns {PageSchema} */ +const incomeTypePage = { + uiSchema: { + ...arrayBuilderItemSubsequentPageTitleUI('Discontinued income type'), + incomeType: textUI({ + title: 'What is the type of income received?', + hint: 'Interest, dividends, etc', + }), + }, + schema: { + type: 'object', + properties: { + incomeType: textSchema, + }, + required: ['incomeType'], + }, +}; + +/** @returns {PageSchema} */ +const incomeFrequencyPage = { + uiSchema: { + ...arrayBuilderItemSubsequentPageTitleUI('Discontinued income frequency'), + incomeFrequency: radioUI({ + title: 'What is the frequency of the income received?', + labels: incomeFrequencyLabels, + }), + }, + schema: { + type: 'object', + properties: { + incomeFrequency: radioSchema(Object.keys(incomeFrequencyLabels)), + }, + required: ['incomeFrequency'], + }, +}; + +/** @returns {PageSchema} */ +const incomeDatePage = { + uiSchema: { + ...arrayBuilderItemSubsequentPageTitleUI('Discontinued income date'), + incomeLastReceivedDate: currentOrPastDateUI( + 'When was the income last paid?', + ), + }, + schema: { + type: 'object', + properties: { + incomeLastReceivedDate: currentOrPastDateSchema, + }, + required: ['incomeLastReceivedDate'], + }, +}; + +/** @returns {PageSchema} */ +const incomeAmountPage = { + uiSchema: { + ...arrayBuilderItemSubsequentPageTitleUI('Discontinued income amount'), + grossAnnualAmount: merge( + {}, + currencyUI('What was the gross annual amount reported to the IRS?'), + { + 'ui:options': { + classNames: 'schemaform-currency-input-v3', + }, + }, + ), + }, + schema: { + type: 'object', + properties: { + grossAnnualAmount: { type: 'number' }, + }, + required: ['grossAnnualAmount'], + }, +}; + +export const discontinuedIncomePages = arrayBuilderPages( + options, + pageBuilder => ({ + discontinuedIncomePagesSummary: pageBuilder.summaryPage({ + title: 'Discontinued incomes', + path: 'discontinued-incomes-summary', + uiSchema: summaryPage.uiSchema, + schema: summaryPage.schema, + }), + discontinuedIncomeRelationshipPage: pageBuilder.itemPage({ + title: 'Discontinued income relationship', + path: 'discontinued-incomes/:index/relationship', + uiSchema: relationshipPage.uiSchema, + schema: relationshipPage.schema, + }), + discontinuedIncomePayerPage: pageBuilder.itemPage({ + title: 'Discontinued income payer', + path: 'discontinued-incomes/:index/payer', + uiSchema: incomePayerPage.uiSchema, + schema: incomePayerPage.schema, + }), + discontinuedIncomeTypePage: pageBuilder.itemPage({ + title: 'Discontinued income type', + path: 'discontinued-incomes/:index/type', + uiSchema: incomeTypePage.uiSchema, + schema: incomeTypePage.schema, + }), + discontinuedIncomeFrequencyPage: pageBuilder.itemPage({ + title: 'Discontinued income frequency', + path: 'discontinued-incomes/:index/frequency', + uiSchema: incomeFrequencyPage.uiSchema, + schema: incomeFrequencyPage.schema, + }), + discontinuedIncomeDatePage: pageBuilder.itemPage({ + title: 'Discontinued income date', + path: 'discontinued-incomes/:index/date', + uiSchema: incomeDatePage.uiSchema, + schema: incomeDatePage.schema, + }), + discontinuedIncomeAmountPage: pageBuilder.itemPage({ + title: 'Discontinued income amount', + path: 'discontinued-incomes/:index/amount', + uiSchema: incomeAmountPage.uiSchema, + schema: incomeAmountPage.schema, + }), + }), +); diff --git a/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/index.js b/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/index.js new file mode 100644 index 000000000000..ad6d87889a3a --- /dev/null +++ b/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/index.js @@ -0,0 +1,6 @@ +import { discontinuedIncomePages } from './discontinuedIncomePages'; + +export default { + title: 'Discontinued incomes information', + pages: discontinuedIncomePages, +}; diff --git a/src/applications/income-and-asset-statement/config/form.js b/src/applications/income-and-asset-statement/config/form.js index 2c9ad8579b51..bfc6b8b3e30c 100644 --- a/src/applications/income-and-asset-statement/config/form.js +++ b/src/applications/income-and-asset-statement/config/form.js @@ -16,6 +16,7 @@ import assetTransfers from './chapters/07-asset-transfers'; import trusts from './chapters/08-trusts'; import annuities from './chapters/09-annuities'; import unreportedAssets from './chapters/10-unreported-assets'; +import discontinuedIncomes from './chapters/11-discontinued-incomes'; // const { } = fullSchema.properties; @@ -69,6 +70,7 @@ const formConfig = { trusts, annuities, unreportedAssets, + discontinuedIncomes, }, }; diff --git a/src/applications/income-and-asset-statement/labels.jsx b/src/applications/income-and-asset-statement/labels.jsx index 351be52b2640..eac687888f49 100644 --- a/src/applications/income-and-asset-statement/labels.jsx +++ b/src/applications/income-and-asset-statement/labels.jsx @@ -25,6 +25,12 @@ export const claimantTypeLabels = { CUSTODIAN: 'Custodian of child beneficiary', }; +export const incomeFrequencyLabels = { + RECURRING: 'Recurring', + IRREGULAR: 'Irregular', + ONE_TIME: 'One time payment', +}; + export const incomeTypeLabels = { SOCIAL_SECURITY: 'Social Security', PENSION_RETIREMENT: 'Pension or retirement income', From 8e11cf3e096b1ced326c970833ef768d290ec9d2 Mon Sep 17 00:00:00 2001 From: Todd Rizzolo Date: Mon, 2 Dec 2024 10:26:42 -0700 Subject: [PATCH 2/3] Update cypress test --- .../tests/e2e/fixtures/data/test-data.json | 11 ++++++ ...income-and-asset-statement.cypress.spec.js | 38 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/applications/income-and-asset-statement/tests/e2e/fixtures/data/test-data.json b/src/applications/income-and-asset-statement/tests/e2e/fixtures/data/test-data.json index f216b2464d8b..568f2d5735bc 100644 --- a/src/applications/income-and-asset-statement/tests/e2e/fixtures/data/test-data.json +++ b/src/applications/income-and-asset-statement/tests/e2e/fixtures/data/test-data.json @@ -112,6 +112,17 @@ "assetLocation": "Global Investments LLC, Portfolio ID #987654321" } ], + "view:isAddingDiscontinuedIncomes": true, + "discontinuedIncomes": [ + { + "recipientRelationship": "VETERAN", + "payer": "Social Security Administration", + "incomeType": "Social Security", + "incomeFrequency": "RECURRING", + "incomeLastReceivedDate": "2023-05-15", + "grossAnnualAmount": 18000.0 + } + ], "statementOfTruthSignature": "John Doe" } } diff --git a/src/applications/income-and-asset-statement/tests/e2e/income-and-asset-statement.cypress.spec.js b/src/applications/income-and-asset-statement/tests/e2e/income-and-asset-statement.cypress.spec.js index f6b73fffdba1..87e22f00de3d 100644 --- a/src/applications/income-and-asset-statement/tests/e2e/income-and-asset-statement.cypress.spec.js +++ b/src/applications/income-and-asset-statement/tests/e2e/income-and-asset-statement.cypress.spec.js @@ -26,6 +26,7 @@ let addedAssetTransferItem = false; let addedTrustItem = false; let addedAnnuityItem = false; let addedUnreportedAssetItem = false; +let addedDiscontinuedIncomeItem = false; const testConfig = createTestConfig( { @@ -375,6 +376,43 @@ const testConfig = createTestConfig( }); }); }, + 'discontinued-incomes-summary': ({ afterHook }) => { + afterHook(() => { + cy.get('@testData').then(data => { + let isAddingDiscontinuedIncomes = + data['view:isAddingDiscontinuedIncomes']; + if (addedDiscontinuedIncomeItem) { + isAddingDiscontinuedIncomes = false; + addedDiscontinuedIncomeItem = false; + } + + selectYesNoWebComponent( + 'view:isAddingDiscontinuedIncomes', + isAddingDiscontinuedIncomes, + ); + + cy.findAllByText(/^Continue/, { selector: 'button' }) + .last() + .click(); + }); + }); + }, + 'discontinued-incomes/0/amount': ({ afterHook }) => { + afterHook(() => { + cy.get('@testData').then(data => { + const { discontinuedIncomes } = data; + const { grossAnnualAmount } = discontinuedIncomes[0]; + + fillStandardTextInput('grossAnnualAmount', grossAnnualAmount); + + addedDiscontinuedIncomeItem = true; + + cy.findAllByText(/^Continue/, { selector: 'button' }) + .last() + .click(); + }); + }); + }, 'review-and-submit': ({ afterHook }) => { afterHook(() => { cy.get('@testData').then(data => { From ee73fbfe877538d508a50af82bfee75edd714694 Mon Sep 17 00:00:00 2001 From: Todd Rizzolo Date: Mon, 2 Dec 2024 14:52:53 -0700 Subject: [PATCH 3/3] Rename item page --- .../11-discontinued-incomes/discontinuedIncomePages.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/discontinuedIncomePages.js b/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/discontinuedIncomePages.js index 10f39f4ef49b..be3e8bdae359 100644 --- a/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/discontinuedIncomePages.js +++ b/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/discontinuedIncomePages.js @@ -117,7 +117,7 @@ const summaryPage = { const relationshipPage = { uiSchema: { ...arrayBuilderItemFirstPageTitleUI({ - title: 'Discontinued income', + title: 'Discontinued income relationship', nounSingular: options.nounSingular, }), recipientRelationship: radioUI({ @@ -164,9 +164,7 @@ const relationshipPage = { /** @returns {PageSchema} */ const incomePayerPage = { uiSchema: { - ...arrayBuilderItemSubsequentPageTitleUI( - 'Discontinued income relationship', - ), + ...arrayBuilderItemSubsequentPageTitleUI('Discontinued income payer'), payer: textUI({ title: 'Income payer name', hint: 'Name of business, financial institution, etc.',