diff --git a/src/components/HrTools/SalaryCalculator/Landing/NewSalaryCalculationLanding/LandingSalaryCalculations.graphql b/src/components/HrTools/SalaryCalculator/Landing/NewSalaryCalculationLanding/LandingSalaryCalculations.graphql index 2c0ba6af8..2db0b4e77 100644 --- a/src/components/HrTools/SalaryCalculator/Landing/NewSalaryCalculationLanding/LandingSalaryCalculations.graphql +++ b/src/components/HrTools/SalaryCalculator/Landing/NewSalaryCalculationLanding/LandingSalaryCalculations.graphql @@ -4,6 +4,7 @@ query LandingSalaryCalculations { ) { id status + personNumber salary spouseSalary mhaAmount @@ -11,6 +12,12 @@ query LandingSalaryCalculations { submittedAt changesRequestedAt feedback + calculations { + requestedGross + } + spouseCalculations { + requestedGross + } } inProgressCalculation: latestSalaryRequest(status: [IN_PROGRESS]) { id diff --git a/src/components/HrTools/SalaryCalculator/Landing/NewSalaryCalculationLanding/LandingTestWrapper.tsx b/src/components/HrTools/SalaryCalculator/Landing/NewSalaryCalculationLanding/LandingTestWrapper.tsx index 7357ecc20..b4a6e5163 100644 --- a/src/components/HrTools/SalaryCalculator/Landing/NewSalaryCalculationLanding/LandingTestWrapper.tsx +++ b/src/components/HrTools/SalaryCalculator/Landing/NewSalaryCalculationLanding/LandingTestWrapper.tsx @@ -26,6 +26,7 @@ export interface LandingTestWrapperProps { hasApprovedCalculation?: boolean; hasSpouseApprovedCalculation?: boolean; hasLatestCalculation?: boolean; + hasSpouseLatestCalculation?: boolean; salaryRequestEligible?: boolean; } @@ -36,6 +37,7 @@ export const LandingTestWrapper: React.FC = ({ hasApprovedCalculation = false, hasSpouseApprovedCalculation = false, hasLatestCalculation = false, + hasSpouseLatestCalculation = false, salaryRequestEligible = true, }) => ( @@ -116,9 +118,16 @@ export const LandingTestWrapper: React.FC = ({ ? { id: 'pending-calc-1', status: SalaryRequestStatusEnum.Pending, + personNumber: hasSpouseLatestCalculation + ? '000123457' + : '000123456', + salary: 52000, + spouseSalary: 51000, submittedAt: '2025-01-16T10:00:00Z', changesRequestedAt: null, feedback: null, + calculations: { requestedGross: 69714.29 }, + spouseCalculations: { requestedGross: 62000 }, } : null, }, diff --git a/src/components/HrTools/SalaryCalculator/Landing/PendingSalaryCalculationLanding/PendingRequestCard.test.tsx b/src/components/HrTools/SalaryCalculator/Landing/PendingSalaryCalculationLanding/PendingRequestCard.test.tsx index 78381290e..315b45b90 100644 --- a/src/components/HrTools/SalaryCalculator/Landing/PendingSalaryCalculationLanding/PendingRequestCard.test.tsx +++ b/src/components/HrTools/SalaryCalculator/Landing/PendingSalaryCalculationLanding/PendingRequestCard.test.tsx @@ -1,10 +1,13 @@ import React from 'react'; -import { render } from '@testing-library/react'; -import { LandingTestWrapper } from '../NewSalaryCalculationLanding/LandingTestWrapper'; +import { render, waitFor } from '@testing-library/react'; +import { + LandingTestWrapper, + LandingTestWrapperProps, +} from '../NewSalaryCalculationLanding/LandingTestWrapper'; import { PendingRequestCard } from './PendingRequestCard'; -const TestComponent: React.FC = () => ( - +const TestComponent: React.FC = (props) => ( + ); @@ -19,6 +22,57 @@ describe('PendingRequestCard', () => { ).toBeInTheDocument(); }); + it('renders the requested gross salary, not the current gross salary', async () => { + const { getByTestId } = render(); + + await waitFor(() => + expect(getByTestId('gross-salary-amount')).toHaveTextContent( + '$69,714.29', + ), + ); + }); + + it("renders the spouse's requested gross salary alongside the user's", async () => { + const { getByTestId, getByText } = render(); + + await waitFor(() => + expect(getByTestId('spouse-gross-salary-amount')).toHaveTextContent( + '$62,000.00', + ), + ); + expect(getByText('John')).toBeInTheDocument(); + expect(getByText('Jane')).toBeInTheDocument(); + }); + + it('swaps the amounts when the spouse created the request', async () => { + const { getByTestId } = render( + , + ); + + await waitFor(() => + expect(getByTestId('gross-salary-amount')).toHaveTextContent( + '$62,000.00', + ), + ); + expect(getByTestId('spouse-gross-salary-amount')).toHaveTextContent( + '$69,714.29', + ); + }); + + it('renders a single amount and no names when there is no spouse', async () => { + const { getByTestId, queryByTestId, queryByText } = render( + , + ); + + await waitFor(() => + expect(getByTestId('gross-salary-amount')).toHaveTextContent( + '$69,714.29', + ), + ); + expect(queryByTestId('spouse-gross-salary-amount')).not.toBeInTheDocument(); + expect(queryByText('John')).not.toBeInTheDocument(); + }); + it('renders print link with correct href', async () => { const { findByRole } = render(); diff --git a/src/components/HrTools/SalaryCalculator/Landing/PendingSalaryCalculationLanding/PendingRequestCard.tsx b/src/components/HrTools/SalaryCalculator/Landing/PendingSalaryCalculationLanding/PendingRequestCard.tsx index e593a0b70..1f7621377 100644 --- a/src/components/HrTools/SalaryCalculator/Landing/PendingSalaryCalculationLanding/PendingRequestCard.tsx +++ b/src/components/HrTools/SalaryCalculator/Landing/PendingSalaryCalculationLanding/PendingRequestCard.tsx @@ -6,6 +6,7 @@ import { Card, CardContent, CardHeader, + Grid, IconButton, Typography, } from '@mui/material'; @@ -21,16 +22,19 @@ import { PendingRequestTimeline } from './components/PendingRequestTimeline'; export const PendingRequestCard: React.FC = () => { const { t } = useTranslation(); const accountListId = useAccountListId(); - const { - calculation, - requestedOn, - processedOn, - feedback, - salaryData: { currentGrossSalary }, - } = useLandingData(); + const { calculation, self, spouse, requestedOn, processedOn, feedback } = + useLandingData(); const locale = useLocale(); + // The gross request is the requested salary plus SECA and 403(b) contributions + const requestedGross = calculation?.calculations?.requestedGross ?? 0; + const spouseRequestedGross = calculation?.spouseCalculations?.requestedGross; + const hasSpouse = !!spouse && spouseRequestedGross !== undefined; + + const formatGross = (amount: number) => + currencyFormat(amount, 'USD', locale, { showTrailingZeros: true }); + return ( { > {t('Gross Salary Requested')?.toUpperCase()} - - {currencyFormat(currentGrossSalary, 'USD', locale, { - showTrailingZeros: true, - })} - + + + {hasSpouse && ( + + {self?.staffInfo.preferredName} + + )} + + {formatGross(requestedGross)} + + + {hasSpouse && ( + + + {spouse.staffInfo.preferredName} + + + {formatGross(spouseRequestedGross)} + + + )} + ({ id: '1', status, + personNumber: '000123456', mhaAmount: null, spouseMhaAmount: null, salary: null, @@ -22,6 +23,8 @@ const createCalculation = ( submittedAt: '2025-01-15T10:00:00Z', changesRequestedAt: null, feedback, + calculations: { requestedGross: 0 }, + spouseCalculations: null, }); interface TestComponentProps { diff --git a/src/components/HrTools/SalaryCalculator/Landing/useLandingData.ts b/src/components/HrTools/SalaryCalculator/Landing/useLandingData.ts index 0ea4b9708..790c4a28e 100644 --- a/src/components/HrTools/SalaryCalculator/Landing/useLandingData.ts +++ b/src/components/HrTools/SalaryCalculator/Landing/useLandingData.ts @@ -96,6 +96,13 @@ export const useLandingData = (): LandingData => { }; }, [hcmData]); + // The latest calculation may have been created by the spouse, so orient it to the user's + // perspective before exposing its amounts + const calculation = useMemo( + () => orientSalaryRequest(latestCalculation, self?.staffInfo.personNumber), + [latestCalculation, self], + ); + const staffAccountId = useMemo( () => staffAccountIdData?.user?.staffAccountId ?? null, [staffAccountIdData], @@ -264,7 +271,7 @@ export const useLandingData = (): LandingData => { calculationLoading || accountBalanceLoading || staffAccountIdLoading, - calculation: latestCalculation, + calculation, requestedOn, processedOn, feedback,