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..be3e8bdae359
--- /dev/null
+++ b/src/applications/income-and-asset-statement/config/chapters/11-discontinued-incomes/discontinuedIncomePages.js
@@ -0,0 +1,304 @@
+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 && (
+
+ -
+ Income relationship:{' '}
+
+ {relationshipLabels[item.recipientRelationship]}
+
+
+ -
+ Income type:{' '}
+ {item.incomeType}
+
+ -
+ Gross annual amount:{' '}
+
+ {formatCurrency(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 relationship',
+ 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 payer'),
+ 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',
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 => {