Skip to content

Commit

Permalink
Merge pull request #23 from JosephGasiorekUSDS/jgasiorek-ffs-918
Browse files Browse the repository at this point in the history
FFS-918: Ledger Review Screen
  • Loading branch information
JosephGasiorekUSDS authored Jun 14, 2024
2 parents b9c23bc + ad573be commit d8ab461
Show file tree
Hide file tree
Showing 16 changed files with 439 additions and 64 deletions.
41 changes: 41 additions & 0 deletions app/components/ExpenseList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Card, CardBody, CardGroup, CardHeader, GridContainer } from "@trussworks/react-uswds";
import { useTranslation } from "@/app/i18n/client";
import { useAppSelector } from "@/lib/hooks";
import { ExpenseItem, selectExpenseItems, selectExpenseTotal } from "@/lib/features/ledger/expenses/expensesSlice";
import ExpenseListItem from "./ExpenseListItem";

interface ExpenseListProps {
header: string
}

export default function ExpenseList({header}: ExpenseListProps) {
const { t } = useTranslation('en')
const items = useAppSelector(state => selectExpenseItems(state))
const expenseTotal = useAppSelector(state => selectExpenseTotal(state))

const expenseItemElements = items.map((item: ExpenseItem, idx: number) => {
return <ExpenseListItem key={idx} item={item} index={idx} />
})

function getTotal() {
if (expenseTotal > 0) {
return (t('expenses_summary_total', {amount: expenseTotal}))
}

return <></>
}

return (
<CardGroup>
<Card className="grid-col-12 margin-top-4">
<CardHeader><b>{header}</b></CardHeader>
<CardBody>
<GridContainer>
{expenseItemElements}
</GridContainer>
{ getTotal() }
</CardBody>
</Card>
</CardGroup>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface ItemProps {
item: NewType
index: number
}
export default function Item({ item, index }: ItemProps) {
export default function ExpenseListItem({ item, index }: ItemProps) {
const ref = useRef(null)
const { t } = useTranslation('en')
const dispatch = useAppDispatch()
Expand Down
43 changes: 43 additions & 0 deletions app/components/IncomeList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use client'

import { IncomeItem, selectIncomeItems, selectIncomeTotal } from "@/lib/features/ledger/income/incomeSlice"
import { useAppSelector } from "@/lib/hooks"
import IncomeListItem from "./IncomeListItem"
import { Card, CardBody, CardGroup, CardHeader, GridContainer } from "@trussworks/react-uswds"
import { useTranslation } from "@/app/i18n/client"

interface Props {
dayCount: number
header: string
}

export default function IncomeList({dayCount, header}: Props) {
const { t } = useTranslation('en')
const items = useAppSelector(state => selectIncomeItems(state))
const incomeTotal = useAppSelector(state => selectIncomeTotal(state))
const incomeItemElements = items.map((item: IncomeItem, idx: number) => {
return <IncomeListItem key={idx} item={item} index={idx} />
})

function getTotal() {
if (incomeTotal > 0) {
return (t('list_income_total', {day_count: dayCount, amount: incomeTotal}))
}

return <></>
}

return (
<CardGroup>
<Card className="grid-col-12 margin-top-4">
<CardHeader><b>{header}</b></CardHeader>
<CardBody>
<GridContainer>
{incomeItemElements}
</GridContainer>
{getTotal()}
</CardBody>
</Card>
</CardGroup>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface ItemProps {
item: IncomeItem
index: number
}
export default function Item({ item, index }: ItemProps) {
export default function IncomeListItem({ item, index }: ItemProps) {
const ref = useRef(null)
const { t } = useTranslation('en')
const dispatch = useAppDispatch()
Expand Down
18 changes: 17 additions & 1 deletion app/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,21 @@
"intro_how_do_i_know_list_have_expenses": "They have business eexpenses that aren't paid back by anyone they work for.",
"intro_how_do_i_know_list_they_receive": "They receive tax form 1099-MISC from a company or individual at the end of the year.",
"intro_how_do_i_know_list_own": "They own or run their own business.",
"intro_how_do_i_know_list_benefits": "They do not get employment benefits or tax contributions from the individual or company they work for."
"intro_how_do_i_know_list_benefits": "They do not get employment benefits or tax contributions from the individual or company they work for.",
"review_title": "Income and expenses summary",
"review_header": "Total calculated self employment income",
"review_snap_income": "SNAP Income: ${{amount}}",
"review_medicaid_income": "Medicaid Income: ${{amount}}",
"review_medicaid_only_income": "Total calculated self employment income for Medicaid: ${{amount}}",
"review_snap_only_income": "Total calculated self cmployment income for SNAP: ${{amount}}",
"review_ledger_sent_medicaid_snap": "This is the ledger that will be sent to your Medicaid and SNAP applications",
"review_ledger_sent_medicaid_only": "This is the ledger that will be sent to your Medicaid applicaton",
"review_ledger_sent_snap_only": "This is the ledger that will be sent to your SNAP application",
"review_download_copy": "Download a copy of your ledger and keep it",
"review_legally_sign": "Next you'll legally sign and submit this statement",
"review_income_header": "Money you received (last {{days}} days)",
"review_expenses_header": "Your expenses (last {{days}} days)",
"review_snap_expenses_header": "Your expenses",
"review_snap_expenses_body": "SNAP Standard expense deduction ({{deduction}}% of your income): ${{amount}}",
"review_continue_button": "Continue"
}
32 changes: 2 additions & 30 deletions app/ledger/expense/list/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,17 @@ import "@trussworks/react-uswds/lib/uswds.css"
import "@trussworks/react-uswds/lib/index.css"
import { Header, Title, Button, ButtonGroup, CardGroup, ModalToggleButton, Modal, ModalHeading, ModalFooter, Card, CardBody, CardHeader, Grid, GridContainer, Label, TextInput, ModalRef } from '@trussworks/react-uswds'
import { useTranslation } from '../../../i18n/client'
import { useAppSelector, useAppDispatch } from "@/lib/hooks"
import { useRouter } from "next/navigation"
import { ExpenseItem, selectExpenseItems } from "@/lib/features/ledger/expenses/expensesSlice"
import Item from "./item"
import ExpenseList from "@/app/components/ExpenseList"

export default function Page() {
const { t } = useTranslation('en')
const router = useRouter()
const items = useAppSelector(state => selectExpenseItems(state))

const expenseItemElements = items.map((item: ExpenseItem, idx: number) => {
return <Item key={idx} item={item} index={idx} />
})

console.log('items' ,items)

function addItemClicked() {
router.push("/ledger/expense/add")
}

function getTotal() {
let total = items.reduce((t, item) => t + item.amount, 0)

if (total > 0) {
return (t('expenses_summary_total', {amount: total}))
}

return <></>
}

return (
<div>
Expand All @@ -49,17 +31,7 @@ export default function Page() {
<main className="usa-layout-docs">
<h3>{t('expenses_summary_header')}</h3>
<span className="usa-hint">{t('expenses_summary_subheader')}</span>
<CardGroup>
<Card className="grid-col-12 margin-top-4">
<CardHeader><b>{t('expenses_summary_list_header')}</b></CardHeader>
<CardBody>
<GridContainer>
{expenseItemElements}
</GridContainer>
{ getTotal() }
</CardBody>
</Card>
</CardGroup>
<ExpenseList header={t('expenses_summary_list_header')} />
<ButtonGroup type="default">
<Button type="button" onClick={addItemClicked} data-testid="add_another_button">{t('expenses_summary_add_button')}</Button>
<Button type="button" data-testid="continue_button">{t('expenses_summary_review_button')}</Button>
Expand Down
2 changes: 1 addition & 1 deletion app/ledger/expense/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { vi } from 'vitest'
import { EnhancedStore } from '@reduxjs/toolkit'
import mockRouter from 'next-router-mock'

describe('List Income in Ledger Page', async () => {
describe('Expense Landing Screen', async () => {
let store: EnhancedStore
beforeEach(() => {
vi.mock('next/navigation', () => require('next-router-mock'))
Expand Down
32 changes: 3 additions & 29 deletions app/ledger/income/list/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,21 @@

import "@trussworks/react-uswds/lib/uswds.css"
import "@trussworks/react-uswds/lib/index.css"
import { Header, Title, Button, ButtonGroup, CardGroup, ModalToggleButton, Modal, ModalHeading, ModalFooter, Card, CardBody, CardHeader, Grid, GridContainer, Label, TextInput, ModalRef } from '@trussworks/react-uswds'
import { Header, Title, Button, ButtonGroup, Grid, GridContainer } from '@trussworks/react-uswds'
import { useTranslation } from '../../../i18n/client'
import { useAppSelector, useAppDispatch } from "@/lib/hooks"
import { removeIncome, IncomeItem, selectIcomeItems } from "@/lib/features/ledger/income/incomeSlice"
import { useRouter } from "next/navigation"
import { useRef } from "react"
import Item from './item'
import IncomeList from "@/app/components/IncomeList"

const DAY_COUNT = 30

export default function Page() {
const { t } = useTranslation('en')
const router = useRouter()
const items = useAppSelector(state => selectIcomeItems(state))
const dispatch = useAppDispatch()
const deleteRef = useRef<ModalRef[]>([])

const incomeItemElements = items.map((item: IncomeItem, idx: number) => {
return <Item key={idx} item={item} index={idx} />
})

function addItemClicked() {
router.push("/ledger/income/add")
}

function getTotal() {
let total = items.reduce((t, item) => t + item.amount, 0)
return (t('list_income_total', {day_count: DAY_COUNT, amount: total}))

}

return (
<div>
<Header basic={true}>
Expand All @@ -48,17 +32,7 @@ export default function Page() {
<main className="usa-layout-docs">
<h3>{t('list_income_header', {day_count: DAY_COUNT})}</h3>
<span className="usa-hint">{t('list_income_subheader')}</span>
<CardGroup>
<Card className="grid-col-12 margin-top-4">
{incomeItemElements.length > 0 && (<CardHeader><b>{t('list_income_list_header')}</b></CardHeader>)}
<CardBody>
<GridContainer>
{incomeItemElements}
</GridContainer>
{getTotal()}
</CardBody>
</Card>
</CardGroup>
<IncomeList dayCount={DAY_COUNT} header={t('list_income_list_header')} />
<ButtonGroup type="default">
<Button type="button" onClick={addItemClicked} data-testid="add_another_button">{t('list_income_add_button')}</Button>
<Button type="button" data-testid="done_button">{t('list_income_done_button')}</Button>
Expand Down
121 changes: 121 additions & 0 deletions app/ledger/review/LedgerReviewHeader.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { afterEach, beforeEach, describe, expect, it, test } from 'vitest'
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'
import { Provider } from 'react-redux'
import LedgerReviewHeader from './LedgerReviewHeader'
import { makeStore } from '@/lib/store'
import { EnhancedStore } from '@reduxjs/toolkit'
import { BenefitsState } from '@/lib/features/benefits/benefitsSlice'

describe('Ledger Review Header', async () => {
const SNAP_INCOME = 350.00
const MEDICAID_INCOME = 412.00

afterEach(cleanup)

describe('Medicaid and Snap', () => {
let benefits: BenefitsState
beforeEach(() => {
benefits = {
standardDeduction: true,
deductionAmount: 50,
medicaid: true,
snap: true,
}

const store: EnhancedStore = makeStore()
render (<Provider store={store}><LedgerReviewHeader benefits={benefits} snapIncomeTotal={SNAP_INCOME} medicaidIncomeTotal={MEDICAID_INCOME} /></Provider>)
})

it('Displays SNAP and Medicaid header', () => {
expect(screen.getByTestId('review-header')).toBeDefined()
})

it('Displays SNAP Income', () => {
expect(screen.getByText(`SNAP Income: $${SNAP_INCOME}`)).toBeDefined()
})

it('Displays Medicaid Income', () => {
expect(screen.getByText(`Medicaid Income: $${MEDICAID_INCOME}`)).toBeDefined()
})

it('Does not display Medicaid only header', () => {
expect(screen.queryByTestId("medicaid-only-header")).toBeNull()
})

it('Does not display SNAP only header', () => {
expect(screen.queryByTestId("snap-only-header")).toBeNull()
})
})

describe('Medicaid Only', () => {
let benefits: BenefitsState
beforeEach(() => {
benefits = {
medicaid: true,
snap: false,
}

const store: EnhancedStore = makeStore()
render (<Provider store={store}><LedgerReviewHeader benefits={benefits} snapIncomeTotal={SNAP_INCOME} medicaidIncomeTotal={MEDICAID_INCOME} /></Provider>)
})

it('Displays Medicaid only header', () => {
expect(screen.getByTestId('medicaid-only-header')).toBeDefined()
})

it('Does not display SNAP and Medicaid header', () => {
expect(screen.queryByTestId('review-header')).toBeNull()
})

it('Does not display SNAP Income', () => {
const header = screen.getByTestId('medicaid-only-header')
expect(header.firstChild?.textContent?.indexOf(`${SNAP_INCOME}`)).toEqual(-1)
})

it('Displays Medicaid Income', () => {
const header = screen.getByTestId('medicaid-only-header')
expect(header.firstChild?.textContent?.indexOf(`${MEDICAID_INCOME}`)).toBeGreaterThanOrEqual(0)
})

it('Does not display SNAP only header', () => {
expect(screen.queryByTestId("snap-only-header")).toBeNull()
})
})

describe('SNAP Only', () => {
let benefits: BenefitsState
beforeEach(() => {
benefits = {
standardDeduction: true,
deductionAmount: 50,
medicaid: false,
snap: true,
}

const store: EnhancedStore = makeStore()
render (<Provider store={store}><LedgerReviewHeader benefits={benefits} snapIncomeTotal={SNAP_INCOME} medicaidIncomeTotal={MEDICAID_INCOME} /></Provider>)
})

it('Does not display Medicaid only header', () => {
expect(screen.queryByTestId('medicaid-only-header')).toBeNull()
})

it('Does not display SNAP and Medicaid header', () => {
expect(screen.queryByTestId('review-header')).toBeNull()
})

it('Does display SNAP Income', () => {
const header = screen.getByTestId('snap-only-header')
expect(header.firstChild?.textContent?.indexOf(`${SNAP_INCOME}`)).toBeGreaterThanOrEqual(0)
})

it('Does not display Medicaid Income', () => {
const header = screen.getByTestId('snap-only-header')
expect(header.firstChild?.textContent?.indexOf(`${MEDICAID_INCOME}`)).toEqual(-1)
})

it('Does display SNAP only header', () => {
expect(screen.queryByTestId("snap-only-header")).toBeDefined()
})
})
})
Loading

0 comments on commit d8ab461

Please sign in to comment.