From 4d875b26e47751104d146cee568f838cdeee8955 Mon Sep 17 00:00:00 2001 From: Caleb Cox Date: Wed, 13 May 2026 12:04:07 -0500 Subject: [PATCH 1/7] Use approval reason from server --- .../AdditionalSalaryRequest.graphql | 1 + .../RequestPage/Helper/CapSubContent.test.tsx | 11 ++-- .../RequestPage/Helper/CapSubContent.tsx | 10 ++-- .../Helper/getCapOverrides.test.ts | 34 ++++++------ .../RequestPage/Helper/getCapOverrides.ts | 54 +++++++++++++------ .../RequestPage/RequestPage.test.tsx | 26 ++++----- .../RequestPage/RequestPage.tsx | 11 ++-- .../Shared/AdditionalSalaryRequestContext.tsx | 5 +- .../SalaryCalculator/Receipt/Receipt.test.tsx | 38 ++++++++++--- .../SalaryCalculator/Receipt/Receipt.tsx | 17 ++++-- .../ApprovalProcessCard.test.tsx | 19 ++++--- .../ApprovalProcessCard.tsx | 9 ++-- .../RequestSummaryCard.test.tsx | 54 ++++++++++++++----- .../RequestSummaryCard/RequestSummaryCard.tsx | 19 +++++-- .../RequestedSalaryCard.test.tsx | 3 ++ .../SalaryCalculation/useCaps.ts | 29 +++++----- .../useSosaBlockOverCap.test.tsx | 2 + .../SalaryCalculation/useSosaBlockOverCap.ts | 8 +-- .../SalaryCalculation.graphql | 1 + .../SalaryCalculatorTestWrapper.tsx | 1 + .../useSubmitDialogContent.test.tsx | 12 +++-- .../StepNavigation/useSubmitDialogContent.ts | 20 +++++-- 22 files changed, 248 insertions(+), 136 deletions(-) diff --git a/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.graphql b/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.graphql index 75046686f1..79bde211f8 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.graphql +++ b/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.graphql @@ -37,6 +37,7 @@ fragment AdditionalSalaryRequestDetailsFields on AdditionalSalaryRequest { approver approvalTimeframe } + progressiveApprovalTierReason calculations { currentSalaryCap combinedCap diff --git a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.test.tsx index b1a8bb4ca0..78f0a8407a 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.test.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { ThemeProvider } from '@mui/material/styles'; import { render } from '@testing-library/react'; import { FormikProvider, useFormik } from 'formik'; +import { ProgressiveApprovalTierReasonEnum } from 'pages/api/graphql-rest.page.generated'; import theme from 'src/theme'; import { CompleteFormValues } from '../../AdditionalSalaryRequest'; import { useAdditionalSalaryRequest } from '../../Shared/AdditionalSalaryRequestContext'; @@ -44,15 +45,16 @@ describe('CapSubContent', () => { jest.clearAllMocks(); }); - it('renders Progressive Approvals messaging when hasBoardCapException is false', () => { + it('renders Progressive Approvals messaging when reason is not board cap exception', () => { mockUseAdditionalSalaryRequest.mockReturnValue({ - hasBoardCapException: false, requestData: { latestAdditionalSalaryRequest: { progressiveApprovalTier: { approver: 'Division Head', approvalTimeframe: '1-2 weeks', }, + progressiveApprovalTierReason: + ProgressiveApprovalTierReasonEnum.OverUserCap, }, }, } as unknown as ReturnType); @@ -67,12 +69,13 @@ describe('CapSubContent', () => { ).not.toBeInTheDocument(); }); - it('renders nothing when hasBoardCapException is true (message is carried by getCapOverrides)', () => { + it('renders nothing when reason is board cap exception (message is carried by getCapOverrides)', () => { mockUseAdditionalSalaryRequest.mockReturnValue({ - hasBoardCapException: true, requestData: { latestAdditionalSalaryRequest: { progressiveApprovalTier: null, + progressiveApprovalTierReason: + ProgressiveApprovalTierReasonEnum.BoardCapException, }, }, } as unknown as ReturnType); diff --git a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.tsx b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.tsx index 60e2d75f20..e523a8434a 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.tsx @@ -4,6 +4,7 @@ import { Box, List, ListItemText } from '@mui/material'; import { useFormikContext } from 'formik'; import { Trans, useTranslation } from 'react-i18next'; import { StyledListItem } from 'src/components/HrTools/SavingsFundTransfer/styledComponents/StyledListItem'; +import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; import { useLocale } from 'src/hooks/useLocale'; import { currencyFormat } from 'src/lib/intlFormat'; import theme from 'src/theme'; @@ -14,13 +15,14 @@ export const CapSubContent: React.FC = () => { const { t } = useTranslation(); const locale = useLocale(); const currency = 'USD'; - const { requestData, hasBoardCapException } = useAdditionalSalaryRequest(); - const progressiveApprovalTier = - requestData?.latestAdditionalSalaryRequest?.progressiveApprovalTier; + const { requestData } = useAdditionalSalaryRequest(); + const latestRequest = requestData?.latestAdditionalSalaryRequest; + const progressiveApprovalTier = latestRequest?.progressiveApprovalTier; + const reason = latestRequest?.progressiveApprovalTierReason; const { values } = useFormikContext(); - if (hasBoardCapException) { + if (reason === ProgressiveApprovalTierReasonEnum.BoardCapException) { return null; } diff --git a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.test.ts b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.test.ts index 175221cf6b..78c4ff3bee 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.test.ts +++ b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.test.ts @@ -1,3 +1,4 @@ +import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; import { getCapOverrides } from './getCapOverrides'; const t = ((key: string) => key) as unknown as Parameters< @@ -9,8 +10,7 @@ describe('getCapOverrides', () => { const result = getCapOverrides( { splitAsr: false, - additionalApproval: false, - hasBoardCapException: false, + reason: null, }, t, ); @@ -22,20 +22,18 @@ describe('getCapOverrides', () => { const result = getCapOverrides( { splitAsr: true, - additionalApproval: false, - hasBoardCapException: false, + reason: null, }, t, ); expect(result.title).toMatch(/exceeds your remaining allowable salary/); }); - it('returns Progressive Approvals messaging when additionalApproval without board exception', () => { + it('returns Progressive Approvals messaging when over user cap', () => { const result = getCapOverrides( { splitAsr: false, - additionalApproval: true, - hasBoardCapException: false, + reason: ProgressiveApprovalTierReasonEnum.OverUserCap, }, t, ); @@ -43,32 +41,32 @@ describe('getCapOverrides', () => { expect(result.content).toMatch(/exceed your Maximum Allowable Salary/); }); - it('returns board-approval messaging when approval required with board exception', () => { + it('returns combined-cap messaging when over combined cap', () => { const result = getCapOverrides( { splitAsr: false, - additionalApproval: true, - hasBoardCapException: true, + reason: ProgressiveApprovalTierReasonEnum.OverCombinedCap, }, t, ); - expect(result.title).toMatch(/Board approval/); + expect(result.title).toMatch(/requires additional approval/); expect(result.content).toMatch( - /You have a Board approved Maximum Allowable Salary/, + /combined Total Requested Salary to exceed your combined Maximum Allowable Salary/, ); - expect(result.content).toMatch(/Additional Salary Request exceeds/); }); - it('board exception does not apply when no approval required', () => { + it('returns board-approval messaging with board cap exception', () => { const result = getCapOverrides( { splitAsr: false, - additionalApproval: false, - hasBoardCapException: true, + reason: ProgressiveApprovalTierReasonEnum.BoardCapException, }, t, ); - expect(result.title).toBeUndefined(); - expect(result.content).toBeUndefined(); + expect(result.title).toMatch(/Board approval/); + expect(result.content).toMatch( + /You have a Board approved Maximum Allowable Salary/, + ); + expect(result.content).toMatch(/Additional Salary Request exceeds/); }); }); diff --git a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.ts b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.ts index b2855c5b7f..4747081302 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.ts +++ b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.ts @@ -1,13 +1,13 @@ import { TFunction } from 'i18next'; +import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; interface CapOverridesOptions { splitAsr: boolean; - additionalApproval: boolean; - hasBoardCapException: boolean; + reason: ProgressiveApprovalTierReasonEnum | null | undefined; } export const getCapOverrides = ( - { splitAsr, additionalApproval, hasBoardCapException }: CapOverridesOptions, + { splitAsr, reason }: CapOverridesOptions, t: TFunction, ) => { if (splitAsr) { @@ -19,27 +19,49 @@ export const getCapOverrides = ( }; } - if (additionalApproval) { - if (hasBoardCapException) { - return { - title: t( - 'Your request requires Board approval. Please review the information below to continue.', - ), - content: t( - "You have a Board approved Maximum Allowable Salary (CAP) and your Additional Salary Request exceeds that amount. As a result we need to get their approval for this request. We'll forward your request to them and get back to you with their decision.", - ), - }; - } + if (!reason) { + return { title: undefined, content: undefined }; + } + + if (reason === ProgressiveApprovalTierReasonEnum.BoardCapException) { + return { + title: t( + 'Your request requires Board approval. Please review the information below to continue.', + ), + content: t( + "You have a Board approved Maximum Allowable Salary (CAP) and your Additional Salary Request exceeds that amount. As a result we need to get their approval for this request. We'll forward your request to them and get back to you with their decision.", + ), + }; + } + if (reason === ProgressiveApprovalTierReasonEnum.OverlappingRequests) { return { title: t( 'Your request requires additional approval. Please fill in the information below to continue.', ), content: t( - 'Your request causes your Total Requested Salary to exceed your Maximum Allowable Salary.', + 'Your spouse has a pending Additional Salary Request or Salary Request, so this request needs additional approval.', + ), + }; + } + + const title = t( + 'Your request requires additional approval. Please fill in the information below to continue.', + ); + + if (reason === ProgressiveApprovalTierReasonEnum.OverCombinedCap) { + return { + title, + content: t( + 'Your request causes your combined Total Requested Salary to exceed your combined Maximum Allowable Salary.', ), }; } - return { title: undefined, content: undefined }; + return { + title, + content: t( + 'Your request causes your Total Requested Salary to exceed your Maximum Allowable Salary.', + ), + }; }; diff --git a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.test.tsx index 04d564eae8..86968800e2 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.test.tsx @@ -10,6 +10,7 @@ import { GqlMockedProvider } from '__tests__/util/graphqlMocking'; import { AsrStatusEnum, ElectionType403bEnum, + ProgressiveApprovalTierReasonEnum, } from 'src/graphql/types.generated'; import i18n from 'src/lib/i18n'; import { amount, phoneNumber } from 'src/lib/yupHelpers'; @@ -408,10 +409,10 @@ describe('RequestPage', () => { pageType: PageEnum.New, requestData: { latestAdditionalSalaryRequest: { - calculations: { - currentSalaryCap: 50, - }, + calculations: {}, progressiveApprovalTier: { id: 'tier-1' }, + progressiveApprovalTierReason: + ProgressiveApprovalTierReasonEnum.OverUserCap, }, }, } as unknown as ReturnType); @@ -452,24 +453,11 @@ describe('RequestPage', () => { currentStep: AdditionalSalaryRequestSectionEnum.CompleteForm, pageType: PageEnum.New, spouse: { - currentSalary: { grossSalaryAmount: 40000 }, staffInfo: { preferredName: 'Jane', lastName: 'Doe', }, }, - requestData: { - latestAdditionalSalaryRequest: { - calculations: { - currentSalaryCap: 500, - combinedCap: 100000, - }, - spouseCalculations: { - currentSalaryCap: 50000, - pendingAsrAmount: 100, - }, - }, - }, } as unknown as ReturnType); const validFormValues: CompleteFormValues = { @@ -526,6 +514,8 @@ describe('RequestPage', () => { pendingAsrAmount: 600, }, progressiveApprovalTier: { id: 'tier-1' }, + progressiveApprovalTierReason: + ProgressiveApprovalTierReasonEnum.OverUserCap, }, }, } as unknown as ReturnType); @@ -718,7 +708,6 @@ describe('RequestPage', () => { ...defaultMockContextValue, currentIndex: mockSteps.length - 2, currentStep: AdditionalSalaryRequestSectionEnum.CompleteForm, - hasBoardCapException: true, requestData: { latestAdditionalSalaryRequest: { id: 'asr-1', @@ -730,6 +719,8 @@ describe('RequestPage', () => { pendingAsrAmount: 0, }, progressiveApprovalTier: { id: 'tier-1' }, + progressiveApprovalTierReason: + ProgressiveApprovalTierReasonEnum.BoardCapException, }, }, }; @@ -792,6 +783,7 @@ describe('RequestPage', () => { currentSalaryCap: 100000, }, progressiveApprovalTier: null, + progressiveApprovalTierReason: null, }, }, } as unknown as ReturnType); diff --git a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.tsx b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.tsx index c860707020..aa34e42485 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.tsx @@ -50,9 +50,11 @@ const MainContent: React.FC = () => { spouse, isSpouse, setIsNewAsr, - hasBoardCapException, } = useAdditionalSalaryRequest(); + const latestRequest = requestData?.latestAdditionalSalaryRequest; + const reason = latestRequest?.progressiveApprovalTierReason ?? null; + const [createRequest, { loading: creatingRequest }] = useCreateAdditionalSalaryRequestMutation(); @@ -60,7 +62,6 @@ const MainContent: React.FC = () => { useFormikContext(); const handleContinue = async () => { - const latestRequest = requestData?.latestAdditionalSalaryRequest; if ( latestRequest === null || latestRequest?.status === AsrStatusEnum.ApprovedAndPaid @@ -104,11 +105,7 @@ const MainContent: React.FC = () => { const isFormPage = !isFirstFormPage && !reviewPage; const { title: overrideTitle, content: overrideContent } = getCapOverrides( - { - splitAsr: !!splitAsr, - additionalApproval, - hasBoardCapException, - }, + { splitAsr: !!splitAsr, reason }, t, ); diff --git a/src/components/HrTools/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx b/src/components/HrTools/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx index 9fef2bc182..54060f6046 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx @@ -17,6 +17,7 @@ import { import { AdditionalSalaryRequestCalculations, AsrStatusEnum, + ProgressiveApprovalTierReasonEnum, } from 'src/graphql/types.generated'; import { useStepList } from 'src/hooks/useStepList'; import { useTrackMutation } from 'src/hooks/useTrackMutation'; @@ -255,7 +256,9 @@ export const AdditionalSalaryRequestProvider: React.FC = ({ : spousePerson : undefined; const hasBoardCapException = - user?.exceptionSalaryCap?.boardCapException ?? false; + requestData?.latestAdditionalSalaryRequest + ?.progressiveApprovalTierReason === + ProgressiveApprovalTierReasonEnum.BoardCapException; const salaryInfo = salaryInfoData?.salaryInfo; const isInternational = user?.staffInfo?.isInternational ?? false; diff --git a/src/components/HrTools/SalaryCalculator/Receipt/Receipt.test.tsx b/src/components/HrTools/SalaryCalculator/Receipt/Receipt.test.tsx index d6b6fb4314..c1dae7ee49 100644 --- a/src/components/HrTools/SalaryCalculator/Receipt/Receipt.test.tsx +++ b/src/components/HrTools/SalaryCalculator/Receipt/Receipt.test.tsx @@ -1,5 +1,6 @@ import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; import { SalaryCalculatorTestWrapper, SalaryCalculatorTestWrapperProps, @@ -14,13 +15,14 @@ const TestComponent: React.FC = (props) => ( describe('Receipt step', () => { describe('board cap exception', () => { - const hcmMock = { exceptionSalaryCap: { boardCapException: true } }; - - it('should show approval info when require requires approval', async () => { + it('should show approval info when request requires approval', async () => { const { getByTestId } = render( , ); @@ -35,16 +37,36 @@ We'll forward your request to them and get back to you with their decision.", }); it('should not show approval info when request does not require approval', async () => { + const { getByTestId } = render( + , + ); + + await waitFor(() => + expect(getByTestId('Receipt-message')).toHaveTextContent( + 'It will be processed by HR Services within the next 2-3 business days. Please print a copy for your records.', + ), + ); + }); + }); + + describe('overlapping requests', () => { + it('shows overlap message when reason is OverlappingRequests', async () => { const { getByTestId } = render( , ); await waitFor(() => expect(getByTestId('Receipt-message')).toHaveTextContent( - 'It will be processed by HR Services within the next 2-3 business days. Please print a copy for your records.', + /pending Additional Salary Request/, ), ); }); diff --git a/src/components/HrTools/SalaryCalculator/Receipt/Receipt.tsx b/src/components/HrTools/SalaryCalculator/Receipt/Receipt.tsx index b9fc3d8053..eecd40a41e 100644 --- a/src/components/HrTools/SalaryCalculator/Receipt/Receipt.tsx +++ b/src/components/HrTools/SalaryCalculator/Receipt/Receipt.tsx @@ -10,6 +10,7 @@ import { Typography, } from '@mui/material'; import { Trans, useTranslation } from 'react-i18next'; +import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; import { useAccountListId } from 'src/hooks/useAccountListId'; import { useCaps } from '../SalaryCalculation/useCaps'; import { useSalaryCalculator } from '../SalaryCalculatorContext/SalaryCalculatorContext'; @@ -24,9 +25,9 @@ export const ReceiptStep: React.FC = () => { const accountListId = useAccountListId(); const { t } = useTranslation(); const { formatCurrency } = useFormatters(); - const { hcmUser, calculation } = useSalaryCalculator(); + const { calculation } = useSalaryCalculator(); const progressiveApprovalTier = calculation?.progressiveApprovalTier; - const boardCapException = hcmUser?.exceptionSalaryCap.boardCapException; + const reason = calculation?.progressiveApprovalTierReason; const { combinedGross } = useCaps(); const [showReceipt, setShowReceipt] = useState(false); @@ -49,13 +50,23 @@ export const ReceiptStep: React.FC = () => { It will be processed by HR Services within the next 2-3 business days. Please print a copy for your records. - ) : boardCapException ? ( + ) : reason === ProgressiveApprovalTierReasonEnum.BoardCapException ? ( You have a Board approved Maximum Allowable Salary (CAP) and your salary request exceeds that amount. As a result we need to get their approval for this request. We'll forward your request to them and get back to you with their decision. + ) : reason === + ProgressiveApprovalTierReasonEnum.OverlappingRequests ? ( + + Because you or your spouse has a pending Additional Salary + Request, this request requires additional approval. This will take{' '} + {{ timeframe: progressiveApprovalTier.approvalTimeframe }} as it + needs to be signed off by the{' '} + {{ approver: progressiveApprovalTier.approver }}. This may affect + your selected effective date. + ) : ( Because your request exceeds your maximum allowable salary it will diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.test.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.test.tsx index e7ec50c834..cec36602d3 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.test.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.test.tsx @@ -1,6 +1,9 @@ import { render, waitFor } from '@testing-library/react'; import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; -import { ProgressiveApprovalTierEnum } from 'src/graphql/types.generated'; +import { + ProgressiveApprovalTierEnum, + ProgressiveApprovalTierReasonEnum, +} from 'src/graphql/types.generated'; import { SalaryCalculatorTestWrapper, SalaryCalculatorTestWrapperProps, @@ -25,11 +28,12 @@ describe('ApprovalProcessCard', () => { const { getByRole, getByTestId } = render( , ); @@ -51,11 +55,12 @@ If this is correct, please provide reasoning for why John's Salary should exceed const { getByRole, getByTestId } = render( , ); @@ -79,7 +84,6 @@ If this is correct, please provide reasoning for why Jane's Salary should exceed }, }; const overCapMock = { - calculations: { requestedGross: 40000, effectiveCap: 30000 }, progressiveApprovalTier: { tier: ProgressiveApprovalTierEnum.VicePresident, }, @@ -111,11 +115,12 @@ If this is correct, please provide reasoning for why Jane's Salary should exceed const { getByRole, getByTestId } = render( , ); diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.tsx index 4e22dc0ba3..0dcc20a7ae 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.tsx @@ -53,13 +53,14 @@ export const ApprovalProcessCard: React.FC = () => { /> - {tier === ProgressiveApprovalTierEnum.DivisionHead ? ( + {tier === ProgressiveApprovalTierEnum.DivisionHead && + overCapPerson ? ( - {{ name: overCapPerson?.name }}'s Gross Requested Salary + {{ name: overCapPerson.name }}'s Gross Requested Salary exceeds their individual Maximum Allowable Salary. If this is correct, please provide reasoning for why{' '} - {{ name: overCapPerson?.name }}'s Salary should exceed{' '} - {{ cap: overCapPerson?.effectiveCap }} for division head approval + {{ name: overCapPerson.name }}'s Salary should exceed{' '} + {{ cap: overCapPerson.effectiveCap }} for division head approval below. ) : spouseName ? ( diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx index a9ab075b6a..f6abf57fa4 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx @@ -1,7 +1,10 @@ import { render, waitFor } from '@testing-library/react'; import { merge } from 'lodash'; import { DeepPartial } from 'ts-essentials'; -import { ProgressiveApprovalTierEnum } from 'src/graphql/types.generated'; +import { + ProgressiveApprovalTierEnum, + ProgressiveApprovalTierReasonEnum, +} from 'src/graphql/types.generated'; import { SalaryCalculationQuery } from '../../SalaryCalculatorContext/SalaryCalculation.generated'; import { SalaryCalculatorTestWrapper, @@ -47,16 +50,15 @@ describe('RequestSummaryCard', () => { }); describe('board cap exception', () => { - const hcmUser = { exceptionSalaryCap: { boardCapException: true } }; - it('renders status message and textfield', async () => { const { getByTestId } = render( , ); @@ -73,10 +75,7 @@ We'll forward your request to them and get back to you with their decision.", it('renders status message when request does not require approval', async () => { const { findByTestId } = render( - , + , ); expect(await findByTestId('RequestSummaryCard-status')).toHaveTextContent( @@ -85,16 +84,41 @@ We'll forward your request to them and get back to you with their decision.", }); }); + describe('overlapping requests', () => { + it('renders overlap message when reason is OverlappingRequests', async () => { + const { getByTestId } = render( + , + ); + + await waitFor(() => + expect(getByTestId('RequestSummaryCard-status')).toHaveTextContent( + 'You or your spouse has a pending Additional Salary Request, so this request needs additional approval. \ +This may take 2 weeks as it needs to be signed off by the MCC. This may affect your selected effective date.', + ), + ); + }); + }); + describe('user over cap', () => { it('renders status message', async () => { const { getByTestId } = render( , ); @@ -115,11 +139,11 @@ or make changes to how your Requested Salary is distributed above.", const { getByTestId } = render( , ); @@ -140,12 +164,13 @@ or make changes to how your Requested Salary is distributed above.", const { getByTestId } = render( , ); @@ -294,12 +319,13 @@ This may affect your selected effective date.', , ); diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.tsx index 6975ff2828..dd63117938 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.tsx @@ -14,7 +14,10 @@ import { useTheme, } from '@mui/material'; import { Trans, useTranslation } from 'react-i18next'; -import { ProgressiveApprovalTierEnum } from 'src/graphql/types.generated'; +import { + ProgressiveApprovalTierEnum, + ProgressiveApprovalTierReasonEnum, +} from 'src/graphql/types.generated'; import { useSalaryCalculator } from '../../SalaryCalculatorContext/SalaryCalculatorContext'; import { StepCard } from '../../Shared/StepCard'; import { useFormatters } from '../../Shared/useFormatters'; @@ -55,10 +58,10 @@ export const RequestSummaryCard: React.FC = () => { const theme = useTheme(); const { calculation, hcmUser, hcmSpouse } = useSalaryCalculator(); const progressiveApprovalTier = calculation?.progressiveApprovalTier; + const reason = calculation?.progressiveApprovalTierReason; const approvalRequired = !!progressiveApprovalTier && progressiveApprovalTier?.tier !== ProgressiveApprovalTierEnum.DivisionHead; - const boardCapException = hcmUser?.exceptionSalaryCap.boardCapException; const { combinedGross, overCapPerson } = useCaps(); const { formatCurrency } = useFormatters(); @@ -95,14 +98,22 @@ export const RequestSummaryCard: React.FC = () => { const combinedModifier = hasSpouse ? t('Combined') : ''; const statusMessage = !progressiveApprovalTier ? ( t('Your gross request is within your Maximum Allowable Salary.') - ) : boardCapException ? ( + ) : reason === ProgressiveApprovalTierReasonEnum.BoardCapException ? ( You have a Board approved Maximum Allowable Salary (CAP) and your salary request exceeds that amount. As a result we need to get their approval for this request. We'll forward your request to them and get back to you with their decision. - ) : approvalRequired ? ( + ) : reason === ProgressiveApprovalTierReasonEnum.OverlappingRequests ? ( + + You or your spouse has a pending Additional Salary Request, so this + request needs additional approval. This may take{' '} + {{ timeframe: progressiveApprovalTier.approvalTimeframe }} as it needs to + be signed off by the {{ approver: progressiveApprovalTier.approver }}. + This may affect your selected effective date. + + ) : reason === ProgressiveApprovalTierReasonEnum.OverCombinedCap ? ( Your {{ combined: combinedModifier }} Gross Requested Salary exceeds your{' '} {{ combined: combinedModifier }} Maximum Allowable Salary. Please make diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestedSalaryCard/RequestedSalaryCard.test.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestedSalaryCard/RequestedSalaryCard.test.tsx index df24a665eb..45c686c36b 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestedSalaryCard/RequestedSalaryCard.test.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestedSalaryCard/RequestedSalaryCard.test.tsx @@ -3,6 +3,7 @@ import { render, waitFor } from '@testing-library/react'; import { DeepPartial } from 'ts-essentials'; import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; import { AutosaveForm } from 'src/components/Shared/Autosave/AutosaveForm'; +import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; import { SalaryCalculationQuery } from '../../SalaryCalculatorContext/SalaryCalculation.generated'; import { SalaryCalculatorTestWrapper, @@ -182,6 +183,8 @@ As you set your salary level, the amount you receive should reflect the amount o effectiveCap: 10004, requestedGross: 15000, }, + progressiveApprovalTierReason: + ProgressiveApprovalTierReasonEnum.OverUserCap, }; it('renders when the SOSA user is over their effective cap', async () => { diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useCaps.ts b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useCaps.ts index d209e7e5f1..60461836d3 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useCaps.ts +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useCaps.ts @@ -1,3 +1,4 @@ +import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; import { useSalaryCalculator } from '../SalaryCalculatorContext/SalaryCalculatorContext'; import { useFormatters } from '../Shared/useFormatters'; @@ -13,9 +14,6 @@ interface UseCapsResult { /** The sum of the users' requested gross salaries */ combinedGross: number; - /** Whether the user is over their effective cap */ - overUserCap: boolean; - /** The person whose salary is over their effective cap */ overCapPerson: OverCapPerson | null; } @@ -26,28 +24,27 @@ export const useCaps = (): UseCapsResult => { const calcs = calculation?.calculations; const spouseCalcs = calculation?.spouseCalculations; + const reason = calculation?.progressiveApprovalTierReason; const combinedGross = (calcs?.requestedGross ?? 0) + (spouseCalcs?.requestedGross ?? 0); - const overUserCap = !!calcs && calcs.requestedGross > calcs.effectiveCap; - const overSpouseCap = - !!spouseCalcs && spouseCalcs.requestedGross > spouseCalcs.effectiveCap; - const overCapPerson = overUserCap - ? { - name: hcmUser?.staffInfo.preferredName ?? null, - effectiveCap: formatCurrency(calcs.effectiveCap), - } - : overSpouseCap + const overCapPerson = + reason === ProgressiveApprovalTierReasonEnum.OverUserCap && calcs ? { - name: hcmSpouse?.staffInfo.preferredName ?? null, - effectiveCap: formatCurrency(spouseCalcs.effectiveCap), + name: hcmUser?.staffInfo.preferredName ?? null, + effectiveCap: formatCurrency(calcs.effectiveCap), } - : null; + : reason === ProgressiveApprovalTierReasonEnum.OverSpouseCap && + spouseCalcs + ? { + name: hcmSpouse?.staffInfo.preferredName ?? null, + effectiveCap: formatCurrency(spouseCalcs.effectiveCap), + } + : null; return { combinedGross, - overUserCap, overCapPerson, }; }; diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx index 13ae9011c1..7c4c5834d5 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { renderHook, waitFor } from '@testing-library/react'; import { DeepPartial } from 'ts-essentials'; import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; +import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; import { SalaryCalculationQuery } from '../SalaryCalculatorContext/SalaryCalculation.generated'; import { SalaryCalculatorTestWrapper } from '../SalaryCalculatorTestWrapper'; import { useSosaBlockOverCap } from './useSosaBlockOverCap'; @@ -12,6 +13,7 @@ const sosaUser = { const overCapMock: DeepPartial = { calculations: { effectiveCap: 10004, requestedGross: 15000 }, + progressiveApprovalTierReason: ProgressiveApprovalTierReasonEnum.OverUserCap, }; const renderUseSosaBlockOverCap = ( diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.ts b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.ts index 6f6a1e6f41..c559423130 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.ts +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.ts @@ -1,6 +1,6 @@ import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; +import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; import { useSalaryCalculator } from '../SalaryCalculatorContext/SalaryCalculatorContext'; -import { useCaps } from './useCaps'; interface UseSosaBlockOverCapResult { /** Whether the user is a SOSA employee (Employee Staff Non-RMO Spouse) */ @@ -15,12 +15,14 @@ interface UseSosaBlockOverCapResult { * effective cap. Requests over their cap may not be submitted online. */ export const useSosaBlockOverCap = (): UseSosaBlockOverCapResult => { - const { hcmUser } = useSalaryCalculator(); - const { overUserCap } = useCaps(); + const { hcmUser, calculation } = useSalaryCalculator(); const isUserSosa = hcmUser?.staffInfo.userPersonType === UserPersonTypeEnum.EmployeeStaffNonRmoSpouse; + const overUserCap = + calculation?.progressiveApprovalTierReason === + ProgressiveApprovalTierReasonEnum.OverUserCap; const blockOnCap = isUserSosa && overUserCap; return { isUserSosa, blockOnCap }; diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculatorContext/SalaryCalculation.graphql b/src/components/HrTools/SalaryCalculator/SalaryCalculatorContext/SalaryCalculation.graphql index 4a906f73b3..742c841d16 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculatorContext/SalaryCalculation.graphql +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculatorContext/SalaryCalculation.graphql @@ -28,6 +28,7 @@ fragment SalaryRequestFields on SalaryRequest { approver approvalTimeframe } + progressiveApprovalTierReason } fragment CalculationFields on SalaryRequestCalculations { diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculatorTestWrapper.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculatorTestWrapper.tsx index 0a4ccaba36..200e8c7485 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculatorTestWrapper.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculatorTestWrapper.tsx @@ -183,6 +183,7 @@ export const SalaryCalculatorTestWrapper: React.FC< combinedCap: 125000, }, progressiveApprovalTier: null, + progressiveApprovalTierReason: null, } satisfies SalaryRequestMock, salaryRequestMock, hasSpouse ? undefined : { spouseCalculations: null }, diff --git a/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx b/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx index 0318260a6c..a9774283ea 100644 --- a/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx +++ b/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx @@ -1,5 +1,8 @@ import { renderHook, waitFor } from '@testing-library/react'; -import { ProgressiveApprovalTierEnum } from 'src/graphql/types.generated'; +import { + ProgressiveApprovalTierEnum, + ProgressiveApprovalTierReasonEnum, +} from 'src/graphql/types.generated'; import { SalaryCalculatorTestWrapper } from '../SalaryCalculatorTestWrapper'; import { useSubmitDialogContent } from './useSubmitDialogContent'; @@ -97,7 +100,7 @@ describe('useSubmitDialogContent', () => { expect(result.current.subContent).toContain('Vice President'); }); - it('returns board cap exception content when user has exception salary cap', async () => { + it('returns board cap exception content when the reason is BoardCapException', async () => { const { result } = renderHook(() => useSubmitDialogContent(), { wrapper: ({ children }) => ( { progressiveApprovalTier: { tier: ProgressiveApprovalTierEnum.BoardCompensationCommittee, }, - }} - hcmUser={{ - exceptionSalaryCap: { boardCapException: true }, + progressiveApprovalTierReason: + ProgressiveApprovalTierReasonEnum.BoardCapException, }} > {children} diff --git a/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.ts b/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.ts index f43c7ed151..6b28c9c626 100644 --- a/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.ts +++ b/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.ts @@ -1,5 +1,8 @@ import { useTranslation } from 'react-i18next'; -import { ProgressiveApprovalTierEnum } from 'src/graphql/types.generated'; +import { + ProgressiveApprovalTierEnum, + ProgressiveApprovalTierReasonEnum, +} from 'src/graphql/types.generated'; import { useCaps } from '../SalaryCalculation/useCaps'; import { useSalaryCalculator } from '../SalaryCalculatorContext/SalaryCalculatorContext'; import { useFormatters } from '../Shared/useFormatters'; @@ -12,16 +15,15 @@ interface DialogContent { export const useSubmitDialogContent = (): DialogContent => { const { t } = useTranslation(); - const { calculation, hcmUser } = useSalaryCalculator(); + const { calculation } = useSalaryCalculator(); const { combinedGross } = useCaps(); const { formatCurrency } = useFormatters(); const progressiveApprovalTier = calculation?.progressiveApprovalTier; + const reason = calculation?.progressiveApprovalTierReason; const approvalRequired = !!progressiveApprovalTier && progressiveApprovalTier.tier !== ProgressiveApprovalTierEnum.DivisionHead; - const hasBoardCapException = - hcmUser?.exceptionSalaryCap.boardCapException ?? false; if (!approvalRequired) { return { @@ -32,10 +34,18 @@ export const useSubmitDialogContent = (): DialogContent => { } let subContent: string; - if (hasBoardCapException) { + if (reason === ProgressiveApprovalTierReasonEnum.BoardCapException) { subContent = t( "You have a Board approved Maximum Allowable Salary (CAP) and your salary request exceeds that amount. As a result we need to get their approval for this request. We'll forward your request to them and get back to you with their decision.", ); + } else if (reason === ProgressiveApprovalTierReasonEnum.OverlappingRequests) { + subContent = t( + 'You or your spouse has a pending Additional Salary Request, so this request needs additional approval. This will take {{timeframe}} as it needs to be signed off by {{approvers}}. This may affect your selected effective date.', + { + timeframe: progressiveApprovalTier?.approvalTimeframe, + approvers: progressiveApprovalTier?.approver, + }, + ); } else { subContent = t( 'We will review your request through our Progressive Approvals process. For the {{amount}} you are requesting, this will take {{timeframe}} as it needs to be signed off by {{approvers}}. This may affect your selected effective date.', From e3bb43bc20bcd296d1437090fe6eeb4f1f5e34e6 Mon Sep 17 00:00:00 2001 From: Caleb Cox Date: Wed, 13 May 2026 14:42:09 -0500 Subject: [PATCH 2/7] Remove hasBoardCapException --- .../RequestPage/RequestPage.test.tsx | 1 - .../Shared/AdditionalSalaryRequestContext.tsx | 8 -------- .../Shared/AutoSave/AutosaveCustomTextField.test.tsx | 1 - .../Shared/AutoSave/useSaveField.test.tsx | 1 - .../Shared/useAdditionalSalaryRequestForm.test.tsx | 2 -- .../Shared/useAdditionalSalaryRequestForm.ts | 8 +++++--- .../SharedComponents/CurrentRequest.test.tsx | 1 - .../SharedComponents/StepList.test.tsx | 1 - .../SalaryCalculator/SalaryCalculatorTestWrapper.tsx | 6 ------ .../StepNavigation/useSubmitDialogContent.test.tsx | 9 --------- src/components/HrTools/Shared/HcmData/Hcm.graphql | 1 - src/components/HrTools/Shared/HcmData/mockData.ts | 1 - 12 files changed, 5 insertions(+), 35 deletions(-) diff --git a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.test.tsx index 86968800e2..02e7b40327 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/RequestPage.test.tsx @@ -105,7 +105,6 @@ const defaultMockContextValue = { setIsNewAsr: jest.fn(), isSpouse: false, hasSpouse: false, - hasBoardCapException: false, fieldConfig: getFieldConfig(i18n.t), }; diff --git a/src/components/HrTools/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx b/src/components/HrTools/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx index 54060f6046..29c5dc4caa 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx @@ -17,7 +17,6 @@ import { import { AdditionalSalaryRequestCalculations, AsrStatusEnum, - ProgressiveApprovalTierReasonEnum, } from 'src/graphql/types.generated'; import { useStepList } from 'src/hooks/useStepList'; import { useTrackMutation } from 'src/hooks/useTrackMutation'; @@ -122,7 +121,6 @@ export type AdditionalSalaryRequestType = { setIsNewAsr: React.Dispatch>; isSpouse: boolean; hasSpouse: boolean; - hasBoardCapException: boolean; isPending: boolean; isApproved: boolean; fieldConfig: FieldConfig; @@ -255,10 +253,6 @@ export const AdditionalSalaryRequestProvider: React.FC = ({ ? primaryPerson : spousePerson : undefined; - const hasBoardCapException = - requestData?.latestAdditionalSalaryRequest - ?.progressiveApprovalTierReason === - ProgressiveApprovalTierReasonEnum.BoardCapException; const salaryInfo = salaryInfoData?.salaryInfo; const isInternational = user?.staffInfo?.isInternational ?? false; @@ -310,7 +304,6 @@ export const AdditionalSalaryRequestProvider: React.FC = ({ setIsNewAsr, isSpouse, hasSpouse, - hasBoardCapException, isPending, isApproved, fieldConfig, @@ -348,7 +341,6 @@ export const AdditionalSalaryRequestProvider: React.FC = ({ setIsNewAsr, isSpouse, hasSpouse, - hasBoardCapException, isPending, isApproved, fieldConfig, diff --git a/src/components/HrTools/AdditionalSalaryRequest/Shared/AutoSave/AutosaveCustomTextField.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/Shared/AutoSave/AutosaveCustomTextField.test.tsx index f9a558e32c..9a3b97b441 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/Shared/AutoSave/AutosaveCustomTextField.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/Shared/AutoSave/AutosaveCustomTextField.test.tsx @@ -84,7 +84,6 @@ const defaultMockContextValue: AdditionalSalaryRequestType = { setIsNewAsr: jest.fn(), isSpouse: false, hasSpouse: false, - hasBoardCapException: false, isPending: false, isApproved: false, fieldConfig: getFieldConfig(i18n.t), diff --git a/src/components/HrTools/AdditionalSalaryRequest/Shared/AutoSave/useSaveField.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/Shared/AutoSave/useSaveField.test.tsx index 87b6ee80e9..f32ee255a3 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/Shared/AutoSave/useSaveField.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/Shared/AutoSave/useSaveField.test.tsx @@ -96,7 +96,6 @@ const defaultMockContextValue: AdditionalSalaryRequestType = { setIsNewAsr: jest.fn(), isSpouse: false, hasSpouse: false, - hasBoardCapException: false, isPending: false, isApproved: false, fieldConfig: getFieldConfig(i18n.t), diff --git a/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.test.tsx index cc61ad0e28..2e2d771b16 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.test.tsx @@ -103,7 +103,6 @@ const defaultMockContextValue: AdditionalSalaryRequestType = { setIsNewAsr: jest.fn(), isSpouse: false, hasSpouse: false, - hasBoardCapException: false, isPending: false, isApproved: false, fieldConfig, @@ -491,7 +490,6 @@ describe('useAdditionalSalaryRequestForm', () => { it('should not require additional info when exceedsCap is true and user has board cap exception', async () => { mockUseAdditionalSalaryRequest.mockReturnValue({ ...defaultMockContextValue, - hasBoardCapException: true, }); const { result } = renderHook( diff --git a/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.ts b/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.ts index 646d12e80a..f359e5126d 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.ts +++ b/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.ts @@ -32,7 +32,6 @@ export const useAdditionalSalaryRequestForm = ( isInternational, requestId, isSpouse, - hasBoardCapException, fieldConfig, } = useAdditionalSalaryRequest(); @@ -161,7 +160,10 @@ export const useAdditionalSalaryRequestForm = ( 'required-when-exceeds-cap', t('Additional info is required for requests exceeding your cap.'), function (value) { - if (hasBoardCapException) { + if ( + requestData?.latestAdditionalSalaryRequest + ?.progressiveApprovalTier + ) { return true; } const total = getTotal(this.parent as CompleteFormValues); @@ -192,7 +194,7 @@ export const useAdditionalSalaryRequestForm = ( primaryAccountBalance, individualCap, locale, - hasBoardCapException, + requestData, ], ); diff --git a/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/CurrentRequest.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/CurrentRequest.test.tsx index 52d0b16ff8..f3d8afcd32 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/CurrentRequest.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/CurrentRequest.test.tsx @@ -102,7 +102,6 @@ const mockContextValue = { setIsNewAsr: jest.fn(), isSpouse: false, hasSpouse: false, - hasBoardCapException: false, isPending: true, isApproved: false, fieldConfig: getFieldConfig(i18n.t), diff --git a/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/StepList.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/StepList.test.tsx index 779c12eff1..97d6f7a1ba 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/StepList.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/StepList.test.tsx @@ -78,7 +78,6 @@ const mockContextValue = { setIsNewAsr: jest.fn(), isSpouse: false, hasSpouse: false, - hasBoardCapException: false, isPending: false, isApproved: false, fieldConfig: getFieldConfig(i18n.t), diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculatorTestWrapper.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculatorTestWrapper.tsx index 200e8c7485..7ca4c0ce0b 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculatorTestWrapper.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculatorTestWrapper.tsx @@ -54,9 +54,6 @@ const hcmMock = gqlMock(HcmDocument, { mhiEit: { mhiEligibility: false, }, - exceptionSalaryCap: { - boardCapException: false, - }, }, { salaryRequestEligible: true, @@ -83,9 +80,6 @@ const hcmMock = gqlMock(HcmDocument, { mhiEit: { mhiEligibility: false, }, - exceptionSalaryCap: { - boardCapException: false, - }, }, ], }, diff --git a/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx b/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx index a9774283ea..64496912a6 100644 --- a/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx +++ b/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx @@ -14,9 +14,6 @@ describe('useSubmitDialogContent', () => { salaryRequestMock={{ progressiveApprovalTier: null, }} - hcmUser={{ - exceptionSalaryCap: { boardCapException: true }, - }} > {children} @@ -47,9 +44,6 @@ describe('useSubmitDialogContent', () => { approver: 'Division Head', }, }} - hcmUser={{ - exceptionSalaryCap: { boardCapException: false }, - }} > {children} @@ -80,9 +74,6 @@ describe('useSubmitDialogContent', () => { requestedGross: 30000, }, }} - hcmUser={{ - exceptionSalaryCap: { boardCapException: false }, - }} > {children} diff --git a/src/components/HrTools/Shared/HcmData/Hcm.graphql b/src/components/HrTools/Shared/HcmData/Hcm.graphql index b9b7d37470..6be97a2f35 100644 --- a/src/components/HrTools/Shared/HcmData/Hcm.graphql +++ b/src/components/HrTools/Shared/HcmData/Hcm.graphql @@ -31,7 +31,6 @@ query Hcm($effectiveDate: ISO8601Date) { exceptionSalaryCap { amount effectiveDate - boardCapException } fourOThreeB { currentRothContributionPercentage diff --git a/src/components/HrTools/Shared/HcmData/mockData.ts b/src/components/HrTools/Shared/HcmData/mockData.ts index 11e064ba23..7b42671125 100644 --- a/src/components/HrTools/Shared/HcmData/mockData.ts +++ b/src/components/HrTools/Shared/HcmData/mockData.ts @@ -47,7 +47,6 @@ const noMhaAndNoException: HcmQuery['hcm'][number] = { exceptionSalaryCap: { amount: null, effectiveDate: null, - boardCapException: false, }, fourOThreeB: { currentTaxDeferredContributionPercentage: 6, From 3e064802969e5aed3ee1745ffd1436d860daf9ab Mon Sep 17 00:00:00 2001 From: Caleb Cox Date: Wed, 13 May 2026 15:00:39 -0500 Subject: [PATCH 3/7] Code review feedback --- .../Helper/getCapOverrides.test.ts | 26 ++++++++++++++++ .../useSosaBlockOverCap.test.tsx | 26 +++------------- .../useSubmitDialogContent.test.tsx | 31 +++++++++++++++++++ .../StepNavigation/useSubmitDialogContent.ts | 10 ++++-- 4 files changed, 69 insertions(+), 24 deletions(-) diff --git a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.test.ts b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.test.ts index 78c4ff3bee..3e08a2092f 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.test.ts +++ b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/getCapOverrides.test.ts @@ -41,6 +41,32 @@ describe('getCapOverrides', () => { expect(result.content).toMatch(/exceed your Maximum Allowable Salary/); }); + it('returns Progressive Approvals messaging when over spouse cap', () => { + const result = getCapOverrides( + { + splitAsr: false, + reason: ProgressiveApprovalTierReasonEnum.OverSpouseCap, + }, + t, + ); + expect(result.title).toMatch(/requires additional approval/); + expect(result.content).toMatch(/exceed your Maximum Allowable Salary/); + }); + + it('returns Progressive Approvals messaging with overlapping requests', () => { + const result = getCapOverrides( + { + splitAsr: false, + reason: ProgressiveApprovalTierReasonEnum.OverlappingRequests, + }, + t, + ); + expect(result.title).toMatch(/requires additional approval/); + expect(result.content).toMatch( + /pending Additional Salary Request or Salary Request/, + ); + }); + it('returns combined-cap messaging when over combined cap', () => { const result = getCapOverrides( { diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx index 7c4c5834d5..3d4be0c95d 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx @@ -11,8 +11,7 @@ const sosaUser = { staffInfo: { userPersonType: UserPersonTypeEnum.EmployeeStaffNonRmoSpouse }, }; -const overCapMock: DeepPartial = { - calculations: { effectiveCap: 10004, requestedGross: 15000 }, +const overCap: DeepPartial = { progressiveApprovalTierReason: ProgressiveApprovalTierReasonEnum.OverUserCap, }; @@ -32,32 +31,17 @@ describe('useSosaBlockOverCap', () => { const { result } = renderUseSosaBlockOverCap({ hasSpouse: false, hcmUser: sosaUser, - salaryRequestMock: overCapMock, + salaryRequestMock: overCap, }); await waitFor(() => expect(result.current.blockOnCap).toBe(true)); }); - it('does not block when a SOSA user is under their cap', async () => { + it('does not block when reason is null', async () => { const { result } = renderUseSosaBlockOverCap({ hasSpouse: false, hcmUser: sosaUser, - salaryRequestMock: { - calculations: { effectiveCap: 10004, requestedGross: 10003 }, - }, - }); - - await waitFor(() => expect(result.current.isUserSosa).toBe(true)); - expect(result.current.blockOnCap).toBe(false); - }); - - it('does not block when a SOSA user is exactly at their cap', async () => { - const { result } = renderUseSosaBlockOverCap({ - hasSpouse: false, - hcmUser: sosaUser, - salaryRequestMock: { - calculations: { effectiveCap: 10004, requestedGross: 10004 }, - }, + salaryRequestMock: { progressiveApprovalTierReason: null }, }); await waitFor(() => expect(result.current.isUserSosa).toBe(true)); @@ -67,7 +51,7 @@ describe('useSosaBlockOverCap', () => { it('does not block when the user is not SOSA, even if over cap', async () => { const { result } = renderUseSosaBlockOverCap({ hasSpouse: false, - salaryRequestMock: overCapMock, + salaryRequestMock: overCap, }); await waitFor(() => expect(result.current.isUserSosa).toBe(false)); diff --git a/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx b/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx index 64496912a6..70ee13f889 100644 --- a/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx +++ b/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.test.tsx @@ -123,4 +123,35 @@ describe('useSubmitDialogContent', () => { "We'll forward your request to them and get back to you with their decision", ); }); + + it('returns overlapping requests content when the reason is OverlappingRequests', async () => { + const { result } = renderHook(() => useSubmitDialogContent(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + await waitFor(() => { + expect(result.current.title).toBe( + 'Your request requires additional approval. Do you want to continue?', + ); + }); + expect(result.current.subContent).toContain( + 'pending Additional Salary Request', + ); + expect(result.current.subContent).toContain('2 weeks'); + expect(result.current.subContent).toContain('MCC'); + }); }); diff --git a/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.ts b/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.ts index 6b28c9c626..816b12ffb3 100644 --- a/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.ts +++ b/src/components/HrTools/SalaryCalculator/StepNavigation/useSubmitDialogContent.ts @@ -33,12 +33,18 @@ export const useSubmitDialogContent = (): DialogContent => { }; } + let title = t( + 'Your request requires additional approval because your Gross Salary exceeds your Maximum Allowable Salary. Do you want to continue?', + ); let subContent: string; if (reason === ProgressiveApprovalTierReasonEnum.BoardCapException) { subContent = t( "You have a Board approved Maximum Allowable Salary (CAP) and your salary request exceeds that amount. As a result we need to get their approval for this request. We'll forward your request to them and get back to you with their decision.", ); } else if (reason === ProgressiveApprovalTierReasonEnum.OverlappingRequests) { + title = t( + 'Your request requires additional approval. Do you want to continue?', + ); subContent = t( 'You or your spouse has a pending Additional Salary Request, so this request needs additional approval. This will take {{timeframe}} as it needs to be signed off by {{approvers}}. This may affect your selected effective date.', { @@ -58,9 +64,7 @@ export const useSubmitDialogContent = (): DialogContent => { } return { - title: t( - 'Your request requires additional approval because your Gross Salary exceeds your Maximum Allowable Salary. Do you want to continue?', - ), + title, content: t( 'Requests exceeding your Maximum Allowable Salary require additional review.', ), From f4d4b2f6d62db0b7da7b2a412474339639e299e7 Mon Sep 17 00:00:00 2001 From: Caleb Cox Date: Wed, 13 May 2026 15:06:20 -0500 Subject: [PATCH 4/7] Standardize wording --- .../RequestSummaryCard/RequestSummaryCard.test.tsx | 6 +++--- .../RequestSummaryCard/RequestSummaryCard.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx index f6abf57fa4..5fc471a763 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx @@ -103,7 +103,7 @@ We'll forward your request to them and get back to you with their decision.", await waitFor(() => expect(getByTestId('RequestSummaryCard-status')).toHaveTextContent( 'You or your spouse has a pending Additional Salary Request, so this request needs additional approval. \ -This may take 2 weeks as it needs to be signed off by the MCC. This may affect your selected effective date.', +This will take 2 weeks as it needs to be signed off by the MCC. This may affect your selected effective date.', ), ); }); @@ -179,7 +179,7 @@ or make changes to how your Requested Salary is distributed above.", expect(getByTestId('RequestSummaryCard-status')).toHaveTextContent( 'Your Combined Gross Requested Salary exceeds your Combined Maximum Allowable Salary. \ Please make adjustments to your Salary Request above or fill out the Approval Process Section below to request a higher amount through our Progressive Approvals process. \ -This may take 1-2 weeks as it needs to be signed off by the Vice President. \ +This will take 1-2 weeks as it needs to be signed off by the Vice President. \ This may affect your selected effective date.', ), ); @@ -334,7 +334,7 @@ This may affect your selected effective date.', expect(getByTestId('RequestSummaryCard-status')).toHaveTextContent( 'Your Gross Requested Salary exceeds your Maximum Allowable Salary. \ Please make adjustments to your Salary Request above or fill out the Approval Process Section below to request a higher amount through our Progressive Approvals process. \ -This may take 1-2 weeks as it needs to be signed off by the Vice President. \ +This will take 1-2 weeks as it needs to be signed off by the Vice President. \ This may affect your selected effective date.', ), ); diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.tsx index dd63117938..dff6b9ee55 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.tsx @@ -108,7 +108,7 @@ export const RequestSummaryCard: React.FC = () => { ) : reason === ProgressiveApprovalTierReasonEnum.OverlappingRequests ? ( You or your spouse has a pending Additional Salary Request, so this - request needs additional approval. This may take{' '} + request needs additional approval. This will take{' '} {{ timeframe: progressiveApprovalTier.approvalTimeframe }} as it needs to be signed off by the {{ approver: progressiveApprovalTier.approver }}. This may affect your selected effective date. @@ -119,7 +119,7 @@ export const RequestSummaryCard: React.FC = () => { {{ combined: combinedModifier }} Maximum Allowable Salary. Please make adjustments to your Salary Request above or fill out the Approval Process Section below to request a higher amount through our Progressive Approvals - process. This may take{' '} + process. This will take{' '} {{ timeframe: progressiveApprovalTier.approvalTimeframe }} as it needs to be signed off by the {{ approver: progressiveApprovalTier.approver }}. This may affect your selected effective date. From fde3e82a879dcf83705f71dc87675fc5ec495b96 Mon Sep 17 00:00:00 2001 From: Caleb Cox Date: Wed, 13 May 2026 15:10:50 -0500 Subject: [PATCH 5/7] Standardize imports --- src/components/Announcements/Announcements.tsx | 2 +- .../Items/PersonModal/PersonEmail/PersonEmailItem.tsx | 2 +- .../RequestPage/Helper/CapSubContent.test.tsx | 2 +- .../Shared/AutoSave/useSaveField.ts | 2 +- .../ApprovalProcessCard/ApprovalProcessCard.test.tsx | 2 +- .../RequestedSalaryCard/RequestedSalaryCard.test.tsx | 6 ++++-- .../SalaryCalculation/useSosaBlockOverCap.test.tsx | 6 ++++-- .../SalaryCalculation/useSosaBlockOverCap.ts | 6 ++++-- .../SalaryCalculator/Shared/getLocalizedTaxStatus.test.tsx | 2 +- .../SalaryCalculator/Shared/getLocalizedTaxStatus.tsx | 2 +- 10 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/components/Announcements/Announcements.tsx b/src/components/Announcements/Announcements.tsx index 2ba0063743..b67983747e 100644 --- a/src/components/Announcements/Announcements.tsx +++ b/src/components/Announcements/Announcements.tsx @@ -8,11 +8,11 @@ import React, { } from 'react'; import { getApolloContext } from '@apollo/client'; import { DateTime } from 'luxon'; -import { DisplayMethodEnum } from 'pages/api/graphql-rest.page.generated'; import { AlertBanner } from 'src/components/Shared/alertBanner/AlertBanner'; import { ActionEnum, ContactFilterStatusEnum, + DisplayMethodEnum, } from 'src/graphql/types.generated'; import { useAccountListId } from 'src/hooks/useAccountListId'; import { useContactPartnershipStatuses } from 'src/hooks/useContactPartnershipStatuses'; diff --git a/src/components/Contacts/ContactDetails/ContactDetailsTab/People/Items/PersonModal/PersonEmail/PersonEmailItem.tsx b/src/components/Contacts/ContactDetails/ContactDetailsTab/People/Items/PersonModal/PersonEmail/PersonEmailItem.tsx index ca665eaee5..39d729c52d 100644 --- a/src/components/Contacts/ContactDetails/ContactDetailsTab/People/Items/PersonModal/PersonEmail/PersonEmailItem.tsx +++ b/src/components/Contacts/ContactDetails/ContactDetailsTab/People/Items/PersonModal/PersonEmail/PersonEmailItem.tsx @@ -11,8 +11,8 @@ import { import { styled } from '@mui/material/styles'; import { FormikErrors, getIn } from 'formik'; import { useTranslation } from 'react-i18next'; -import { InputMaybe } from 'pages/api/graphql-rest.page.generated'; import { + InputMaybe, PersonCreateInput, PersonEmailAddressInput, PersonUpdateInput, diff --git a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.test.tsx index 78f0a8407a..9c16c33ac6 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/RequestPage/Helper/CapSubContent.test.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { ThemeProvider } from '@mui/material/styles'; import { render } from '@testing-library/react'; import { FormikProvider, useFormik } from 'formik'; -import { ProgressiveApprovalTierReasonEnum } from 'pages/api/graphql-rest.page.generated'; +import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; import theme from 'src/theme'; import { CompleteFormValues } from '../../AdditionalSalaryRequest'; import { useAdditionalSalaryRequest } from '../../Shared/AdditionalSalaryRequestContext'; diff --git a/src/components/HrTools/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts b/src/components/HrTools/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts index bda0708a71..a30350a1b6 100644 --- a/src/components/HrTools/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts +++ b/src/components/HrTools/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts @@ -1,7 +1,7 @@ import { useCallback } from 'react'; import { useSnackbar } from 'notistack'; import { useTranslation } from 'react-i18next'; -import { MinistryHousingAllowanceRequestAttributesInput } from 'pages/api/graphql-rest.page.generated'; +import { MinistryHousingAllowanceRequestAttributesInput } from 'src/graphql/types.generated'; import { calculateAnnualTotals } from 'src/hooks/useAnnualTotal'; import { useUpdateMinistryHousingAllowanceRequestMutation } from '../../MinisterHousingAllowance.generated'; import { CalculationFormValues } from '../../Steps/StepThree/Calculation'; diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.test.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.test.tsx index cec36602d3..97b8ad6120 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.test.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/ApprovalProcessCard/ApprovalProcessCard.test.tsx @@ -1,8 +1,8 @@ import { render, waitFor } from '@testing-library/react'; -import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; import { ProgressiveApprovalTierEnum, ProgressiveApprovalTierReasonEnum, + UserPersonTypeEnum, } from 'src/graphql/types.generated'; import { SalaryCalculatorTestWrapper, diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestedSalaryCard/RequestedSalaryCard.test.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestedSalaryCard/RequestedSalaryCard.test.tsx index 45c686c36b..8ccb9526b7 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestedSalaryCard/RequestedSalaryCard.test.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/RequestedSalaryCard/RequestedSalaryCard.test.tsx @@ -1,9 +1,11 @@ import React from 'react'; import { render, waitFor } from '@testing-library/react'; import { DeepPartial } from 'ts-essentials'; -import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; import { AutosaveForm } from 'src/components/Shared/Autosave/AutosaveForm'; -import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; +import { + ProgressiveApprovalTierReasonEnum, + UserPersonTypeEnum, +} from 'src/graphql/types.generated'; import { SalaryCalculationQuery } from '../../SalaryCalculatorContext/SalaryCalculation.generated'; import { SalaryCalculatorTestWrapper, diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx index 3d4be0c95d..134981c13e 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx @@ -1,8 +1,10 @@ import React from 'react'; import { renderHook, waitFor } from '@testing-library/react'; import { DeepPartial } from 'ts-essentials'; -import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; -import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; +import { + ProgressiveApprovalTierReasonEnum, + UserPersonTypeEnum, +} from 'src/graphql/types.generated'; import { SalaryCalculationQuery } from '../SalaryCalculatorContext/SalaryCalculation.generated'; import { SalaryCalculatorTestWrapper } from '../SalaryCalculatorTestWrapper'; import { useSosaBlockOverCap } from './useSosaBlockOverCap'; diff --git a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.ts b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.ts index c559423130..a41ca30270 100644 --- a/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.ts +++ b/src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.ts @@ -1,5 +1,7 @@ -import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; -import { ProgressiveApprovalTierReasonEnum } from 'src/graphql/types.generated'; +import { + ProgressiveApprovalTierReasonEnum, + UserPersonTypeEnum, +} from 'src/graphql/types.generated'; import { useSalaryCalculator } from '../SalaryCalculatorContext/SalaryCalculatorContext'; interface UseSosaBlockOverCapResult { diff --git a/src/components/HrTools/SalaryCalculator/Shared/getLocalizedTaxStatus.test.tsx b/src/components/HrTools/SalaryCalculator/Shared/getLocalizedTaxStatus.test.tsx index c496c8c322..cae1446ee0 100644 --- a/src/components/HrTools/SalaryCalculator/Shared/getLocalizedTaxStatus.test.tsx +++ b/src/components/HrTools/SalaryCalculator/Shared/getLocalizedTaxStatus.test.tsx @@ -1,4 +1,4 @@ -import { SecaStatusEnum } from 'pages/api/graphql-rest.page.generated'; +import { SecaStatusEnum } from 'src/graphql/types.generated'; import i18n from 'src/lib/i18n'; import { getLocalizedTaxStatus } from './getLocalizedTaxStatus'; diff --git a/src/components/HrTools/SalaryCalculator/Shared/getLocalizedTaxStatus.tsx b/src/components/HrTools/SalaryCalculator/Shared/getLocalizedTaxStatus.tsx index 9cac1c68f0..03b38a7eb5 100644 --- a/src/components/HrTools/SalaryCalculator/Shared/getLocalizedTaxStatus.tsx +++ b/src/components/HrTools/SalaryCalculator/Shared/getLocalizedTaxStatus.tsx @@ -1,5 +1,5 @@ import { TFunction } from 'react-i18next'; -import { SecaStatusEnum } from 'pages/api/graphql-rest.page.generated'; +import { SecaStatusEnum } from 'src/graphql/types.generated'; export const getLocalizedTaxStatus = ( status: SecaStatusEnum | null | undefined, From 950115f0b19d8f18cac060133c0a7cc39bd0dde0 Mon Sep 17 00:00:00 2001 From: Caleb Cox Date: Wed, 13 May 2026 15:49:46 -0500 Subject: [PATCH 6/7] Remove createdAt field --- .../AdditionalSalaryRequest/AdditionalSalaryRequest.graphql | 1 - .../AdditionalSalaryRequest/AdditionalSalaryRequest.test.tsx | 1 - .../SharedComponents/CurrentRequest.test.tsx | 1 - 3 files changed, 3 deletions(-) diff --git a/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.graphql b/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.graphql index 79bde211f8..62efd39fec 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.graphql +++ b/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.graphql @@ -63,7 +63,6 @@ query AdditionalSalaryRequest($isSpouse: Boolean) { isSpouse: $isSpouse ) { ...AdditionalSalaryRequestDetailsFields - createdAt } } diff --git a/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.test.tsx index 7faa9fabfb..384f687350 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/AdditionalSalaryRequest.test.tsx @@ -14,7 +14,6 @@ const accountListId = 'account-list-1'; const mockRequest = { id: 'request-1', - createdAt: '2024-01-01T00:00:00Z', status: AsrStatusEnum.InProgress, totalAdditionalSalaryRequested: 5000, currentYearSalaryNotReceived: 1000, diff --git a/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/CurrentRequest.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/CurrentRequest.test.tsx index f3d8afcd32..2b7a1d9662 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/CurrentRequest.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/SharedComponents/CurrentRequest.test.tsx @@ -30,7 +30,6 @@ const mockHandleDeleteRequest = jest.fn(); const mockRequest: RequestType = { id: 'request-123', - createdAt: '2025-06-01T00:00:00.000Z', totalAdditionalSalaryRequested: 5000, usingSpouseSalary: false, approvedAt: null, From 6e84c1522a3ab6600553d18a63b4fa0fd5852a61 Mon Sep 17 00:00:00 2001 From: Caleb Cox Date: Thu, 14 May 2026 09:16:51 -0500 Subject: [PATCH 7/7] Fix specs --- .../useAdditionalSalaryRequestForm.test.tsx | 107 ++++++++++++------ .../Shared/useAdditionalSalaryRequestForm.ts | 4 +- 2 files changed, 75 insertions(+), 36 deletions(-) diff --git a/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.test.tsx b/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.test.tsx index 2e2d771b16..6fe94de6fa 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.test.tsx +++ b/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.test.tsx @@ -1,14 +1,22 @@ import { ThemeProvider } from '@mui/material/styles'; import { act, renderHook, waitFor } from '@testing-library/react'; import { DeepPartial } from 'ts-essentials'; -import { GqlMockedProvider } from '__tests__/util/graphqlMocking'; +import { GqlMockedProvider, gqlMock } from '__tests__/util/graphqlMocking'; import { PageEnum } from 'src/components/HrTools/Shared/CalculationReports/Shared/sharedTypes'; -import { HcmQuery } from 'src/components/HrTools/Shared/HcmData/Hcm.generated'; -import { ElectionType403bEnum } from 'src/graphql/types.generated'; +import { + HcmDocument, + HcmQuery, +} from 'src/components/HrTools/Shared/HcmData/Hcm.generated'; +import { + ElectionType403bEnum, + ProgressiveApprovalTierReasonEnum, +} from 'src/graphql/types.generated'; import i18n from 'src/lib/i18n'; import theme from 'src/theme'; import { CompleteFormValues } from '../AdditionalSalaryRequest'; import { + AdditionalSalaryRequestDetailsFieldsFragment, + AdditionalSalaryRequestDetailsFieldsFragmentDoc, AdditionalSalaryRequestQuery, SubmitAdditionalSalaryRequestMutation, UpdateAdditionalSalaryRequestMutation, @@ -39,7 +47,7 @@ const mockUseAdditionalSalaryRequest = const mockHandleNextStep = jest.fn(); -const defaultMockContextValue: AdditionalSalaryRequestType = { +const defaultMockContextValue = { staffAccountId: 'staff-account-1', staffAccountIdLoading: false, steps: [], @@ -51,16 +59,21 @@ const defaultMockContextValue: AdditionalSalaryRequestType = { isDrawerOpen: true, toggleDrawer: jest.fn(), requestData: { - latestAdditionalSalaryRequest: { - phoneNumber: '555-123-4567', - traditional403bContribution: 0.12, - calculations: { - currentSalaryCap: 100000, - staffAccountBalance: 50000, - pendingAsrAmount: 0, - }, - }, - } as unknown as AdditionalSalaryRequestQuery, + latestAdditionalSalaryRequest: + gqlMock( + AdditionalSalaryRequestDetailsFieldsFragmentDoc, + { + mocks: { + phoneNumber: '555-123-4567', + calculations: { + currentSalaryCap: 100000, + staffAccountBalance: 50000, + pendingAsrAmount: 0, + }, + }, + }, + ), + }, loading: false, requestError: undefined, pageType: PageEnum.New, @@ -69,19 +82,21 @@ const defaultMockContextValue: AdditionalSalaryRequestType = { setPendingPrint: jest.fn(), handleDeleteRequest: jest.fn(), requestId: 'test-request-id', - user: { - staffInfo: { - id: 'staff-1', - firstName: 'John', - lastName: 'Doe', - preferredName: 'Doe, John', - personNumber: '00123456', - emailAddress: 'john.doe@example.com', - }, - currentSalary: { - grossSalaryAmount: 40000, + user: gqlMock(HcmDocument, { + mocks: { + staffInfo: { + id: 'staff-1', + firstName: 'John', + lastName: 'Doe', + preferredName: 'Doe, John', + personNumber: '00123456', + emailAddress: 'john.doe@example.com', + }, + currentSalary: { + grossSalaryAmount: 40000, + }, }, - } as unknown as HcmQuery['hcm'][0], + }).hcm[0], spouse: undefined, salaryInfo: { id: '1', @@ -106,7 +121,7 @@ const defaultMockContextValue: AdditionalSalaryRequestType = { isPending: false, isApproved: false, fieldConfig, -}; +} satisfies AdditionalSalaryRequestType; const defaultFormValues: CompleteFormValues = { currentYearSalaryNotReceived: '0', @@ -304,9 +319,16 @@ describe('useAdditionalSalaryRequestForm', () => { describe('validation', () => { it('should require phone number', async () => { - const { result } = renderHook(() => useAdditionalSalaryRequestForm(), { - wrapper: TestWrapper, - }); + const { result } = renderHook( + () => + useAdditionalSalaryRequestForm({ + ...defaultFormValues, + phoneNumber: '', + }), + { + wrapper: TestWrapper, + }, + ); let errors: Record = {}; await act(async () => { @@ -488,10 +510,6 @@ describe('useAdditionalSalaryRequestForm', () => { }); it('should not require additional info when exceedsCap is true and user has board cap exception', async () => { - mockUseAdditionalSalaryRequest.mockReturnValue({ - ...defaultMockContextValue, - }); - const { result } = renderHook( () => useAdditionalSalaryRequestForm({ @@ -500,10 +518,29 @@ describe('useAdditionalSalaryRequestForm', () => { additionalSalaryWithinMax: '70000', }), { - wrapper: TestWrapper, + wrapper: ({ children }) => ( + + {children as React.ReactElement} + + ), }, ); + await waitFor(() => { + expect(mutationSpy).toHaveGraphqlOperation('AdditionalSalaryRequest'); + }); + let errors: Record = {}; await act(async () => { errors = await result.current.validateForm(); diff --git a/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.ts b/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.ts index f359e5126d..e4014d2653 100644 --- a/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.ts +++ b/src/components/HrTools/AdditionalSalaryRequest/Shared/useAdditionalSalaryRequestForm.ts @@ -5,6 +5,7 @@ import * as yup from 'yup'; import { AsrStatusEnum, ElectionType403bEnum, + ProgressiveApprovalTierReasonEnum, } from 'src/graphql/types.generated'; import { useLocale } from 'src/hooks/useLocale'; import i18n from 'src/lib/i18n'; @@ -162,7 +163,8 @@ export const useAdditionalSalaryRequestForm = ( function (value) { if ( requestData?.latestAdditionalSalaryRequest - ?.progressiveApprovalTier + ?.progressiveApprovalTierReason === + ProgressiveApprovalTierReasonEnum.BoardCapException ) { return true; }