From ba3bcea824aa0082085475cb1e7991910201db20 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Thu, 4 Dec 2025 13:30:14 -0500
Subject: [PATCH 01/36] Added delete mutation to mha
---
.../MinisterHousingAllowance.graphql | 8 +++
.../SharedComponents/CurrentRequest.test.tsx | 62 ++++++++++++++++---
.../SharedComponents/CurrentRequest.tsx | 24 ++++++-
3 files changed, 84 insertions(+), 10 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
index 4b1afe4107..ce656a2df9 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
@@ -125,3 +125,11 @@ mutation UpdateMinistryHousingAllowanceRequest(
}
}
}
+
+mutation DeleteMinistryHousingAllowanceRequest(
+ $input: MinistryHousingAllowanceRequestDeleteMutationInput!
+) {
+ deleteMinistryHousingAllowanceRequest(input: $input) {
+ id
+ }
+}
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx
index 2f4f93181d..f45c815164 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx
@@ -1,24 +1,43 @@
import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
-import { render } from '@testing-library/react';
+import { render, waitFor } from '@testing-library/react';
+import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { MhaStatusEnum } from 'src/graphql/types.generated';
import theme from 'src/theme';
-import { MinisterHousingAllowanceProvider } from '../Shared/Context/MinisterHousingAllowanceContext';
+import { DeleteMinistryHousingAllowanceRequestMutation } from '../MinisterHousingAllowance.generated';
+import {
+ ContextType,
+ MinisterHousingAllowanceContext,
+} from '../Shared/Context/MinisterHousingAllowanceContext';
import { mockMHARequest } from '../mockData';
import { CurrentRequest, getDotColor, getDotVariant } from './CurrentRequest';
+const mutationSpy = jest.fn();
+
const TestComponent: React.FC = () => {
return (
-
-
-
-
-
-
-
+
+
+ onCall={mutationSpy}
+ >
+
+
+
+
+
+
+
);
};
@@ -42,6 +61,31 @@ describe('CurrentRequest Component', () => {
expect(getByText(/MHA Available on/i)).toBeInTheDocument();
expect(getByText(/Nov 20, 2019/i)).toBeInTheDocument();
});
+
+ it('should call delete mutation on cancel request', async () => {
+ const { getByText, findByText } = render( );
+
+ const cancelButton = getByText('Cancel Request');
+ cancelButton.click();
+
+ const confirmButton = await findByText('Yes, Cancel');
+ confirmButton.click();
+
+ await waitFor(() => {
+ expect(mutationSpy).toHaveBeenCalledWith(
+ expect.objectContaining({
+ operation: expect.objectContaining({
+ operationName: 'DeleteMinistryHousingAllowanceRequest',
+ variables: {
+ input: {
+ requestId: 'request-id',
+ },
+ },
+ }),
+ }),
+ );
+ });
+ });
});
describe('getDotColor', () => {
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
index ddf815390e..cf276f88bb 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
@@ -9,12 +9,14 @@ import {
} from '@mui/lab';
import { Box, Typography } from '@mui/material';
import { DateTime } from 'luxon';
+import { useSnackbar } from 'notistack';
import { useTranslation } from 'react-i18next';
import { MhaStatusEnum } from 'src/graphql/types.generated';
import { useAccountListId } from 'src/hooks/useAccountListId';
import { useLocale } from 'src/hooks/useLocale';
import { currencyFormat, dateFormat } from 'src/lib/intlFormat';
import { StatusCard } from '../../Shared/CalculationReports/StatusCard/StatusCard';
+import { useDeleteMinistryHousingAllowanceRequestMutation } from '../MinisterHousingAllowance.generated';
import { useMinisterHousingAllowance } from '../Shared/Context/MinisterHousingAllowanceContext';
import { MHARequest } from './types';
@@ -27,6 +29,7 @@ export const CurrentRequest: React.FC = ({ request }) => {
const locale = useLocale();
const accountListId = useAccountListId();
const currency = 'USD';
+ const { enqueueSnackbar } = useSnackbar();
const { requestId } = useMinisterHousingAllowance();
@@ -40,6 +43,25 @@ export const CurrentRequest: React.FC = ({ request }) => {
approvedOverallAmount,
} = requestAttributes || {};
+ const [deleteRequestMutation] =
+ useDeleteMinistryHousingAllowanceRequestMutation();
+
+ const handleCancelRequest = async () => {
+ try {
+ await deleteRequestMutation({
+ variables: {
+ input: {
+ requestId: requestId ?? '',
+ },
+ },
+ });
+ } catch (error) {
+ enqueueSnackbar(t('Failed to cancel your MHA request.'), {
+ variant: 'error',
+ });
+ }
+ };
+
return (
= ({ request }) => {
linkTwoText={t('Edit Request')}
linkTwo={`/accountLists/${accountListId}/reports/housingAllowance/${requestId}/edit`}
isRequest={true}
- handleConfirmCancel={() => {}}
+ handleConfirmCancel={handleCancelRequest}
>
From d0a5190c4251a3b03a7c1885f0ab1f2c16f35086 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Fri, 5 Dec 2025 14:19:42 -0500
Subject: [PATCH 02/36] Added submit mutation to mha
---
.../MinisterHousingAllowance.graphql | 25 +++++++++++++
.../CalcComponents/CostOfHome.test.tsx | 2 +-
.../Steps/StepThree/Calculation.test.tsx | 35 ++++++++++++++++---
.../Steps/StepThree/Calculation.tsx | 6 ++++
4 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
index ce656a2df9..26e74efbc2 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
@@ -133,3 +133,28 @@ mutation DeleteMinistryHousingAllowanceRequest(
id
}
}
+
+mutation SubmitMinistryHousingAllowanceRequest(
+ $input: MinistryHousingAllowanceRequestSubmitMutationInput!
+) {
+ submitMinistryHousingAllowanceRequest(input: $input) {
+ ministryHousingAllowanceRequest {
+ requestAttributes {
+ rentOrOwn
+ rentalValue
+ furnitureCostsOne
+ avgUtilityOne
+ mortgageOrRentPayment
+ furnitureCostsTwo
+ repairCosts
+ avgUtilityTwo
+ unexpectedExpenses
+ overallAmount
+ phoneNumber
+ emailAddress
+ iUnderstandMhaPolicy
+ submittedDate
+ }
+ }
+ }
+}
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx
index 6274decc61..5f55c740cd 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx
@@ -119,7 +119,7 @@ describe('CostOfHome', () => {
furnitureCostsTwo: null,
repairCosts: null,
avgUtilityTwo: null,
- unexpectedCosts: null,
+ unexpectedExpenses: null,
},
},
} as unknown as ContextType
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
index 1f7cac50b1..d6a976a224 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
@@ -10,7 +10,10 @@ import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
import { MhaRentOrOwnEnum } from 'src/graphql/types.generated';
import theme from 'src/theme';
-import { UpdateMinistryHousingAllowanceRequestMutation } from '../../MinisterHousingAllowance.generated';
+import {
+ SubmitMinistryHousingAllowanceRequestMutation,
+ UpdateMinistryHousingAllowanceRequestMutation,
+} from '../../MinisterHousingAllowance.generated';
import {
ContextType,
MinisterHousingAllowanceContext,
@@ -22,6 +25,7 @@ const mutationSpy = jest.fn();
const setHasCalcValues = jest.fn();
const setIsPrint = jest.fn();
const updateMutation = jest.fn();
+const handleNextStep = jest.fn();
interface TestComponentProps {
contextValue: Partial;
@@ -41,6 +45,7 @@ const TestComponent: React.FC = ({
onCall={mutationSpy}
>
@@ -101,7 +106,7 @@ describe('Calculation', () => {
requestData: {
id: 'request-id',
requestAttributes: {
- unexpectedCosts: null,
+ unexpectedExpenses: null,
},
},
} as unknown as ContextType
@@ -163,7 +168,7 @@ describe('Calculation', () => {
).toBeInTheDocument();
});
- it('shows validation errors when inputs are invalid', async () => {
+ it('shows validation errors when email and phone are invalid', async () => {
const { getByRole, findByText } = render(
{
setHasCalcValues,
setIsPrint,
updateMutation,
+ handleNextStep,
requestData: {
id: 'request-id',
requestAttributes: {
@@ -222,7 +228,7 @@ describe('Calculation', () => {
furnitureValue: null,
repairCosts: null,
utilityCosts: null,
- unexpectedCosts: null,
+ unexpectedExpenses: null,
iUnderstandMhaPolicy: false,
phoneNumber: '1234567890',
emailAddress: 'john.doe@cru.org',
@@ -285,6 +291,27 @@ describe('Calculation', () => {
expect(getByRole('button', { name: /go back/i })).toBeInTheDocument();
expect(getByRole('button', { name: /yes, continue/i })).toBeInTheDocument();
+
+ expect(mutationSpy).not.toHaveGraphqlOperation(
+ 'SubmitMinistryHousingAllowanceRequest',
+ );
+
+ const confirmButton = getByRole('button', { name: /yes, continue/i });
+
+ await userEvent.click(confirmButton);
+
+ await waitFor(() => {
+ expect(mutationSpy).toHaveBeenCalledTimes(6);
+ });
+
+ expect(mutationSpy).toHaveGraphqlOperation(
+ 'SubmitMinistryHousingAllowanceRequest',
+ {
+ input: {
+ requestId: 'request-id',
+ },
+ },
+ );
});
it('should change text when dates are null', () => {
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
index 38db49edd8..6cc77a660c 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
@@ -27,6 +27,7 @@ import { useLocale } from 'src/hooks/useLocale';
import i18n from 'src/lib/i18n';
import { dateFormatShort } from 'src/lib/intlFormat';
import { DirectionButtons } from '../../../Shared/CalculationReports/DirectionButtons/DirectionButtons';
+import { useSubmitMinistryHousingAllowanceRequestMutation } from '../../MinisterHousingAllowance.generated';
import { hasPopulatedValues } from '../../Shared/Context/Helper/hasPopulatedValues';
import { useMinisterHousingAllowance } from '../../Shared/Context/MinisterHousingAllowanceContext';
import { CostOfHome } from './CalcComponents/CostOfHome';
@@ -109,6 +110,8 @@ export const Calculation: React.FC = ({
const { query } = useRouter();
const print = query.print === 'true';
+ const [submitMutation] = useSubmitMinistryHousingAllowanceRequestMutation();
+
const {
handleNextStep,
handlePreviousStep,
@@ -204,6 +207,9 @@ export const Calculation: React.FC = ({
validateOnChange
validateOnBlur
onSubmit={() => {
+ submitMutation({
+ variables: { input: { requestId: requestData?.id ?? '' } },
+ });
handleNextStep();
}}
>
From fec8fdf1e8a217142be69adeb393ebf47a80813b Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Mon, 8 Dec 2025 08:59:29 -0500
Subject: [PATCH 03/36] Updated current board approved card design
---
.../MainPages/EligibleDisplay.tsx | 5 +-
.../MainPages/IneligibleDisplay.tsx | 11 +-
.../MinisterHousingAllowance.graphql | 2 +
.../MinisterHousingAllowance.tsx | 1 +
.../CurrentBoardApproved.test.tsx | 37 ++-
.../SharedComponents/CurrentBoardApproved.tsx | 242 +++++++++++++-----
.../StatusCard/StatusCard.tsx | 12 +-
7 files changed, 216 insertions(+), 94 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/MainPages/EligibleDisplay.tsx b/src/components/Reports/MinisterHousingAllowance/MainPages/EligibleDisplay.tsx
index b1ea0ab5a9..121ec8c478 100644
--- a/src/components/Reports/MinisterHousingAllowance/MainPages/EligibleDisplay.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/MainPages/EligibleDisplay.tsx
@@ -30,9 +30,8 @@ export const EligibleDisplay: React.FC = ({
Our records indicate that you have an approved MHA amount. To view
your MHA amount, click on the "View Current MHA" button
- below. If you would like to apply for a new MHA, click on the
- "Duplicate Last Year's MHA" button below or
- "Request New MHA" below.
+ below. If you would like to apply for a new MHA, click
+ "Update Current MHA".
)}
diff --git a/src/components/Reports/MinisterHousingAllowance/MainPages/IneligibleDisplay.tsx b/src/components/Reports/MinisterHousingAllowance/MainPages/IneligibleDisplay.tsx
index f33e8031f8..55515dc0cd 100644
--- a/src/components/Reports/MinisterHousingAllowance/MainPages/IneligibleDisplay.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/MainPages/IneligibleDisplay.tsx
@@ -34,10 +34,13 @@ export const IneligibleDisplay: React.FC = () => {
Completing a Minister's Housing Allowance will submit the
request for {preferredName}. {spousePreferredName} has not
completed the required IBS courses to meet eligibility criteria.
- When you calculate your salary, you will see the approved amount
- that can be applied to {preferredName}'s salary. If you
- believe this is incorrect, please contact Personnel Records at
- 407-826-2252 or MHA@cru.org .
+
+
+ Once approved, when you calculate your salary, you will see the
+ approved amount that can be applied to {preferredName}'s
+ salary. If you believe this is incorrect, please contact
+ Personnel Records at 407-826-2252 or{' '}
+ MHA@cru.org .
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
index 26e74efbc2..0b6dc22df4 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
@@ -3,6 +3,7 @@ query MinistryHousingAllowanceRequests {
nodes {
id
personNumber
+ updatedAt
requestAttributes {
rentOrOwn
rentalValue
@@ -42,6 +43,7 @@ query MinistryHousingAllowanceRequest($ministryHousingAllowanceRequestId: ID!) {
ministryHousingAllowanceRequest(id: $ministryHousingAllowanceRequestId) {
id
personNumber
+ updatedAt
requestAttributes {
rentOrOwn
rentalValue
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
index 27df5bf7b1..9cf9c87653 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
@@ -103,6 +103,7 @@ export const MinisterHousingAllowanceReport = () => {
request.status === MhaStatusEnum.BoardApproved &&
isCurrentRequestPending,
);
+
return (
= ({ contextValue }) => {
const approvedMHARequest = {
...mockMHARequest,
+ updatedAt: '2022-12-01',
requestAttributes: {
...mockMHARequest.requestAttributes,
approvedDate: '2023-01-15',
@@ -42,7 +43,7 @@ const TestComponent: React.FC = ({ contextValue }) => {
describe('CurrentBoardApproved Component', () => {
it('should render correctly for married person', () => {
- const { getByText } = render(
+ const { getByText, getByRole, getAllByText } = render(
{
);
expect(getByText('Current Board Approved MHA')).toBeInTheDocument();
- expect(getByText(/APPROVAL DATE/i)).toBeInTheDocument();
- expect(getByText(/1\/15\/2023/i)).toBeInTheDocument();
- expect(getByText('CURRENT MHA CLAIMED')).toBeInTheDocument();
+ expect(getByRole('columnheader', { name: /spouse/i })).toBeInTheDocument();
+ expect(
+ getByRole('columnheader', { name: /mha approved by board/i }),
+ ).toBeInTheDocument();
+ expect(
+ getByRole('columnheader', { name: /mha claimed in salary/i }),
+ ).toBeInTheDocument();
- expect(getByText('$1,500.00')).toBeInTheDocument();
- expect(getByText('John')).toBeInTheDocument();
+ expect(getByRole('cell', { name: 'John' })).toBeInTheDocument();
+ expect(getAllByText('$1,500.00')).toHaveLength(2);
+ expect(getAllByText('Approved on: 1/15/2023')).toHaveLength(2);
expect(getByText('$1,000.00')).toBeInTheDocument();
- expect(getByText('Jane')).toBeInTheDocument();
+ expect(getAllByText('Last updated: 12/1/2022')).toHaveLength(2);
+
+ expect(getByRole('cell', { name: 'Jane' })).toBeInTheDocument();
expect(getByText('$500.00')).toBeInTheDocument();
});
it('should render correctly for single person', () => {
- const { getByText, queryByText } = render(
+ const { getByText, queryByText, getByRole, getAllByText } = render(
{
);
expect(getByText('Current Board Approved MHA')).toBeInTheDocument();
- expect(getByText(/APPROVAL DATE/i)).toBeInTheDocument();
- expect(getByText('CURRENT MHA CLAIMED')).toBeInTheDocument();
+ expect(getByRole('columnheader', { name: /spouse/i })).toBeInTheDocument();
+ expect(
+ getByRole('columnheader', { name: /mha approved by board/i }),
+ ).toBeInTheDocument();
+ expect(
+ getByRole('columnheader', { name: /mha claimed in salary/i }),
+ ).toBeInTheDocument();
- expect(getByText('$1,500.00')).toBeInTheDocument();
- expect(getByText('John')).toBeInTheDocument();
+ expect(getByRole('cell', { name: 'John' })).toBeInTheDocument();
+ expect(getAllByText('$1,500.00')).toHaveLength(1);
expect(getByText('$1,000.00')).toBeInTheDocument();
// Spouse data should not be rendered
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
index 7f32697df2..85b835b188 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
@@ -1,5 +1,15 @@
import { HomeSharp } from '@mui/icons-material';
-import { Grid, Skeleton, Typography } from '@mui/material';
+import {
+ Grid,
+ Skeleton,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow,
+ Typography,
+} from '@mui/material';
import { DateTime } from 'luxon';
import { useTranslation } from 'react-i18next';
import { useAccountListId } from 'src/hooks/useAccountListId';
@@ -27,89 +37,179 @@ export const CurrentBoardApproved: React.FC = ({
const { approvedDate, approvedOverallAmount, staffSpecific, spouseSpecific } =
request?.requestAttributes || {};
+ const lastUpdated = request?.updatedAt ?? null;
+
return (
{}}
+ styling={{ p: 0 }}
>
-
-
-
- {t('APPROVAL DATE')}:{' '}
- {approvedDate ? (
- dateFormatShort(DateTime.fromISO(approvedDate), locale)
- ) : (
-
+
+
+
+
+
+ {t('Spouse')}
+
+
+ {t('MHA Approved by Board')}
+
+
+ {t('MHA Claimed in Salary')}
+
+
+
+
+
+ {preferredName}
+
+
+
+
+ {currencyFormat(approvedOverallAmount, currency, locale, {
+ showTrailingZeros: true,
+ })}
+
+
+
+
+ {t('Approved on')}:{' '}
+ {approvedDate ? (
+ dateFormatShort(DateTime.fromISO(approvedDate), locale)
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+ {currencyFormat(staffSpecific, currency, locale, {
+ showTrailingZeros: true,
+ })}
+
+
+
+
+ {t('Last updated')}:{' '}
+ {lastUpdated ? (
+ dateFormatShort(DateTime.fromISO(lastUpdated), locale)
+ ) : (
+
+ )}
+
+
+
+
+
+ {isMarried && (
+
+
+ {spousePreferredName}
+
+
+
+
+
+ {currencyFormat(
+ approvedOverallAmount,
+ currency,
+ locale,
+ {
+ showTrailingZeros: true,
+ },
+ )}
+
+
+
+
+ {t('Approved on')}:{' '}
+ {approvedDate ? (
+ dateFormatShort(
+ DateTime.fromISO(approvedDate),
+ locale,
+ )
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+ {currencyFormat(spouseSpecific, currency, locale, {
+ showTrailingZeros: true,
+ })}
+
+
+
+
+ {t('Last updated')}:{' '}
+ {lastUpdated ? (
+ dateFormatShort(DateTime.fromISO(lastUpdated), locale)
+ ) : (
+
+ )}
+
+
+
+
+
)}
-
-
-
-
- {t('CURRENT MHA CLAIMED')}
-
-
-
-
-
-
- {currencyFormat(approvedOverallAmount || 0, currency, locale, {
- showTrailingZeros: true,
- })}
-
-
-
-
-
- {preferredName}
-
-
- {isMarried && (
- {spousePreferredName}
- )}
-
-
-
-
-
- {currencyFormat(staffSpecific ?? 0, currency, locale, {
- showTrailingZeros: true,
- })}
-
-
-
- {isMarried && (
-
- {currencyFormat(spouseSpecific ?? 0, currency, locale, {
- showTrailingZeros: true,
- })}
-
- )}
-
-
-
-
+
+
+
);
};
diff --git a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
index b4d7df9ab7..9baa2fc596 100644
--- a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
+++ b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
@@ -11,6 +11,8 @@ import {
CardHeader,
Divider,
IconButton,
+ SxProps,
+ Theme,
Typography,
} from '@mui/material';
import { useTranslation } from 'react-i18next';
@@ -35,6 +37,7 @@ interface StatusCardProps {
hideActions?: boolean;
handleDownload?: () => void;
handleConfirmCancel: () => void;
+ styling?: SxProps;
}
export const StatusCard: React.FC = ({
@@ -53,6 +56,7 @@ export const StatusCard: React.FC = ({
hideActions,
handleDownload,
handleConfirmCancel,
+ styling,
}) => {
const { t } = useTranslation();
@@ -73,14 +77,14 @@ export const StatusCard: React.FC = ({
{subtitle ? (
-
+
{title}
@@ -102,7 +106,7 @@ export const StatusCard: React.FC = ({
}
/>
- {children}
+ {children}
{!hideActions && (
@@ -117,7 +121,7 @@ export const StatusCard: React.FC = ({
{linkTwoText}
From 881cab75c44353582aadb243def5b08ce9c6e455 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Mon, 8 Dec 2025 09:02:28 -0500
Subject: [PATCH 04/36] Added updatedAt to mock data
---
src/components/Reports/MinisterHousingAllowance/mockData.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/components/Reports/MinisterHousingAllowance/mockData.ts b/src/components/Reports/MinisterHousingAllowance/mockData.ts
index acbefe99c3..8f31da3bc2 100644
--- a/src/components/Reports/MinisterHousingAllowance/mockData.ts
+++ b/src/components/Reports/MinisterHousingAllowance/mockData.ts
@@ -4,6 +4,7 @@ import { MHARequest } from './SharedComponents/types';
export const mockMHARequest: MHARequest = {
id: '1',
personNumber: '123456',
+ updatedAt: '2019-09-15T12:00:00.000Z',
status: MhaStatusEnum.Pending,
feedback: null,
user: {
From b0a30fb653c9f490b8c427518c265dca5cd40358 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Mon, 8 Dec 2025 09:24:30 -0500
Subject: [PATCH 05/36] Updated UI based on new designs
---
.../Steps/StepOne/AboutForm.tsx | 2 +-
.../StepThree/CalcComponents/CostOfHome.test.tsx | 10 +++++-----
.../Steps/StepThree/CalcComponents/CostOfHome.tsx | 10 +++++-----
.../CalcComponents/FairRentalValue.test.tsx | 6 +++---
.../StepThree/CalcComponents/FairRentalValue.tsx | 6 +++---
.../Steps/StepThree/Calculation.test.tsx | 12 ++++++------
6 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.tsx
index 4af3d18f93..f9906285f5 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.tsx
@@ -72,7 +72,7 @@ export const AboutForm: React.FC = ({
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx
index 5f55c740cd..91ad607c0a 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx
@@ -130,25 +130,25 @@ describe('CostOfHome', () => {
const row1 = getByRole('row', {
name: /monthly rent/i,
});
- const input1 = within(row1).getByPlaceholderText(/enter amount/i);
+ const input1 = within(row1).getByPlaceholderText(/\$0/i);
const row2 = getByRole('row', { name: /monthly value for furniture/i });
- const input2 = within(row2).getByPlaceholderText(/enter amount/i);
+ const input2 = within(row2).getByPlaceholderText(/\$0/i);
const row3 = getByRole('row', {
name: /estimated monthly cost of repairs/i,
});
- const input3 = within(row3).getByPlaceholderText(/enter amount/i);
+ const input3 = within(row3).getByPlaceholderText(/\$0/i);
const row4 = getByRole('row', {
name: /average monthly utility costs/i,
});
- const input4 = within(row4).getByPlaceholderText(/enter amount/i);
+ const input4 = within(row4).getByPlaceholderText(/\$0/i);
const row5 = getByRole('row', {
name: /average monthly amount for unexpected/i,
});
- const input5 = within(row5).getByPlaceholderText(/enter amount/i);
+ const input5 = within(row5).getByPlaceholderText(/\$0/i);
await userEvent.type(input1, '1000');
userEvent.tab();
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.tsx
index 3dfb4bddf6..6937a67a1a 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.tsx
@@ -56,7 +56,7 @@ export const CostOfHome: React.FC = ({
fullWidth
size="small"
variant="standard"
- placeholder={t('Enter Amount')}
+ placeholder={t('$0')}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="mortgageOrRentPayment"
schema={schema}
@@ -87,7 +87,7 @@ export const CostOfHome: React.FC = ({
fullWidth
size="small"
variant="standard"
- placeholder={t('Enter Amount')}
+ placeholder={t('$0')}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="furnitureCostsTwo"
schema={schema}
@@ -116,7 +116,7 @@ export const CostOfHome: React.FC = ({
fullWidth
size="small"
variant="standard"
- placeholder={t('Enter Amount')}
+ placeholder={t('$0')}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="repairCosts"
schema={schema}
@@ -150,7 +150,7 @@ export const CostOfHome: React.FC = ({
fullWidth
size="small"
variant="standard"
- placeholder={t('Enter Amount')}
+ placeholder={t('$0')}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="avgUtilityTwo"
schema={schema}
@@ -179,7 +179,7 @@ export const CostOfHome: React.FC = ({
fullWidth
size="small"
variant="standard"
- placeholder={t('Enter Amount')}
+ placeholder={t('$0')}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="unexpectedExpenses"
schema={schema}
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.test.tsx
index a7266717b2..9ffc477787 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.test.tsx
@@ -95,15 +95,15 @@ describe('FairRentalValue', () => {
const row1 = getByRole('row', {
name: /monthly market rental value of your home/i,
});
- const input1 = within(row1).getByPlaceholderText(/enter amount/i);
+ const input1 = within(row1).getByPlaceholderText(/\$0/i);
const row2 = getByRole('row', { name: /monthly value for furniture/i });
- const input2 = within(row2).getByPlaceholderText(/enter amount/i);
+ const input2 = within(row2).getByPlaceholderText(/\$0/i);
const row3 = getByRole('row', {
name: /average monthly utility costs/i,
});
- const input3 = within(row3).getByPlaceholderText(/enter amount/i);
+ const input3 = within(row3).getByPlaceholderText(/\$0/i);
await userEvent.type(input1, '1000');
await userEvent.type(input2, '200');
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.tsx
index 8aff485713..443bac6eb3 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.tsx
@@ -54,7 +54,7 @@ export const FairRentalValue: React.FC = ({ schema }) => {
fullWidth
size="small"
variant="standard"
- placeholder={t('Enter Amount')}
+ placeholder={t('$0')}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="rentalValue"
schema={schema}
@@ -91,7 +91,7 @@ export const FairRentalValue: React.FC = ({ schema }) => {
fullWidth
size="small"
variant="standard"
- placeholder={t('Enter Amount')}
+ placeholder={t('$0')}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="furnitureCostsOne"
schema={schema}
@@ -120,7 +120,7 @@ export const FairRentalValue: React.FC = ({ schema }) => {
fullWidth
size="small"
variant="standard"
- placeholder={t('Enter Amount')}
+ placeholder={t('$0')}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="avgUtilityOne"
schema={schema}
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
index d6a976a224..205733028c 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
@@ -117,7 +117,7 @@ describe('Calculation', () => {
const row = getByRole('row', {
name: /average monthly amount for unexpected/i,
});
- const input = within(row).getByPlaceholderText(/enter amount/i);
+ const input = within(row).getByPlaceholderText(/\$0/i);
await userEvent.type(input, '100');
expect(input).toHaveValue('100');
@@ -243,25 +243,25 @@ describe('Calculation', () => {
const row1 = getByRole('row', {
name: /monthly rent/i,
});
- const input1 = within(row1).getByPlaceholderText(/enter amount/i);
+ const input1 = within(row1).getByPlaceholderText(/\$0/i);
const row2 = getByRole('row', { name: /monthly value for furniture/i });
- const input2 = within(row2).getByPlaceholderText(/enter amount/i);
+ const input2 = within(row2).getByPlaceholderText(/\$0/i);
const row3 = getByRole('row', {
name: /estimated monthly cost of repairs/i,
});
- const input3 = within(row3).getByPlaceholderText(/enter amount/i);
+ const input3 = within(row3).getByPlaceholderText(/\$0/i);
const row4 = getByRole('row', {
name: /average monthly utility costs/i,
});
- const input4 = within(row4).getByPlaceholderText(/enter amount/i);
+ const input4 = within(row4).getByPlaceholderText(/\$0/i);
const row5 = getByRole('row', {
name: /average monthly amount for unexpected/i,
});
- const input5 = within(row5).getByPlaceholderText(/enter amount/i);
+ const input5 = within(row5).getByPlaceholderText(/\$0/i);
await userEvent.type(input1, '1000');
await userEvent.type(input2, '200');
From 7693cd853ecc808203d51a06121456ecc24cf775 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Mon, 8 Dec 2025 10:33:02 -0500
Subject: [PATCH 06/36] Added duplicate mutation to mha
---
.../MinisterHousingAllowance.graphql | 25 +++++
.../CurrentBoardApproved.test.tsx | 95 +++++++++++++++++--
.../SharedComponents/CurrentBoardApproved.tsx | 38 +++++++-
.../StatusCard/StatusCard.tsx | 7 +-
4 files changed, 155 insertions(+), 10 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
index 0b6dc22df4..54fbb8b09d 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
@@ -160,3 +160,28 @@ mutation SubmitMinistryHousingAllowanceRequest(
}
}
}
+
+mutation DuplicateMinistryHousingAllowanceRequest(
+ $input: DuplicateMinistryHousingAllowanceRequestMutationInput!
+) {
+ duplicateMinistryHousingAllowanceRequest(input: $input) {
+ ministryHousingAllowanceRequest {
+ id
+ requestAttributes {
+ rentOrOwn
+ rentalValue
+ furnitureCostsOne
+ avgUtilityOne
+ mortgageOrRentPayment
+ furnitureCostsTwo
+ repairCosts
+ avgUtilityTwo
+ unexpectedExpenses
+ overallAmount
+ phoneNumber
+ emailAddress
+ iUnderstandMhaPolicy
+ }
+ }
+ }
+}
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.test.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.test.tsx
index 4ddca140e1..fd1c2483d1 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.test.tsx
@@ -1,8 +1,11 @@
import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
-import { render } from '@testing-library/react';
+import { render, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
import TestRouter from '__tests__/util/TestRouter';
+import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import theme from 'src/theme';
+import { DuplicateMinistryHousingAllowanceRequestMutation } from '../MinisterHousingAllowance.generated';
import {
ContextType,
HcmData,
@@ -11,11 +14,21 @@ import {
import { mockMHARequest } from '../mockData';
import { CurrentBoardApproved } from './CurrentBoardApproved';
+const newRequestId = 'new-request-id';
+const mutationSpy = jest.fn();
+const mockPush = jest.fn();
interface TestComponentProps {
contextValue: Partial;
+ router?: {
+ push?: jest.Mock;
+ query?: { accountListId?: string };
+ };
}
-const TestComponent: React.FC = ({ contextValue }) => {
+const TestComponent: React.FC = ({
+ contextValue,
+ router = {},
+}) => {
const approvedMHARequest = {
...mockMHARequest,
updatedAt: '2022-12-01',
@@ -30,12 +43,18 @@ const TestComponent: React.FC = ({ contextValue }) => {
return (
-
-
+
+ onCall={mutationSpy}
>
-
-
+
+
+
+
);
@@ -115,4 +134,66 @@ describe('CurrentBoardApproved Component', () => {
// Spouse data should not be rendered
expect(queryByText('Jane')).not.toBeInTheDocument();
});
+
+ it('should navigate to edit page with new requestId after duplicate mutation', async () => {
+ const { getByText } = render(
+
+
+
+ mocks={{
+ DuplicateMinistryHousingAllowanceRequest: {
+ duplicateMinistryHousingAllowanceRequest: {
+ ministryHousingAllowanceRequest: {
+ id: newRequestId,
+ },
+ },
+ },
+ }}
+ onCall={mutationSpy}
+ >
+
+
+
+
+
+ ,
+ );
+
+ const updateButton = getByText('Update Current MHA');
+ userEvent.click(updateButton);
+
+ await waitFor(() => {
+ expect(mutationSpy).toHaveGraphqlOperation(
+ 'DuplicateMinistryHousingAllowanceRequest',
+ {
+ input: {
+ requestId: 'old-request-id',
+ },
+ },
+ );
+ });
+
+ await waitFor(() => {
+ expect(mockPush).toHaveBeenCalledWith(
+ `/accountLists/account-list-1/reports/housingAllowance/${newRequestId}/edit`,
+ );
+ });
+ });
});
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
index 85b835b188..75c89974e3 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
@@ -1,3 +1,4 @@
+import { useRouter } from 'next/router';
import { HomeSharp } from '@mui/icons-material';
import {
Grid,
@@ -16,6 +17,7 @@ import { useAccountListId } from 'src/hooks/useAccountListId';
import { useLocale } from 'src/hooks/useLocale';
import { currencyFormat, dateFormatShort } from 'src/lib/intlFormat';
import { StatusCard } from '../../Shared/CalculationReports/StatusCard/StatusCard';
+import { useDuplicateMinistryHousingAllowanceRequestMutation } from '../MinisterHousingAllowance.generated';
import { useMinisterHousingAllowance } from '../Shared/Context/MinisterHousingAllowanceContext';
import { MHARequest } from './types';
@@ -29,8 +31,16 @@ export const CurrentBoardApproved: React.FC = ({
const { t } = useTranslation();
const locale = useLocale();
const accountListId = useAccountListId();
+ const router = useRouter();
const currency = 'USD';
+ const [duplicateMHA] = useDuplicateMinistryHousingAllowanceRequestMutation({
+ refetchQueries: [
+ 'MinistryHousingAllowanceRequests',
+ 'MinistryHousingAllowanceRequest',
+ ],
+ });
+
const { isMarried, preferredName, spousePreferredName, requestId } =
useMinisterHousingAllowance();
@@ -39,6 +49,32 @@ export const CurrentBoardApproved: React.FC = ({
const lastUpdated = request?.updatedAt ?? null;
+ const handleDuplicateRequest = async () => {
+ if (!requestId) {
+ return;
+ }
+
+ try {
+ const result = await duplicateMHA({
+ variables: {
+ input: {
+ requestId: requestId,
+ },
+ },
+ });
+
+ const newRequestId =
+ result.data?.duplicateMinistryHousingAllowanceRequest
+ ?.ministryHousingAllowanceRequest?.id;
+
+ if (newRequestId) {
+ router.push(
+ `/accountLists/${accountListId}/reports/housingAllowance/${newRequestId}/edit`,
+ );
+ }
+ } catch (error) {}
+ };
+
return (
= ({
linkOneText={t('View Current MHA')}
linkOne={`/accountLists/${accountListId}/reports/housingAllowance/${requestId}/view`}
linkTwoText={t('Update Current MHA')}
- linkTwo=""
+ handleLinkTwo={handleDuplicateRequest}
isRequest={false}
handleConfirmCancel={() => {}}
styling={{ p: 0 }}
diff --git a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
index 9baa2fc596..be1a292d88 100644
--- a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
+++ b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
@@ -37,6 +37,7 @@ interface StatusCardProps {
hideActions?: boolean;
handleDownload?: () => void;
handleConfirmCancel: () => void;
+ handleLinkTwo?: () => void;
styling?: SxProps;
}
@@ -56,6 +57,7 @@ export const StatusCard: React.FC = ({
hideActions,
handleDownload,
handleConfirmCancel,
+ handleLinkTwo,
styling,
}) => {
const { t } = useTranslation();
@@ -119,8 +121,9 @@ export const StatusCard: React.FC = ({
{linkOneText}
From 7568156f83071aef9cf14e7615606f73bca3b3ae Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Tue, 9 Dec 2025 09:38:19 -0500
Subject: [PATCH 07/36] Added functionality to remember current step
---
.../AboutForm/AboutForm.tsx | 4 +-
.../CompleteForm/CompleteForm.tsx | 4 +-
.../AdditionalSalaryRequest/CurrentStep.tsx | 13 ++--
.../AdditionalSalaryRequestContext.test.tsx | 4 +-
.../Shared/AdditionalSalaryRequestContext.tsx | 62 +++++++------------
.../Shared/Helper/getHeader.ts | 14 ++---
.../EditRequest/EditRequestPage.test.tsx | 5 +-
.../EditRequest/EditRequestPage.tsx | 10 ++-
.../NewRequest/NewRequestPage.test.tsx | 3 +-
.../NewRequest/NewRequestPage.tsx | 10 ++-
.../MinisterHousingAllowanceContext.test.tsx | 25 ++++----
.../MinisterHousingAllowanceContext.tsx | 45 ++++++--------
.../CalcComponents/Helper/CustomTextField.tsx | 54 ----------------
.../CalcComponents/Helper/formatHelper.tsx | 30 ---------
.../Steps/StepThree/Calculation.test.tsx | 34 ++++++++++
.../Steps/StepThree/Calculation.tsx | 40 +++++++++---
.../Reports/SalaryCalculator/CurrentStep.tsx | 17 ++---
.../SalaryCalculatorContext.tsx | 57 ++++++++---------
src/hooks/useStepList.ts | 53 +++++++++++-----
19 files changed, 222 insertions(+), 262 deletions(-)
delete mode 100644 src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/Helper/CustomTextField.tsx
delete mode 100644 src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/Helper/formatHelper.tsx
diff --git a/src/components/Reports/AdditionalSalaryRequest/AboutForm/AboutForm.tsx b/src/components/Reports/AdditionalSalaryRequest/AboutForm/AboutForm.tsx
index 64f57dadc3..961b901a65 100644
--- a/src/components/Reports/AdditionalSalaryRequest/AboutForm/AboutForm.tsx
+++ b/src/components/Reports/AdditionalSalaryRequest/AboutForm/AboutForm.tsx
@@ -9,7 +9,7 @@ import { AdditionalSalaryRequestSection } from '../SharedComponents/AdditionalSa
import { SpouseComponent } from '../SharedComponents/SpouseComponent';
export const AboutForm: React.FC = () => {
- const { currentStep } = useAdditionalSalaryRequest();
+ const { currentIndex } = useAdditionalSalaryRequest();
const { t } = useTranslation();
const theme = useTheme();
@@ -20,7 +20,7 @@ export const AboutForm: React.FC = () => {
const remainingAllowableSalary = 17500.0;
return (
-
+
You can use this form to electronically submit additional salary
diff --git a/src/components/Reports/AdditionalSalaryRequest/CompleteForm/CompleteForm.tsx b/src/components/Reports/AdditionalSalaryRequest/CompleteForm/CompleteForm.tsx
index 2f78539bcf..0407f8e931 100644
--- a/src/components/Reports/AdditionalSalaryRequest/CompleteForm/CompleteForm.tsx
+++ b/src/components/Reports/AdditionalSalaryRequest/CompleteForm/CompleteForm.tsx
@@ -11,7 +11,7 @@ import { Deduction } from './Deduction/Deduction';
export const CompleteForm: React.FC = () => {
const { t } = useTranslation();
- const { currentStep } = useAdditionalSalaryRequest();
+ const { currentIndex } = useAdditionalSalaryRequest();
const theme = useTheme();
const name = 'Doc, John';
@@ -20,7 +20,7 @@ export const CompleteForm: React.FC = () => {
const remainingAllowableSalary = 17500.0;
return (
-
+
{
- const { currentStep } = useAdditionalSalaryRequest();
+ const { currentIndex } = useAdditionalSalaryRequest();
const { t } = useTranslation();
const accountListId = useAccountListId();
const pageLink = `/accountLists/${accountListId}/reports/additionalSalaryRequest`;
- switch (currentStep) {
- case AdditionalSalaryRequestSectionEnum.AboutForm:
+ switch (currentIndex) {
+ case 0:
return ;
- case AdditionalSalaryRequestSectionEnum.CompleteForm:
+ case 1:
return ;
- case AdditionalSalaryRequestSectionEnum.Receipt:
+ case 2:
return (
{
/>
);
+ default:
+ return null;
}
};
diff --git a/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.test.tsx b/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.test.tsx
index 6d4d476978..21d66fb800 100644
--- a/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.test.tsx
+++ b/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.test.tsx
@@ -7,13 +7,13 @@ import { useAdditionalSalaryRequest } from './AdditionalSalaryRequestContext';
import { getHeader } from './Helper/getHeader';
const TestComponent: React.FC = () => {
- const { currentStep, handleNextStep, isDrawerOpen, toggleDrawer } =
+ const { currentIndex, handleNextStep, isDrawerOpen, toggleDrawer } =
useAdditionalSalaryRequest();
const { t } = useTranslation();
return (
-
{getHeader(t, currentStep)}
+
{getHeader(t, currentIndex)}
Drawer: {isDrawerOpen ? 'open' : 'closed'}
diff --git a/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx b/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
index b41eff5345..85a3eaa863 100644
--- a/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
+++ b/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
@@ -1,4 +1,5 @@
import React, { createContext, useCallback, useMemo, useState } from 'react';
+import { Box, CircularProgress } from '@mui/material';
import { FormikProvider, useFormik } from 'formik';
import { useTranslation } from 'react-i18next';
import * as yup from 'yup';
@@ -9,14 +10,12 @@ import { amount } from 'src/lib/yupHelpers';
import { FormEnum } from '../../Shared/CalculationReports/Shared/sharedTypes';
import { Steps } from '../../Shared/CalculationReports/StepsList/StepsList';
import { CompleteFormValues } from '../AdditionalSalaryRequest';
-import { AdditionalSalaryRequestSectionEnum } from '../AdditionalSalaryRequestHelper';
import { calculateCompletionPercentage } from './calculateCompletionPercentage';
export type AdditionalSalaryRequestType = {
steps: Steps[];
currentIndex: number;
percentComplete: number;
- currentStep: AdditionalSalaryRequestSectionEnum;
handleNextStep: () => void;
handlePreviousStep: () => void;
isDrawerOpen: boolean;
@@ -43,16 +42,13 @@ interface Props {
initialValues?: CompleteFormValues;
}
-const objects = Object.values(AdditionalSalaryRequestSectionEnum);
-
export const AdditionalSalaryRequestProvider: React.FC
= ({
children,
initialValues: providedInitialValues,
}) => {
const { t } = useTranslation();
- const { steps, nextStep, previousStep, currentIndex } = useStepList(
- FormEnum.AdditionalSalary,
- );
+ const { steps, nextStep, previousStep, currentIndex, isLoading } =
+ useStepList(FormEnum.AdditionalSalary);
const locale = useLocale();
const createCurrencyValidation = useCallback(
@@ -120,25 +116,6 @@ export const AdditionalSalaryRequestProvider: React.FC = ({
[createCurrencyValidation],
);
- // Step Handlers
- const [currentStep, setCurrentStep] = useState(
- AdditionalSalaryRequestSectionEnum.AboutForm,
- );
-
- const handleNextStep = useCallback(() => {
- const next = objects[currentIndex + 1];
- nextStep();
-
- setCurrentStep(next);
- }, [currentIndex, objects, nextStep]);
-
- const handlePreviousStep = useCallback(() => {
- const next = objects[currentIndex - 1];
- previousStep();
-
- setCurrentStep(next);
- }, [currentIndex, objects, previousStep]);
-
const [isDrawerOpen, setIsDrawerOpen] = useState(true);
const toggleDrawer = useCallback(() => {
setIsDrawerOpen((prev) => !prev);
@@ -151,9 +128,9 @@ export const AdditionalSalaryRequestProvider: React.FC = ({
const handleSubmit = useCallback(
(_values: CompleteFormValues) => {
//TODO: Submit form values
- handleNextStep();
+ nextStep();
},
- [handleNextStep],
+ [nextStep],
);
const formik = useFormik({
@@ -173,26 +150,29 @@ export const AdditionalSalaryRequestProvider: React.FC = ({
steps,
currentIndex,
percentComplete,
- currentStep,
- handleNextStep,
- handlePreviousStep,
+ handleNextStep: nextStep,
+ handlePreviousStep: previousStep,
isDrawerOpen,
toggleDrawer,
setIsDrawerOpen,
handleCancel,
}),
- [
- steps,
- currentIndex,
- percentComplete,
- currentStep,
- handleNextStep,
- handlePreviousStep,
- isDrawerOpen,
- toggleDrawer,
- ],
+ [steps, currentIndex, percentComplete, isDrawerOpen, toggleDrawer],
);
+ if (isLoading) {
+ return (
+
+
+
+ );
+ }
+
return (
diff --git a/src/components/Reports/AdditionalSalaryRequest/Shared/Helper/getHeader.ts b/src/components/Reports/AdditionalSalaryRequest/Shared/Helper/getHeader.ts
index 73dd4e090b..caabb3d773 100644
--- a/src/components/Reports/AdditionalSalaryRequest/Shared/Helper/getHeader.ts
+++ b/src/components/Reports/AdditionalSalaryRequest/Shared/Helper/getHeader.ts
@@ -1,16 +1,14 @@
import { TFunction } from 'i18next';
-import { AdditionalSalaryRequestSectionEnum } from '../../AdditionalSalaryRequestHelper';
-export const getHeader = (
- t: TFunction,
- step: AdditionalSalaryRequestSectionEnum,
-): string => {
+export const getHeader = (t: TFunction, step: number): string => {
switch (step) {
- case AdditionalSalaryRequestSectionEnum.AboutForm:
+ case 0:
return 'About this Form';
- case AdditionalSalaryRequestSectionEnum.CompleteForm:
+ case 1:
return 'Complete the Form';
- case AdditionalSalaryRequestSectionEnum.Receipt:
+ case 2:
return 'Receipt';
+ default:
+ return '';
}
};
diff --git a/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.test.tsx b/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.test.tsx
index 96538ef73b..0d8d3e3ddc 100644
--- a/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.test.tsx
@@ -13,7 +13,6 @@ import {
MinisterHousingAllowanceContext,
MinisterHousingAllowanceProvider,
} from '../Shared/Context/MinisterHousingAllowanceContext';
-import { StepsEnum } from '../Shared/sharedTypes';
import { EditRequestPage } from './EditRequestPage';
const mutationSpy = jest.fn();
@@ -154,7 +153,7 @@ describe('EditRequestPage', () => {
contextValue={
{
pageType: PageEnum.Edit,
- currentStep: StepsEnum.RentOrOwn,
+ currentIndex: 1,
steps,
handleNextStep,
handlePreviousStep,
@@ -183,7 +182,7 @@ describe('EditRequestPage', () => {
{
pageType: PageEnum.Edit,
steps,
- currentStep: StepsEnum.RentOrOwn,
+ currentIndex: 1,
handleNextStep,
handlePreviousStep,
hasCalcValues: true,
diff --git a/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.tsx
index b440f0f227..90c60a7fba 100644
--- a/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.tsx
@@ -17,7 +17,6 @@ import { StepsList } from '../../Shared/CalculationReports/StepsList/StepsList';
import { mainContentWidth } from '../MinisterHousingAllowance';
import { useMinisterHousingAllowance } from '../Shared/Context/MinisterHousingAllowanceContext';
import { mocks } from '../Shared/mockData';
-import { StepsEnum } from '../Shared/sharedTypes';
import { AboutForm } from '../Steps/StepOne/AboutForm';
import { Calculation } from '../Steps/StepThree/Calculation';
import { RentOwn } from '../Steps/StepTwo/RentOwn';
@@ -39,7 +38,6 @@ export const EditRequestPage: React.FC = () => {
requestId,
steps,
handleNextStep,
- currentStep,
pageType,
isDrawerOpen,
toggleDrawer,
@@ -83,14 +81,14 @@ export const EditRequestPage: React.FC = () => {
{({ values }) => (
- {currentStep === StepsEnum.AboutForm ? (
+ {currentIndex === 0 ? (
- ) : currentStep === StepsEnum.RentOrOwn ? (
+ ) : currentIndex === 1 ? (
- ) : currentStep === StepsEnum.CalcForm ? (
+ ) : currentIndex === 2 ? (
{
}
rentOrOwn={values.rentOrOwn}
/>
- ) : currentStep === StepsEnum.Receipt ? (
+ ) : currentIndex === 3 ? (
{
{
pageType: PageEnum.New,
steps,
- currentStep: StepsEnum.RentOrOwn,
+ currentIndex: 1,
handleNextStep,
handlePreviousStep,
hasCalcValues: true,
diff --git a/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.tsx
index c1225b89ea..d648b48e1b 100644
--- a/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.tsx
@@ -16,7 +16,6 @@ import { StepsList } from '../../Shared/CalculationReports/StepsList/StepsList';
import { mainContentWidth } from '../MinisterHousingAllowance';
import { useMinisterHousingAllowance } from '../Shared/Context/MinisterHousingAllowanceContext';
import { mocks } from '../Shared/mockData';
-import { StepsEnum } from '../Shared/sharedTypes';
import { AboutForm } from '../Steps/StepOne/AboutForm';
import { Calculation } from '../Steps/StepThree/Calculation';
import { RentOwn } from '../Steps/StepTwo/RentOwn';
@@ -38,7 +37,6 @@ export const NewRequestPage: React.FC = () => {
requestId,
steps,
handleNextStep,
- currentStep,
pageType,
isDrawerOpen,
toggleDrawer,
@@ -78,21 +76,21 @@ export const NewRequestPage: React.FC = () => {
{({ values }) => (
- {currentStep === StepsEnum.AboutForm ? (
+ {currentIndex === 0 ? (
- ) : currentStep === StepsEnum.RentOrOwn ? (
+ ) : currentIndex === 1 ? (
- ) : currentStep === StepsEnum.CalcForm ? (
+ ) : currentIndex === 2 ? (
- ) : currentStep === StepsEnum.Receipt ? (
+ ) : currentIndex === 3 ? (
{steps.length}
{percentComplete}
- {currentStep}
+ {currentIndex}
Next
Previous
@@ -69,23 +68,23 @@ describe('MinisterHousingAllowanceContext', () => {
const { getByTestId, getByRole } = render( );
expect(getByTestId('steps')).toHaveTextContent('4');
- expect(getByTestId('currentStep')).toHaveTextContent(StepsEnum.AboutForm);
+ expect(getByTestId('currentIndex')).toHaveTextContent('0');
expect(getByTestId('percentComplete')).toHaveTextContent('25');
await userEvent.click(getByRole('button', { name: 'Next' }));
- expect(getByTestId('currentStep')).toHaveTextContent(StepsEnum.RentOrOwn);
+ expect(getByTestId('currentIndex')).toHaveTextContent('1');
expect(getByTestId('percentComplete')).toHaveTextContent('50');
await userEvent.click(getByRole('button', { name: 'Next' }));
- expect(getByTestId('currentStep')).toHaveTextContent(StepsEnum.CalcForm);
+ expect(getByTestId('currentIndex')).toHaveTextContent('2');
expect(getByTestId('percentComplete')).toHaveTextContent('75');
await userEvent.click(getByRole('button', { name: 'Next' }));
- expect(getByTestId('currentStep')).toHaveTextContent(StepsEnum.Receipt);
+ expect(getByTestId('currentIndex')).toHaveTextContent('3');
expect(getByTestId('percentComplete')).toHaveTextContent('100');
await userEvent.click(getByRole('button', { name: 'Previous' }));
- expect(getByTestId('currentStep')).toHaveTextContent(StepsEnum.CalcForm);
+ expect(getByTestId('currentIndex')).toHaveTextContent('2');
expect(getByTestId('percentComplete')).toHaveTextContent('75');
});
@@ -95,23 +94,23 @@ describe('MinisterHousingAllowanceContext', () => {
);
expect(getByTestId('steps')).toHaveTextContent('4');
- expect(getByTestId('currentStep')).toHaveTextContent(StepsEnum.AboutForm);
+ expect(getByTestId('currentIndex')).toHaveTextContent('0');
expect(getByTestId('percentComplete')).toHaveTextContent('25');
await userEvent.click(getByRole('button', { name: 'Next' }));
- expect(getByTestId('currentStep')).toHaveTextContent(StepsEnum.RentOrOwn);
+ expect(getByTestId('currentIndex')).toHaveTextContent('1');
expect(getByTestId('percentComplete')).toHaveTextContent('50');
await userEvent.click(getByRole('button', { name: 'Next' }));
- expect(getByTestId('currentStep')).toHaveTextContent(StepsEnum.CalcForm);
+ expect(getByTestId('currentIndex')).toHaveTextContent('2');
expect(getByTestId('percentComplete')).toHaveTextContent('75');
await userEvent.click(getByRole('button', { name: 'Next' }));
- expect(getByTestId('currentStep')).toHaveTextContent(StepsEnum.Receipt);
+ expect(getByTestId('currentIndex')).toHaveTextContent('3');
expect(getByTestId('percentComplete')).toHaveTextContent('100');
await userEvent.click(getByRole('button', { name: 'Previous' }));
- expect(getByTestId('currentStep')).toHaveTextContent(StepsEnum.CalcForm);
+ expect(getByTestId('currentIndex')).toHaveTextContent('2');
expect(getByTestId('percentComplete')).toHaveTextContent('75');
});
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
index 3a4a136c0b..1ce19208b0 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
@@ -9,6 +9,7 @@ import {
useState,
} from 'react';
import { ApolloError } from '@apollo/client';
+import { Box, CircularProgress } from '@mui/material';
import {
FormEnum,
PageEnum,
@@ -27,7 +28,6 @@ import {
useMinistryHousingAllowanceRequestsQuery,
useUpdateMinistryHousingAllowanceRequestMutation,
} from '../../MinisterHousingAllowance.generated';
-import { StepsEnum } from '../sharedTypes';
import { hasPopulatedValues } from './Helper/hasPopulatedValues';
export type HcmData = HcmDataQuery['hcm'][number];
@@ -36,7 +36,6 @@ export type ContextType = {
steps: Steps[];
currentIndex: number;
percentComplete: number;
- currentStep: StepsEnum;
handleNextStep: () => void;
handlePreviousStep: () => void;
pageType: PageEnum | undefined;
@@ -88,8 +87,6 @@ interface Props {
children?: React.ReactNode;
}
-const objects = Object.values(StepsEnum);
-
export const MinisterHousingAllowanceProvider: React.FC = ({
type,
children,
@@ -121,6 +118,7 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
previousStep,
currentIndex,
percentComplete,
+ isLoading,
} = useStepList(FormEnum.MHA, type);
const [isComplete, setIsComplete] = useState(false);
@@ -177,30 +175,13 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
const [hasCalcValues, setHasCalcValues] = useState(hasValues ? true : false);
const [isPrint, setIsPrint] = useState(false);
- const [currentStep, setCurrentStep] = useState(StepsEnum.AboutForm);
-
- const handleNextStep = useCallback(() => {
- const next = objects[currentIndex + 1];
- nextStep();
-
- setCurrentStep(next);
- }, [currentIndex, objects, nextStep]);
-
- const handlePreviousStep = useCallback(() => {
- const next = objects[currentIndex - 1];
- previousStep();
-
- setCurrentStep(next);
- }, [currentIndex, objects, previousStep]);
-
const contextValue = useMemo(
() => ({
steps,
currentIndex,
- currentStep,
percentComplete,
- handleNextStep,
- handlePreviousStep,
+ handleNextStep: nextStep,
+ handlePreviousStep: previousStep,
pageType,
hasCalcValues,
setHasCalcValues,
@@ -226,10 +207,9 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
[
steps,
currentIndex,
- currentStep,
percentComplete,
- handleNextStep,
- handlePreviousStep,
+ nextStep,
+ previousStep,
pageType,
hasCalcValues,
setHasCalcValues,
@@ -253,6 +233,19 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
],
);
+ if (isLoading || !requestsData) {
+ return (
+
+
+
+ );
+ }
+
return (
{children}
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/Helper/CustomTextField.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/Helper/CustomTextField.tsx
deleted file mode 100644
index 93aa213097..0000000000
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/Helper/CustomTextField.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import { useState } from 'react';
-import { TextField } from '@mui/material';
-import { useFormikContext } from 'formik';
-import { useTranslation } from 'react-i18next';
-import { useMinisterHousingAllowance } from 'src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext';
-import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
-import { useLocale } from 'src/hooks/useLocale';
-import { CalculationFormValues } from '../../Calculation';
-import { display, parseInput } from './formatHelper';
-
-interface CustomTextFieldProps {
- name: keyof CalculationFormValues & string;
- value: number | null | undefined;
-}
-
-export const CustomTextField: React.FC = ({
- name,
- value,
-}) => {
- const { t } = useTranslation();
- const locale = useLocale();
- const currency = 'USD';
-
- const { pageType } = useMinisterHousingAllowance();
-
- const [focused, setFocused] = useState(null);
- const isEditing = (name: keyof CalculationFormValues & string) => {
- return focused === name;
- };
-
- const { touched, errors, setFieldValue, handleBlur } =
- useFormikContext();
-
- return (
- setFocused(name)}
- onChange={(e) => setFieldValue(name, parseInput(e.target.value))}
- onBlur={(e) => {
- if (focused === name) {
- setFocused(null);
- }
- handleBlur(e);
- }}
- InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
- error={touched[name] && Boolean(errors[name])}
- helperText={touched[name] && errors[name]}
- placeholder={t('Enter Amount')}
- disabled={pageType === PageEnum.View}
- />
- );
-};
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/Helper/formatHelper.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/Helper/formatHelper.tsx
deleted file mode 100644
index 998e0336d7..0000000000
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/Helper/formatHelper.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { currencyFormat } from 'src/lib/intlFormat';
-import { CalculationFormValues } from '../../Calculation';
-
-// Helper function to parse a currency input string into a number
-export const parseInput = (s: string) => {
- const cleaned = s.replace(/[^\d.-]/g, '');
- if (cleaned === '' || cleaned === '-' || cleaned === '.') {
- return undefined;
- }
- const n = Number(cleaned);
- return Number.isFinite(n) ? n : undefined;
-};
-
-export const display = (
- isEditing: (name: keyof CalculationFormValues & string) => boolean,
- name: keyof CalculationFormValues & string,
- value: number | undefined | null,
- currency: string,
- locale: string,
-) => {
- return isEditing(name)
- ? value
- ? String(value)
- : ''
- : value
- ? currencyFormat(value as number, currency, locale, {
- showTrailingZeros: true,
- })
- : '';
-};
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
index 205733028c..6037be8ac2 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
@@ -211,6 +211,40 @@ describe('Calculation', () => {
expect(await findByText('Invalid email address.')).toBeInTheDocument();
});
+ it('shows validation error when input is 0', async () => {
+ const { getByRole, findByText } = render(
+ ,
+ );
+
+ const row = getByRole('row', {
+ name: /average monthly amount for unexpected/i,
+ });
+ const input = within(row).getByPlaceholderText(/\$0/i);
+
+ await userEvent.type(input, '0');
+
+ input.focus();
+ await userEvent.tab();
+
+ expect(input).toHaveValue('$0.00');
+
+ expect(await findByText('Must be greater than $0.')).toBeInTheDocument();
+ });
+
it('shows confirmation modal when submit is clicked', async () => {
const { getByRole, getByText, findByRole } = render(
{
const baseSchema = {
- mortgageOrRentPayment: yup.number().required(i18n.t('Required field.')),
- furnitureCostsTwo: yup.number().required(i18n.t('Required field.')),
- repairCosts: yup.number().required(i18n.t('Required field.')),
- avgUtilityTwo: yup.number().required(i18n.t('Required field.')),
- unexpectedExpenses: yup.number().required(i18n.t('Required field.')),
+ mortgageOrRentPayment: yup
+ .number()
+ .moreThan(0, i18n.t('Must be greater than $0.'))
+ .required(i18n.t('Required field.')),
+ furnitureCostsTwo: yup
+ .number()
+ .moreThan(0, i18n.t('Must be greater than $0.'))
+ .required(i18n.t('Required field.')),
+ repairCosts: yup
+ .number()
+ .moreThan(0, i18n.t('Must be greater than $0.'))
+ .required(i18n.t('Required field.')),
+ avgUtilityTwo: yup
+ .number()
+ .moreThan(0, i18n.t('Must be greater than $0.'))
+ .required(i18n.t('Required field.')),
+ unexpectedExpenses: yup
+ .number()
+ .moreThan(0, i18n.t('Must be greater than $0.'))
+ .required(i18n.t('Required field.')),
phoneNumber: yup
.string()
.test('is-phone-number', i18n.t('Invalid phone number.'), (val) => {
@@ -89,9 +104,18 @@ const getValidationSchema = (rentOrOwn?: MhaRentOrOwnEnum) => {
if (rentOrOwn === MhaRentOrOwnEnum.Own) {
return yup.object({
...baseSchema,
- rentalValue: yup.number().required(i18n.t('Required field.')),
- furnitureCostsOne: yup.number().required(i18n.t('Required field.')),
- avgUtilityOne: yup.number().required(i18n.t('Required field.')),
+ rentalValue: yup
+ .number()
+ .moreThan(0, i18n.t('Must be greater than $0.'))
+ .required(i18n.t('Required field.')),
+ furnitureCostsOne: yup
+ .number()
+ .moreThan(0, i18n.t('Must be greater than $0.'))
+ .required(i18n.t('Required field.')),
+ avgUtilityOne: yup
+ .number()
+ .moreThan(0, i18n.t('Must be greater than $0.'))
+ .required(i18n.t('Required field.')),
});
}
diff --git a/src/components/Reports/SalaryCalculator/CurrentStep.tsx b/src/components/Reports/SalaryCalculator/CurrentStep.tsx
index 728f43fe9f..e01425e072 100644
--- a/src/components/Reports/SalaryCalculator/CurrentStep.tsx
+++ b/src/components/Reports/SalaryCalculator/CurrentStep.tsx
@@ -1,23 +1,24 @@
import { Typography } from '@mui/material';
import { useTranslation } from 'react-i18next';
-import { SalaryCalculatorSectionEnum } from './SalaryCalculatorContext/Helper/sharedTypes';
import { useSalaryCalculator } from './SalaryCalculatorContext/SalaryCalculatorContext';
import { YourInformationStep } from './YourInformation/YourInformation';
export const CurrentStep: React.FC = () => {
- const { currentStep } = useSalaryCalculator();
+ const { currentIndex } = useSalaryCalculator();
const { t } = useTranslation();
- switch (currentStep) {
- case SalaryCalculatorSectionEnum.EffectiveDate:
+ switch (currentIndex) {
+ case 0:
return {t('Effective Date')} ;
- case SalaryCalculatorSectionEnum.YourInformation:
+ case 1:
return ;
- case SalaryCalculatorSectionEnum.SalaryCalculation:
+ case 2:
return {t('Salary Calculation')} ;
- case SalaryCalculatorSectionEnum.Summary:
+ case 3:
return {t('Summary')} ;
- case SalaryCalculatorSectionEnum.Receipt:
+ case 4:
return {t('Receipt')} ;
+ default:
+ return null;
}
};
diff --git a/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx b/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx
index 4674368216..6c3549ab82 100644
--- a/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx
+++ b/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx
@@ -7,6 +7,7 @@ import React, {
useMemo,
useState,
} from 'react';
+import { Box, CircularProgress } from '@mui/material';
import { useStepList } from 'src/hooks/useStepList';
import { FormEnum } from '../../Shared/CalculationReports/Shared/sharedTypes';
import { Steps } from '../../Shared/CalculationReports/StepsList/StepsList';
@@ -27,7 +28,6 @@ export interface SalaryCalculatorContextType {
currentIndex: number;
percentComplete: number;
- currentStep: SalaryCalculatorSectionEnum;
handleNextStep: () => void;
handlePreviousStep: () => void;
@@ -56,33 +56,17 @@ interface SalaryCalculatorContextProps {
children?: React.ReactNode;
}
-const objects = Object.values(SalaryCalculatorSectionEnum);
-
export const SalaryCalculatorProvider: React.FC<
SalaryCalculatorContextProps
> = ({ children }) => {
- const { steps, nextStep, previousStep, currentIndex, percentComplete } =
- useStepList(FormEnum.SalaryCalc);
-
- // Step Handlers
- const [currentStep, setCurrentStep] = useState(
- SalaryCalculatorSectionEnum.EffectiveDate,
- );
-
- const handleNextStep = useCallback(() => {
- const next = objects[currentIndex + 1];
- nextStep();
-
- setCurrentStep(next);
- }, [currentIndex, objects, nextStep]);
-
- const handlePreviousStep = useCallback(() => {
- const next = objects[currentIndex - 1];
- previousStep();
-
- setCurrentStep(next);
- }, [currentIndex, objects, previousStep]);
- // End Step Handlers
+ const {
+ steps,
+ nextStep,
+ previousStep,
+ currentIndex,
+ percentComplete,
+ isLoading,
+ } = useStepList(FormEnum.SalaryCalc);
const [isDrawerOpen, setDrawerOpen] = useState(true);
const { data: hcmData } = useHcmQuery();
@@ -97,9 +81,8 @@ export const SalaryCalculatorProvider: React.FC<
steps,
currentIndex,
percentComplete,
- currentStep,
- handleNextStep,
- handlePreviousStep,
+ handleNextStep: nextStep,
+ handlePreviousStep: previousStep,
isDrawerOpen,
setDrawerOpen,
toggleDrawer,
@@ -110,9 +93,8 @@ export const SalaryCalculatorProvider: React.FC<
steps,
currentIndex,
percentComplete,
- currentStep,
- handleNextStep,
- handlePreviousStep,
+ nextStep,
+ previousStep,
isDrawerOpen,
toggleDrawer,
hcmData,
@@ -120,6 +102,19 @@ export const SalaryCalculatorProvider: React.FC<
],
);
+ if (isLoading || !calculationData) {
+ return (
+
+
+
+ );
+ }
+
return (
{children}
diff --git a/src/hooks/useStepList.ts b/src/hooks/useStepList.ts
index bb2fc29786..1f84df9b5c 100644
--- a/src/hooks/useStepList.ts
+++ b/src/hooks/useStepList.ts
@@ -1,18 +1,29 @@
-import { useCallback, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
FormEnum,
PageEnum,
} from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
import { Steps } from '../components/Reports/Shared/CalculationReports/StepsList/StepsList';
+import { useLocalStorage } from './useLocalStorage';
export function useStepList(formType: FormEnum, type?: PageEnum) {
const { t } = useTranslation();
- const [currentIndex, setCurrentIndex] = useState(0);
+ const [hasMounted, setHasMounted] = useState(false);
+ useEffect(() => {
+ setHasMounted(true);
+ }, []);
- const [steps, setSteps] = useState(() =>
- formType === FormEnum.MHA
+ const [currentIndex, setCurrentIndex] = useLocalStorage(
+ `steps-${formType}-${type ?? 'none'}`,
+ 0,
+ );
+
+ const effectiveIndex = hasMounted ? currentIndex : 0;
+
+ const [steps, setSteps] = useState(() => {
+ return formType === FormEnum.MHA
? [
{
title: t('1. About this Form'),
@@ -84,16 +95,29 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
complete: false,
},
]
- : [],
- );
+ : [];
+ });
- const percentComplete = ((currentIndex + 1) / steps.length) * 100;
+ useEffect(() => {
+ setSteps((prevSteps) =>
+ prevSteps.map((step, index) => ({
+ ...step,
+ current: index === effectiveIndex,
+ complete: index < effectiveIndex,
+ })),
+ );
+ }, [effectiveIndex]);
+
+ const percentComplete = useMemo(
+ () => ((effectiveIndex + 1) / steps.length) * 100,
+ [effectiveIndex, steps.length],
+ );
const nextStep = useCallback(() => {
- const newIndex = currentIndex + 1;
+ const newIndex = effectiveIndex + 1;
setSteps((prevSteps) =>
prevSteps.map((step, index) => {
- if (index === currentIndex) {
+ if (index === effectiveIndex) {
return {
...step,
current: false,
@@ -112,13 +136,13 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
}),
);
setCurrentIndex(newIndex);
- }, [currentIndex, setSteps]);
+ }, [effectiveIndex]);
const previousStep = useCallback(() => {
- const newIndex = currentIndex - 1;
+ const newIndex = effectiveIndex - 1;
setSteps((prevSteps) =>
prevSteps.map((step, index) => {
- if (index === currentIndex) {
+ if (index === effectiveIndex) {
return { ...step, current: false };
}
@@ -133,13 +157,14 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
}),
);
setCurrentIndex(newIndex);
- }, [currentIndex, setSteps]);
+ }, [effectiveIndex]);
return {
steps,
nextStep,
previousStep,
- currentIndex,
+ currentIndex: effectiveIndex,
percentComplete,
+ isLoading: !hasMounted,
};
}
From e798dd8d432db867d52e30a7ba68f6a832a43de7 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Tue, 9 Dec 2025 10:08:05 -0500
Subject: [PATCH 08/36] Added snackbar to mutations
---
.../Shared/AutoSave/useSaveField.test.tsx | 58 +++++++++++++------
.../Shared/AutoSave/useSaveField.ts | 6 ++
.../SharedComponents/CurrentRequest.test.tsx | 19 ++++++
.../SharedComponents/CurrentRequest.tsx | 3 +
.../Steps/StepThree/Calculation.test.tsx | 58 +++++++++++++------
.../Steps/StepThree/Calculation.tsx | 18 ++++--
.../Steps/StepTwo/RentOwn.test.tsx | 48 ++++++++++-----
.../Steps/StepTwo/RentOwn.tsx | 45 ++++++++------
8 files changed, 182 insertions(+), 73 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.test.tsx b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.test.tsx
index be6389c04e..022ad5702e 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.test.tsx
@@ -1,5 +1,6 @@
import { ThemeProvider } from '@mui/material/styles';
import { renderHook, waitFor } from '@testing-library/react';
+import { SnackbarProvider } from 'notistack';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
import theme from 'src/theme';
@@ -11,6 +12,18 @@ import {
import { useSaveField } from './useSaveField';
const mutationSpy = jest.fn();
+const mockEnqueue = jest.fn();
+
+jest.mock('notistack', () => ({
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ ...jest.requireActual('notistack'),
+ useSnackbar: () => {
+ return {
+ enqueueSnackbar: mockEnqueue,
+ };
+ },
+}));
interface TestComponentProps {
children: React.ReactNode;
@@ -19,25 +32,27 @@ interface TestComponentProps {
const TestComponent: React.FC = ({ children }) => {
return (
-
- onCall={mutationSpy}
- >
-
+
+ onCall={mutationSpy}
>
- {children}
-
-
+
+ {children}
+
+
+
);
};
@@ -69,5 +84,12 @@ describe('useSaveField', () => {
},
),
);
+
+ await waitFor(() =>
+ expect(mockEnqueue).toHaveBeenCalledWith(
+ expect.stringContaining('Saved successfully'),
+ { variant: 'success' },
+ ),
+ );
});
});
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
index 280bac2244..18d049b3d5 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
@@ -1,4 +1,6 @@
import { useCallback } from 'react';
+import { useSnackbar } from 'notistack';
+import { useTranslation } from 'react-i18next';
import { MinistryHousingAllowanceRequestAttributesInput } from 'pages/api/graphql-rest.page.generated';
import { calculateAnnualTotals } from 'src/hooks/useAnnualTotal';
import { useUpdateMinistryHousingAllowanceRequestMutation } from '../../MinisterHousingAllowance.generated';
@@ -10,6 +12,9 @@ interface UseSaveFieldOptions {
}
export const useSaveField = ({ formValues }: UseSaveFieldOptions) => {
+ const { t } = useTranslation();
+ const { enqueueSnackbar } = useSnackbar();
+
const { requestData } = useMinisterHousingAllowance();
const [updateMinistryHousingAllowanceRequest] =
useUpdateMinistryHousingAllowanceRequestMutation();
@@ -56,6 +61,7 @@ export const useSaveField = ({ formValues }: UseSaveFieldOptions) => {
},
},
});
+ enqueueSnackbar(t('Saved successfully'), { variant: 'success' });
} catch (error) {}
},
[formValues, updateMinistryHousingAllowanceRequest, requestData],
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx
index f45c815164..9d370c9dda 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx
@@ -15,6 +15,18 @@ import { mockMHARequest } from '../mockData';
import { CurrentRequest, getDotColor, getDotVariant } from './CurrentRequest';
const mutationSpy = jest.fn();
+const mockEnqueue = jest.fn();
+
+jest.mock('notistack', () => ({
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ ...jest.requireActual('notistack'),
+ useSnackbar: () => {
+ return {
+ enqueueSnackbar: mockEnqueue,
+ };
+ },
+}));
const TestComponent: React.FC = () => {
return (
@@ -85,6 +97,13 @@ describe('CurrentRequest Component', () => {
}),
);
});
+
+ await waitFor(() => {
+ expect(mockEnqueue).toHaveBeenCalledWith(
+ expect.stringContaining('MHA request cancelled successfully.'),
+ { variant: 'success' },
+ );
+ });
});
});
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
index cf276f88bb..20adac78ce 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
@@ -55,6 +55,9 @@ export const CurrentRequest: React.FC = ({ request }) => {
},
},
});
+ enqueueSnackbar(t('MHA request cancelled successfully.'), {
+ variant: 'success',
+ });
} catch (error) {
enqueueSnackbar(t('Failed to cancel your MHA request.'), {
variant: 'error',
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
index 6037be8ac2..a60bbd4cd1 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
@@ -5,6 +5,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { render, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Formik } from 'formik';
+import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
@@ -26,6 +27,18 @@ const setHasCalcValues = jest.fn();
const setIsPrint = jest.fn();
const updateMutation = jest.fn();
const handleNextStep = jest.fn();
+const mockEnqueue = jest.fn();
+
+jest.mock('notistack', () => ({
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ ...jest.requireActual('notistack'),
+ useSnackbar: () => {
+ return {
+ enqueueSnackbar: mockEnqueue,
+ };
+ },
+}));
interface TestComponentProps {
contextValue: Partial;
@@ -43,24 +56,26 @@ const TestComponent: React.FC = ({
-
- onCall={mutationSpy}
- >
-
-
-
-
-
-
+
+
+ onCall={mutationSpy}
+ >
+
+
+
+
+
+
+
@@ -346,6 +361,13 @@ describe('Calculation', () => {
},
},
);
+
+ await waitFor(() => {
+ expect(mockEnqueue).toHaveBeenCalledWith(
+ expect.stringContaining('MHA request submitted successfully.'),
+ { variant: 'success' },
+ );
+ });
});
it('should change text when dates are null', () => {
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
index 73e8627c12..7e7a617151 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
@@ -15,6 +15,7 @@ import {
} from '@mui/material';
import { Formik } from 'formik';
import { DateTime } from 'luxon';
+import { useSnackbar } from 'notistack';
import { Trans, useTranslation } from 'react-i18next';
import * as yup from 'yup';
import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
@@ -131,7 +132,9 @@ export const Calculation: React.FC = ({
}) => {
const { t } = useTranslation();
const locale = useLocale();
- const { query } = useRouter();
+ const { enqueueSnackbar } = useSnackbar();
+ const router = useRouter();
+ const { query } = router;
const print = query.print === 'true';
const [submitMutation] = useSubmitMinistryHousingAllowanceRequestMutation();
@@ -231,10 +234,15 @@ export const Calculation: React.FC = ({
validateOnChange
validateOnBlur
onSubmit={() => {
- submitMutation({
- variables: { input: { requestId: requestData?.id ?? '' } },
- });
- handleNextStep();
+ try {
+ submitMutation({
+ variables: { input: { requestId: requestData?.id ?? '' } },
+ });
+ enqueueSnackbar(t('MHA request submitted successfully.'), {
+ variant: 'success',
+ });
+ handleNextStep();
+ } catch (error) {}
}}
>
{({
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.test.tsx
index d25f979a5f..83f7f2896d 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.test.tsx
@@ -3,6 +3,7 @@ import { ThemeProvider } from '@mui/material/styles';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Formik } from 'formik';
+import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
@@ -18,6 +19,18 @@ const submit = jest.fn();
const mutationSpy = jest.fn();
const updateMutation = jest.fn();
const setHasCalcValues = jest.fn();
+const mockEnqueue = jest.fn();
+
+jest.mock('notistack', () => ({
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ ...jest.requireActual('notistack'),
+ useSnackbar: () => {
+ return {
+ enqueueSnackbar: mockEnqueue,
+ };
+ },
+}));
interface TestComponentProps {
contextValue: Partial;
@@ -26,19 +39,21 @@ interface TestComponentProps {
const TestComponent: React.FC = ({ contextValue }) => (
-
- onCall={mutationSpy}
- >
-
-
-
-
-
-
+
+
+ onCall={mutationSpy}
+ >
+
+
+
+
+
+
+
);
@@ -89,6 +104,13 @@ describe('RentOwn', () => {
}),
);
+ await waitFor(() => {
+ expect(mockEnqueue).toHaveBeenCalledWith(
+ expect.stringContaining('All inputs have been cleared successfully'),
+ { variant: 'success' },
+ );
+ });
+
expect(getByRole('radio', { name: 'Rent' })).toBeChecked();
});
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx
index 665bdcb9ea..d3a1d9e0a8 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx
@@ -9,6 +9,7 @@ import {
Typography,
} from '@mui/material';
import { useFormikContext } from 'formik';
+import { useSnackbar } from 'notistack';
import { useTranslation } from 'react-i18next';
import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
import { MhaRentOrOwnEnum } from 'src/graphql/types.generated';
@@ -19,6 +20,7 @@ import { useMinisterHousingAllowance } from '../../Shared/Context/MinisterHousin
export const RentOwn: React.FC = () => {
const { t } = useTranslation();
+ const { enqueueSnackbar } = useSnackbar();
const {
values,
@@ -41,27 +43,32 @@ export const RentOwn: React.FC = () => {
} = useMinisterHousingAllowance();
const updateRequest = (id: string, rentOrOwn: MhaRentOrOwnEnum) => {
- updateMutation({
- variables: {
- input: {
- requestId: id,
- requestAttributes: {
- rentOrOwn,
- rentalValue: null,
- furnitureCostsOne: null,
- avgUtilityOne: null,
- mortgageOrRentPayment: null,
- furnitureCostsTwo: null,
- repairCosts: null,
- avgUtilityTwo: null,
- unexpectedExpenses: null,
- overallAmount: null,
- iUnderstandMhaPolicy: null,
+ try {
+ updateMutation({
+ variables: {
+ input: {
+ requestId: id,
+ requestAttributes: {
+ rentOrOwn,
+ rentalValue: null,
+ furnitureCostsOne: null,
+ avgUtilityOne: null,
+ mortgageOrRentPayment: null,
+ furnitureCostsTwo: null,
+ repairCosts: null,
+ avgUtilityTwo: null,
+ unexpectedExpenses: null,
+ overallAmount: null,
+ iUnderstandMhaPolicy: null,
+ },
},
},
- },
- });
- setHasCalcValues(false);
+ });
+ enqueueSnackbar(t('All inputs have been cleared successfully'), {
+ variant: 'success',
+ });
+ setHasCalcValues(false);
+ } catch (error) {}
};
const [pendingValue, setPendingValue] = useState(
From 118feac2cd79ced2812c51d65765bb671d065c71 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Tue, 9 Dec 2025 15:06:13 -0500
Subject: [PATCH 09/36] Revert saving current step
---
.../Shared/AdditionalSalaryRequestContext.tsx | 19 ++------
.../MinisterHousingAllowance.tsx | 5 ++-
.../MinisterHousingAllowanceContext.tsx | 5 +--
.../SharedComponents/CurrentRequest.tsx | 7 ++-
.../Steps/StepTwo/RentOwn.tsx | 12 ++++-
.../SalaryCalculatorContext.tsx | 12 ++---
src/hooks/useStepList.ts | 44 +++++--------------
7 files changed, 40 insertions(+), 64 deletions(-)
diff --git a/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx b/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
index 85a3eaa863..b5dce8c994 100644
--- a/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
+++ b/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
@@ -1,5 +1,4 @@
import React, { createContext, useCallback, useMemo, useState } from 'react';
-import { Box, CircularProgress } from '@mui/material';
import { FormikProvider, useFormik } from 'formik';
import { useTranslation } from 'react-i18next';
import * as yup from 'yup';
@@ -47,8 +46,9 @@ export const AdditionalSalaryRequestProvider: React.FC = ({
initialValues: providedInitialValues,
}) => {
const { t } = useTranslation();
- const { steps, nextStep, previousStep, currentIndex, isLoading } =
- useStepList(FormEnum.AdditionalSalary);
+ const { steps, nextStep, previousStep, currentIndex } = useStepList(
+ FormEnum.AdditionalSalary,
+ );
const locale = useLocale();
const createCurrencyValidation = useCallback(
@@ -160,19 +160,6 @@ export const AdditionalSalaryRequestProvider: React.FC = ({
[steps, currentIndex, percentComplete, isDrawerOpen, toggleDrawer],
);
- if (isLoading) {
- return (
-
-
-
- );
- }
-
return (
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
index 9cf9c87653..c255ce99b5 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
@@ -54,7 +54,10 @@ export const MinisterHousingAllowanceReport = () => {
const onCreateMHARequest = async () => {
await createMHA({
variables: {
- requestAttributes: {},
+ requestAttributes: {
+ phoneNumber: userHcmData?.staffInfo.primaryPhoneNumber,
+ emailAddress: userHcmData?.staffInfo.emailAddress,
+ },
},
refetchQueries: ['MinistryHousingAllowanceRequests'],
onCompleted: ({ createMinistryHousingAllowanceRequest: newRequest }) => {
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
index 1ce19208b0..b0f15a6f65 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
@@ -95,7 +95,7 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
useMinistryHousingAllowanceRequestsQuery();
//const requestId = requestsData?.ministryHousingAllowanceRequests.nodes[0]?.id;
- const requestId = 'c1a68821-5fb6-4e5e-b308-9263539af9d8';
+ const requestId = '2018e74b-3bc7-4d19-9d72-089f60feb6d6';
const { data: requestData, error: requestError } =
useMinistryHousingAllowanceRequestQuery({
@@ -118,7 +118,6 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
previousStep,
currentIndex,
percentComplete,
- isLoading,
} = useStepList(FormEnum.MHA, type);
const [isComplete, setIsComplete] = useState(false);
@@ -233,7 +232,7 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
],
);
- if (isLoading || !requestsData) {
+ if (!requestsData) {
return (
= ({ request }) => {
} = requestAttributes || {};
const [deleteRequestMutation] =
- useDeleteMinistryHousingAllowanceRequestMutation();
+ useDeleteMinistryHousingAllowanceRequestMutation({
+ refetchQueries: [
+ 'GetMinistryHousingAllowanceRequests',
+ 'GetMinistryHousingAllowanceRequest',
+ ],
+ });
const handleCancelRequest = async () => {
try {
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx
index d3a1d9e0a8..cb365ce8f4 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx
@@ -107,7 +107,17 @@ export const RentOwn: React.FC = () => {
}
} else {
handleChange(event);
- updateRequest(requestData.id, selectedValue);
+
+ updateMutation({
+ variables: {
+ input: {
+ requestId: requestData.id,
+ requestAttributes: {
+ rentOrOwn: selectedValue,
+ },
+ },
+ },
+ });
}
};
diff --git a/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx b/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx
index 6c3549ab82..ced4383953 100644
--- a/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx
+++ b/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx
@@ -59,14 +59,8 @@ interface SalaryCalculatorContextProps {
export const SalaryCalculatorProvider: React.FC<
SalaryCalculatorContextProps
> = ({ children }) => {
- const {
- steps,
- nextStep,
- previousStep,
- currentIndex,
- percentComplete,
- isLoading,
- } = useStepList(FormEnum.SalaryCalc);
+ const { steps, nextStep, previousStep, currentIndex, percentComplete } =
+ useStepList(FormEnum.SalaryCalc);
const [isDrawerOpen, setDrawerOpen] = useState(true);
const { data: hcmData } = useHcmQuery();
@@ -102,7 +96,7 @@ export const SalaryCalculatorProvider: React.FC<
],
);
- if (isLoading || !calculationData) {
+ if (!calculationData) {
return (
{
- setHasMounted(true);
- }, []);
-
- const [currentIndex, setCurrentIndex] = useLocalStorage(
- `steps-${formType}-${type ?? 'none'}`,
- 0,
- );
-
- const effectiveIndex = hasMounted ? currentIndex : 0;
+ const [currentIndex, setCurrentIndex] = useState(0);
const [steps, setSteps] = useState(() => {
return formType === FormEnum.MHA
@@ -98,26 +87,16 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
: [];
});
- useEffect(() => {
- setSteps((prevSteps) =>
- prevSteps.map((step, index) => ({
- ...step,
- current: index === effectiveIndex,
- complete: index < effectiveIndex,
- })),
- );
- }, [effectiveIndex]);
-
const percentComplete = useMemo(
- () => ((effectiveIndex + 1) / steps.length) * 100,
- [effectiveIndex, steps.length],
+ () => ((currentIndex + 1) / steps.length) * 100,
+ [currentIndex, steps.length],
);
const nextStep = useCallback(() => {
- const newIndex = effectiveIndex + 1;
+ const newIndex = currentIndex + 1;
setSteps((prevSteps) =>
prevSteps.map((step, index) => {
- if (index === effectiveIndex) {
+ if (index === currentIndex) {
return {
...step,
current: false,
@@ -136,13 +115,13 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
}),
);
setCurrentIndex(newIndex);
- }, [effectiveIndex]);
+ }, [currentIndex]);
const previousStep = useCallback(() => {
- const newIndex = effectiveIndex - 1;
+ const newIndex = currentIndex - 1;
setSteps((prevSteps) =>
prevSteps.map((step, index) => {
- if (index === effectiveIndex) {
+ if (index === currentIndex) {
return { ...step, current: false };
}
@@ -157,14 +136,13 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
}),
);
setCurrentIndex(newIndex);
- }, [effectiveIndex]);
+ }, [currentIndex]);
return {
steps,
nextStep,
previousStep,
- currentIndex: effectiveIndex,
+ currentIndex,
percentComplete,
- isLoading: !hasMounted,
};
}
From 2c80523d8814fa03c56c9ee0687156da7f7098e1 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Tue, 9 Dec 2025 15:29:20 -0500
Subject: [PATCH 10/36] Fixed broken tests after adding loading
---
.../MinisterHousingAllowanceContext.test.tsx | 16 ++++----
.../CalcComponents/EndingSection.test.tsx | 23 ++++++-----
.../CalcComponents/FairRentalValue.test.tsx | 33 ++++++++-------
.../CalcComponents/PersonInfo.test.tsx | 6 ++-
.../RequestSummaryCard.test.tsx | 12 +++---
.../ViewRequest/ViewRequestPage.test.tsx | 27 ++++++++-----
.../SalaryCalculator.test.tsx | 6 +--
.../SalaryCalculatorContext.test.tsx | 6 +--
.../StepNavigation/StepNavigation.test.tsx | 6 +--
.../DirectionButtons.test.tsx | 40 +++++++++++--------
10 files changed, 98 insertions(+), 77 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.test.tsx b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.test.tsx
index e84b28d822..7ce619cfb7 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.test.tsx
@@ -65,9 +65,9 @@ describe('MinisterHousingAllowanceContext', () => {
});
it('provides initial state for new page', async () => {
- const { getByTestId, getByRole } = render( );
+ const { findByTestId, getByTestId, getByRole } = render( );
- expect(getByTestId('steps')).toHaveTextContent('4');
+ expect(await findByTestId('steps')).toHaveTextContent('4');
expect(getByTestId('currentIndex')).toHaveTextContent('0');
expect(getByTestId('percentComplete')).toHaveTextContent('25');
@@ -89,11 +89,11 @@ describe('MinisterHousingAllowanceContext', () => {
});
it('provides initial state for edit page', async () => {
- const { getByTestId, getByRole } = render(
+ const { findByTestId, getByTestId, getByRole } = render(
,
);
- expect(getByTestId('steps')).toHaveTextContent('4');
+ expect(await findByTestId('steps')).toHaveTextContent('4');
expect(getByTestId('currentIndex')).toHaveTextContent('0');
expect(getByTestId('percentComplete')).toHaveTextContent('25');
@@ -114,10 +114,12 @@ describe('MinisterHousingAllowanceContext', () => {
expect(getByTestId('percentComplete')).toHaveTextContent('75');
});
- it('renders children correctly', () => {
- const { getByRole } = render( );
+ it('renders children correctly', async () => {
+ const { getByRole, findByRole } = render( );
- expect(getByRole('button', { name: 'Previous' })).toBeInTheDocument();
+ expect(
+ await findByRole('button', { name: 'Previous' }),
+ ).toBeInTheDocument();
expect(getByRole('button', { name: 'Next' })).toBeInTheDocument();
});
});
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/EndingSection.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/EndingSection.test.tsx
index 70a95a6605..7901050ea1 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/EndingSection.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/EndingSection.test.tsx
@@ -4,6 +4,7 @@ import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { render } from '@testing-library/react';
import { Formik } from 'formik';
+import { SnackbarProvider } from 'notistack';
import * as yup from 'yup';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
@@ -23,24 +24,26 @@ const TestComponent: React.FC = () => (
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
);
describe('EndingSection', () => {
- it('renders the component', () => {
- const { getByText, getByRole } = render( );
+ it('renders the component', async () => {
+ const { getByText, getByRole, findByText } = render( );
expect(
- getByText(/if the above information is correct, please confirm/i),
+ await findByText(/if the above information is correct, please confirm/i),
).toBeInTheDocument();
expect(
getByRole('textbox', { name: 'Telephone Number' }),
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.test.tsx
index 9ffc477787..c411402a6e 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.test.tsx
@@ -5,6 +5,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { render, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Formik } from 'formik';
+import { SnackbarProvider } from 'notistack';
import * as yup from 'yup';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
@@ -33,21 +34,23 @@ interface TestComponentProps {
const TestComponent: React.FC = ({ contextValue }) => (
-
- onCall={mutationSpy}
- >
-
-
-
-
-
-
-
-
+
+
+ onCall={mutationSpy}
+ >
+
+
+
+
+
+
+
+
+
);
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/PersonInfo.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/PersonInfo.test.tsx
index d817b26a2c..d7e26b9e79 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/PersonInfo.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/PersonInfo.test.tsx
@@ -31,9 +31,11 @@ const TestComponent: React.FC = () => (
describe('PersonInfo', () => {
it('renders personal contact information', async () => {
- const { findByText, getByText } = render( );
+ const { findByText } = render( );
- expect(getByText('Personal Contact Information')).toBeInTheDocument();
+ expect(
+ await findByText('Personal Contact Information'),
+ ).toBeInTheDocument();
expect(await findByText('John Doe')).toBeInTheDocument();
expect(
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/RequestSummaryCard.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/RequestSummaryCard.test.tsx
index 85872d157c..0ec9d9ca26 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/RequestSummaryCard.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/RequestSummaryCard.test.tsx
@@ -29,12 +29,12 @@ const TestComponent: React.FC = ({ rentOrOwn }) => (
);
describe('RequestSummaryCard', () => {
- it('renders the card for own', () => {
- const { getByText } = render(
+ it('renders the card for own', async () => {
+ const { getByText, findByText } = render(
,
);
- expect(getByText('Your MHA Request Summary')).toBeInTheDocument();
+ expect(await findByText('Your MHA Request Summary')).toBeInTheDocument();
expect(getByText('Own')).toBeInTheDocument();
expect(getByText('Your Annual MHA Total')).toBeInTheDocument();
expect(
@@ -42,12 +42,12 @@ describe('RequestSummaryCard', () => {
).toBeInTheDocument();
});
- it('renders the card for rent', () => {
- const { getByText } = render(
+ it('renders the card for rent', async () => {
+ const { getByText, findByText } = render(
,
);
- expect(getByText('Your MHA Request Summary')).toBeInTheDocument();
+ expect(await findByText('Your MHA Request Summary')).toBeInTheDocument();
expect(getByText('Rent')).toBeInTheDocument();
});
});
diff --git a/src/components/Reports/MinisterHousingAllowance/ViewRequest/ViewRequestPage.test.tsx b/src/components/Reports/MinisterHousingAllowance/ViewRequest/ViewRequestPage.test.tsx
index 0a2feb158d..a5f62b9f71 100644
--- a/src/components/Reports/MinisterHousingAllowance/ViewRequest/ViewRequestPage.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/ViewRequest/ViewRequestPage.test.tsx
@@ -2,6 +2,7 @@ import { useRouter } from 'next/router';
import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { render, within } from '@testing-library/react';
+import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import theme from 'src/theme';
@@ -19,11 +20,13 @@ const setIsPrint = jest.fn();
const TestComponent: React.FC = () => (
-
-
-
-
-
+
+
+
+
+
+
+
);
@@ -49,18 +52,20 @@ jest.mock('../Shared/Context/MinisterHousingAllowanceContext', () => ({
});
describe('ViewRequestPage', () => {
- it('renders empty panel layout,', () => {
- const { getByText, queryByRole, queryByTestId } = render( );
+ it('renders empty panel layout,', async () => {
+ const { queryByRole, queryByTestId, findByText } = render(
+ ,
+ );
- expect(getByText('Your MHA')).toBeInTheDocument();
+ expect(await findByText('Your MHA')).toBeInTheDocument();
expect(queryByRole('progressbar')).not.toBeInTheDocument();
expect(queryByTestId('ArrowBackIcon')).not.toBeInTheDocument();
});
- it('should have disabled text fields', () => {
- const { getByRole } = render( );
+ it('should have disabled text fields', async () => {
+ const { findByRole } = render( );
- const row = getByRole('row', {
+ const row = await findByRole('row', {
name: /estimated monthly cost of repairs/i,
});
const input = within(row).getByRole('textbox');
diff --git a/src/components/Reports/SalaryCalculator/SalaryCalculator.test.tsx b/src/components/Reports/SalaryCalculator/SalaryCalculator.test.tsx
index 04024bd66e..9bb7f4137e 100644
--- a/src/components/Reports/SalaryCalculator/SalaryCalculator.test.tsx
+++ b/src/components/Reports/SalaryCalculator/SalaryCalculator.test.tsx
@@ -9,9 +9,9 @@ const TestComponent: React.FC = () => (
);
describe('SalaryCalculator', () => {
- it('renders without crashing', () => {
- const { getAllByRole } = render( );
+ it('renders without crashing', async () => {
+ const { findAllByRole } = render( );
// Should render at least one heading (main step label)
- expect(getAllByRole('heading').length).toBeGreaterThan(0);
+ expect((await findAllByRole('heading')).length).toBeGreaterThan(0);
});
});
diff --git a/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.test.tsx b/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.test.tsx
index 4968a653b0..6d8566776a 100644
--- a/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.test.tsx
+++ b/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.test.tsx
@@ -12,11 +12,11 @@ const TestComponent: React.FC = () => (
);
describe('SalaryCalculator', () => {
- it('renders main content based on selected section', () => {
- const { getByRole } = render( );
+ it('renders main content based on selected section', async () => {
+ const { findByRole, getByRole } = render( );
expect(
- getByRole('heading', { name: 'Effective Date' }),
+ await findByRole('heading', { name: 'Effective Date' }),
).toBeInTheDocument();
userEvent.click(getByRole('button', { name: 'Continue' }));
diff --git a/src/components/Reports/SalaryCalculator/StepNavigation/StepNavigation.test.tsx b/src/components/Reports/SalaryCalculator/StepNavigation/StepNavigation.test.tsx
index ba5150acf3..7e626b6ba3 100644
--- a/src/components/Reports/SalaryCalculator/StepNavigation/StepNavigation.test.tsx
+++ b/src/components/Reports/SalaryCalculator/StepNavigation/StepNavigation.test.tsx
@@ -9,9 +9,9 @@ const TestComponent: React.FC = () => (
);
describe('StepNavigation', () => {
- it('renders back and continue buttons', () => {
- const { getByText } = render( );
- expect(getByText('Back')).toBeInTheDocument();
+ it('renders back and continue buttons', async () => {
+ const { getByText, findByText } = render( );
+ expect(await findByText('Back')).toBeInTheDocument();
expect(getByText('Continue')).toBeInTheDocument();
});
});
diff --git a/src/components/Reports/Shared/CalculationReports/DirectionButtons/DirectionButtons.test.tsx b/src/components/Reports/Shared/CalculationReports/DirectionButtons/DirectionButtons.test.tsx
index b47386e4bf..329710506c 100644
--- a/src/components/Reports/Shared/CalculationReports/DirectionButtons/DirectionButtons.test.tsx
+++ b/src/components/Reports/Shared/CalculationReports/DirectionButtons/DirectionButtons.test.tsx
@@ -67,50 +67,54 @@ jest.mock('next/router', () => ({
}));
describe('DirectionButtons', () => {
- it('renders Back and Submit buttons', () => {
- const { getByRole } = render(
+ it('renders Back and Submit buttons', async () => {
+ const { getByRole, findByRole } = render(
,
);
- expect(getByRole('button', { name: /back/i })).toBeInTheDocument();
+ expect(await findByRole('button', { name: /back/i })).toBeInTheDocument();
expect(getByRole('button', { name: /submit/i })).toBeInTheDocument();
});
it('calls handleNext when Continue is clicked', async () => {
- const { getByRole } = render( );
+ const { findByRole } = render( );
- await userEvent.click(getByRole('button', { name: 'Continue' }));
+ await userEvent.click(await findByRole('button', { name: 'Continue' }));
expect(handleNextStep).toHaveBeenCalled();
});
it('calls overrideNext when provided and Continue is clicked', async () => {
- const { getByRole } = render( );
+ const { findByRole } = render(
+ ,
+ );
- await userEvent.click(getByRole('button', { name: 'Continue' }));
+ await userEvent.click(await findByRole('button', { name: 'Continue' }));
expect(handleNextStep).not.toHaveBeenCalled();
expect(overrideNext).toHaveBeenCalled();
});
it('calls handlePreviousStep when Back is clicked', async () => {
- const { getByRole } = render( );
+ const { findByRole } = render( );
- await userEvent.click(getByRole('button', { name: /back/i }));
+ await userEvent.click(await findByRole('button', { name: /back/i }));
expect(handlePreviousStep).toHaveBeenCalled();
});
- it('renders custom button title when provided', () => {
- const { getByRole } = render( );
+ it('renders custom button title when provided', async () => {
+ const { findByRole } = render( );
- expect(getByRole('button', { name: title })).toBeInTheDocument();
+ expect(await findByRole('button', { name: title })).toBeInTheDocument();
});
- it('renders Cancel button when handleCancel is provided', () => {
- const { getByRole } = render( );
+ it('renders Cancel button when handleCancel is provided', async () => {
+ const { findByRole } = render(
+ ,
+ );
- expect(getByRole('button', { name: /cancel/i })).toBeInTheDocument();
+ expect(await findByRole('button', { name: /cancel/i })).toBeInTheDocument();
});
it('does not render Cancel button when handleCancel is not provided', () => {
@@ -120,9 +124,11 @@ describe('DirectionButtons', () => {
});
it('calls handleCancel when Cancel button is clicked', async () => {
- const { getByRole } = render( );
+ const { findByRole } = render(
+ ,
+ );
- userEvent.click(getByRole('button', { name: /cancel/i }));
+ userEvent.click(await findByRole('button', { name: /cancel/i }));
expect(handleCancel).toHaveBeenCalled();
});
From f74fa789bb6aa4ab49d614c880b00ee2ddb5d63c Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 10 Dec 2025 06:57:58 -0500
Subject: [PATCH 11/36] Fixed more tests
---
.../EditRequest/EditRequestPage.test.tsx | 64 ++++++++++---------
.../NewRequest/NewRequestPage.test.tsx | 50 ++++++++-------
.../AutoSave/AutosaveCustomTextField.test.tsx | 49 +++++++-------
.../Steps/StepOne/AboutForm.test.tsx | 6 +-
.../CalcComponents/CostOfHome.test.tsx | 33 +++++-----
.../Steps/StepThree/Calculation.test.tsx | 32 +++++-----
.../Steps/StepTwo/RentOwn.test.tsx | 10 ++-
.../StatusCard/StatusCard.test.tsx | 46 ++++++-------
.../SubmitModal/SubmitModal.test.tsx | 16 ++---
9 files changed, 165 insertions(+), 141 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.test.tsx b/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.test.tsx
index 0d8d3e3ddc..ae26fae2eb 100644
--- a/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.test.tsx
@@ -2,6 +2,7 @@ import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { render, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
+import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { MhaRentOrOwnEnum } from 'src/graphql/types.generated';
@@ -53,17 +54,19 @@ const TestComponentContext: React.FC = ({
}) => (
-
- onCall={mutationSpy}
- >
-
+
+ onCall={mutationSpy}
>
-
-
-
+
+
+
+
+
);
@@ -71,33 +74,36 @@ const TestComponentContext: React.FC = ({
const TestComponent: React.FC = () => (
-
- onCall={mutationSpy}
- >
-
-
-
-
+
+
+ onCall={mutationSpy}
+ >
+
+
+
+
+
);
describe('EditRequestPage', () => {
- it('renders steps list', () => {
- const { getByText } = render( );
+ it('renders steps list', async () => {
+ const { getByText, findByText } = render( );
- expect(getByText(/1. about this form/i)).toBeInTheDocument();
+ expect(await findByText(/1. about this form/i)).toBeInTheDocument();
expect(getByText(/2. rent or own?/i)).toBeInTheDocument();
expect(getByText(/3. edit your mha/i)).toBeInTheDocument();
expect(getByText(/4. receipt/i)).toBeInTheDocument();
});
it('updates steps when Continue clicked', async () => {
- const { getByRole, getAllByRole, getByText, queryByTestId } = render(
- ,
- );
+ const { getByRole, getAllByRole, getByText, queryByTestId, findByText } =
+ render( );
+
+ await findByText(/1. about this form/i);
expect(getByRole('progressbar')).toHaveAttribute('aria-valuenow', '25');
expect(queryByTestId('ArrowBackIcon')).toBeInTheDocument();
@@ -148,7 +154,7 @@ describe('EditRequestPage', () => {
});
it('should show an option is preselected', async () => {
- const { findAllByRole, getByRole, findByRole } = render(
+ const { findAllByRole, findByRole } = render(
{
/>,
);
- const continueButton = getByRole('button', { name: 'Continue' });
+ const continueButton = await findByRole('button', { name: 'Continue' });
await userEvent.click(continueButton);
expect(await findByRole('radio', { name: 'Rent' })).toBeChecked();
@@ -176,7 +182,7 @@ describe('EditRequestPage', () => {
});
it('opens confirmation modal when changing selection', async () => {
- const { getByRole, getByText, queryByText } = render(
+ const { getByRole, getByText, queryByText, findByRole } = render(
{
/>,
);
- const ownRadio = getByRole('radio', { name: 'Own' });
+ const ownRadio = await findByRole('radio', { name: 'Own' });
await userEvent.click(ownRadio);
expect(ownRadio).not.toBeChecked();
diff --git a/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.test.tsx b/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.test.tsx
index ff70bd6a7e..16ca3c1973 100644
--- a/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.test.tsx
@@ -2,6 +2,7 @@ import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { render, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
+import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import theme from 'src/theme';
@@ -53,17 +54,19 @@ const TestComponentContext: React.FC = ({
}) => (
-
- onCall={mutationSpy}
- >
-
+
+ onCall={mutationSpy}
>
-
-
-
+
+
+
+
+
);
@@ -71,29 +74,32 @@ const TestComponentContext: React.FC = ({
const TestComponent: React.FC = () => (
-
-
-
-
-
+
+
+
+
+
+
+
);
describe('NewRequestPage', () => {
- it('renders steps list', () => {
- const { getByText } = render( );
+ it('renders steps list', async () => {
+ const { getByText, findByText } = render( );
- expect(getByText(/1. about this form/i)).toBeInTheDocument();
+ expect(await findByText(/1. about this form/i)).toBeInTheDocument();
expect(getByText(/2. rent or own?/i)).toBeInTheDocument();
expect(getByText(/3. calculate your mha/i)).toBeInTheDocument();
expect(getByText(/4. receipt/i)).toBeInTheDocument();
});
it('updates steps when Continue clicked', async () => {
- const { getByRole, getAllByRole, getByText, queryByTestId } = render(
- ,
- );
+ const { getByRole, getAllByRole, getByText, queryByTestId, findByText } =
+ render( );
+
+ await findByText(/1. about this form/i);
expect(getByRole('progressbar')).toHaveAttribute('aria-valuenow', '25');
expect(queryByTestId('ArrowBackIcon')).toBeInTheDocument();
@@ -142,7 +148,7 @@ describe('NewRequestPage', () => {
it('should show validation error if continue is clicked without selecting an option', async () => {
const { getByRole, findByRole } = render( );
- const continueButton = getByRole('button', { name: 'Continue' });
+ const continueButton = await findByRole('button', { name: 'Continue' });
await userEvent.click(continueButton);
expect(getByRole('radio', { name: 'Rent' })).not.toBeChecked();
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/AutosaveCustomTextField.test.tsx b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/AutosaveCustomTextField.test.tsx
index 9b42543a55..a9cc3be41e 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/AutosaveCustomTextField.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/AutosaveCustomTextField.test.tsx
@@ -3,6 +3,7 @@ import { ThemeProvider } from '@mui/material/styles';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Formik } from 'formik';
+import { SnackbarProvider } from 'notistack';
import * as yup from 'yup';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
@@ -23,30 +24,32 @@ const defaultSchema = yup.object({
const TestComponent: React.FC = () => (
-
- onCall={mutationSpy}
- >
-
+
+ onCall={mutationSpy}
>
-
-
-
-
-
+
+
+
+
+
+
+
);
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.test.tsx
index 36f71b1a1e..ea1b9d7bf8 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.test.tsx
@@ -31,11 +31,11 @@ const TestComponent: React.FC = () => (
);
describe('AboutForm', () => {
- it('renders form and formatted dates', () => {
- const { getByText, getByRole } = render( );
+ it('renders form and formatted dates', async () => {
+ const { getByText, getByRole, findByRole } = render( );
expect(
- getByRole('heading', { name: 'About this Form' }),
+ await findByRole('heading', { name: 'About this Form' }),
).toBeInTheDocument();
expect(
getByText(
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx
index 91ad607c0a..55e45d0424 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.test.tsx
@@ -5,6 +5,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { render, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Formik } from 'formik';
+import { SnackbarProvider } from 'notistack';
import * as yup from 'yup';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
@@ -38,21 +39,23 @@ const TestComponent: React.FC = ({
}) => (
-
- onCall={mutationSpy}
- >
-
-
-
-
-
-
-
-
+
+
+ onCall={mutationSpy}
+ >
+
+
+
+
+
+
+
+
+
);
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
index a60bbd4cd1..93ce92fad5 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
@@ -82,8 +82,8 @@ const TestComponent: React.FC = ({
);
describe('Calculation', () => {
- it('renders the component', () => {
- const { getByText, getByRole } = render(
+ it('renders the component', async () => {
+ const { getByText, getByRole, findByRole } = render(
{
);
expect(
- getByRole('heading', { name: 'Calculate Your MHA Request' }),
+ await findByRole('heading', { name: 'Calculate Your MHA Request' }),
).toBeInTheDocument();
expect(
getByText(/please enter dollar amounts for each category below/i),
@@ -129,7 +129,7 @@ describe('Calculation', () => {
/>,
);
- const row = getByRole('row', {
+ const row = await findByRole('row', {
name: /average monthly amount for unexpected/i,
});
const input = within(row).getByPlaceholderText(/\$0/i);
@@ -155,7 +155,7 @@ describe('Calculation', () => {
});
it('should show validation error when checkbox is not checked', async () => {
- const { findByText, getByRole, getByText, findByRole } = render(
+ const { findByText, findByRole, getByText } = render(
{
/>,
);
- const submitButton = getByRole('button', { name: /submit/i });
+ const submitButton = await findByRole('button', { name: /submit/i });
await userEvent.click(submitButton);
@@ -184,7 +184,7 @@ describe('Calculation', () => {
});
it('shows validation errors when email and phone are invalid', async () => {
- const { getByRole, findByText } = render(
+ const { getByRole, findByText, findByRole } = render(
{
/>,
);
- const phone = getByRole('textbox', { name: 'Telephone Number' });
+ const phone = await findByRole('textbox', { name: 'Telephone Number' });
const email = getByRole('textbox', { name: 'Email' });
expect(phone).toHaveValue('1234567890');
@@ -227,7 +227,7 @@ describe('Calculation', () => {
});
it('shows validation error when input is 0', async () => {
- const { getByRole, findByText } = render(
+ const { findByRole, findByText } = render(
{
/>,
);
- const row = getByRole('row', {
+ const row = await findByRole('row', {
name: /average monthly amount for unexpected/i,
});
const input = within(row).getByPlaceholderText(/\$0/i);
@@ -289,7 +289,7 @@ describe('Calculation', () => {
/>,
);
- const row1 = getByRole('row', {
+ const row1 = await findByRole('row', {
name: /monthly rent/i,
});
const input1 = within(row1).getByPlaceholderText(/\$0/i);
@@ -393,7 +393,7 @@ describe('Calculation', () => {
});
it('should update checkbox value when clicked', async () => {
- const { getByRole } = render(
+ const { findByRole } = render(
{
/>,
);
- const checkbox = getByRole('checkbox', {
+ const checkbox = await findByRole('checkbox', {
name: /i understand that my approved/i,
});
expect(checkbox).not.toBeChecked();
@@ -435,8 +435,8 @@ describe('Calculation', () => {
});
describe('isViewPage behavior', () => {
- it('renders view only mode', () => {
- const { getByRole, queryByRole, getByText } = render(
+ it('renders view only mode', async () => {
+ const { findByRole, queryByRole, getByText } = render(
{
);
expect(
- getByRole('heading', { name: 'Your MHA Request' }),
+ await findByRole('heading', { name: 'Your MHA Request' }),
).toBeInTheDocument();
expect(getByText('Personal Contact Information')).toBeInTheDocument();
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.test.tsx
index 83f7f2896d..443dca90b8 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.test.tsx
@@ -7,6 +7,7 @@ import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
+import { MhaRentOrOwnEnum } from 'src/graphql/types.generated';
import theme from 'src/theme';
import { UpdateMinistryHousingAllowanceRequestMutation } from '../../MinisterHousingAllowance.generated';
import {
@@ -60,20 +61,23 @@ const TestComponent: React.FC = ({ contextValue }) => (
describe('RentOwn', () => {
it('renders form and options for new page', async () => {
- const { getByRole, getByText, findAllByRole } = render(
+ const { getByRole, getByText, findAllByRole, findByRole } = render(
,
);
- expect(getByRole('heading', { name: 'Rent or Own?' })).toBeInTheDocument();
+ expect(
+ await findByRole('heading', { name: 'Rent or Own?' }),
+ ).toBeInTheDocument();
expect(getByText('Rent')).toBeInTheDocument();
expect(getByText('Own')).toBeInTheDocument();
@@ -86,7 +90,7 @@ describe('RentOwn', () => {
variables: {
input: {
requestAttributes: {
- rentOrOwn: 'RENT',
+ rentOrOwn: MhaRentOrOwnEnum.Rent,
rentalValue: null,
furnitureCostsOne: null,
avgUtilityOne: null,
diff --git a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx
index d639e7a4a0..894a3a23d2 100644
--- a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx
+++ b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx
@@ -76,45 +76,47 @@ const TestComponent: React.FC = ({
};
describe('CardSkeleton', () => {
- it('should render card header no subtitle', () => {
- const { getByText, getByTestId, queryByText } = render( );
+ it('should render card header no subtitle', async () => {
+ const { getByText, getByTestId, queryByText, findByTestId } = render(
+ ,
+ );
- expect(getByTestId('mock-icon')).toBeInTheDocument();
+ expect(await findByTestId('mock-icon')).toBeInTheDocument();
expect(getByText(title)).toBeInTheDocument();
expect(queryByText(subtitle)).not.toBeInTheDocument();
expect(getByTestId('FileDownloadIcon')).toBeInTheDocument();
});
- it('should render card header with subtitle', () => {
- const { getByText, getByTestId } = render(
+ it('should render card header with subtitle', async () => {
+ const { getByText, getByTestId, findByTestId } = render(
,
);
- expect(getByTestId('mock-icon')).toBeInTheDocument();
+ expect(await findByTestId('mock-icon')).toBeInTheDocument();
expect(getByText(title)).toBeInTheDocument();
expect(getByText(subtitle)).toBeInTheDocument();
expect(getByTestId('FileDownloadIcon')).toBeInTheDocument();
});
- it('should render children', () => {
- const { getByText } = render( );
+ it('should render children', async () => {
+ const { findByText } = render( );
- expect(getByText('Test Children')).toBeInTheDocument();
+ expect(await findByText('Test Children')).toBeInTheDocument();
});
- it('should render action buttons', () => {
- const { getByText } = render( );
+ it('should render action buttons', async () => {
+ const { getByText, findByText } = render( );
- expect(getByText(titleOne)).toBeInTheDocument();
+ expect(await findByText(titleOne)).toBeInTheDocument();
expect(getByText(titleTwo)).toBeInTheDocument();
});
- it('should go to correct link when first button is clicked', () => {
- const { getByRole } = render(
+ it('should go to correct link when first button is clicked', async () => {
+ const { findByRole } = render(
,
);
- const firstButton = getByRole('link', { name: titleOne });
+ const firstButton = await findByRole('link', { name: titleOne });
expect(firstButton).toHaveAttribute(
'href',
@@ -122,12 +124,12 @@ describe('CardSkeleton', () => {
);
});
- it('should go to correct link when second button is clicked', () => {
- const { getByRole } = render(
+ it('should go to correct link when second button is clicked', async () => {
+ const { findByRole } = render(
,
);
- const secondButton = getByRole('link', { name: titleTwo });
+ const secondButton = await findByRole('link', { name: titleTwo });
expect(secondButton).toHaveAttribute(
'href',
@@ -139,7 +141,7 @@ describe('CardSkeleton', () => {
const { getByRole, findByRole, getByText, queryByRole } = render(
,
);
- const cancelButton = getByRole('button', { name: 'Cancel Request' });
+ const cancelButton = await findByRole('button', { name: 'Cancel Request' });
await userEvent.click(cancelButton);
@@ -165,9 +167,9 @@ describe('CardSkeleton', () => {
});
it('calls handleDownload when download icon is clicked', async () => {
- const { getByTestId } = render( );
+ const { findByTestId } = render( );
- const downloadIcon = getByTestId('FileDownloadIcon');
+ const downloadIcon = await findByTestId('FileDownloadIcon');
await userEvent.click(downloadIcon);
@@ -178,7 +180,7 @@ describe('CardSkeleton', () => {
const { getByRole, findByRole, getByText, queryByRole } = render(
,
);
- const cancelButton = getByRole('button', { name: 'Cancel Request' });
+ const cancelButton = await findByRole('button', { name: 'Cancel Request' });
await userEvent.click(cancelButton);
diff --git a/src/components/Reports/Shared/CalculationReports/SubmitModal/SubmitModal.test.tsx b/src/components/Reports/Shared/CalculationReports/SubmitModal/SubmitModal.test.tsx
index 9b89ff82f8..e6be7c1c7d 100644
--- a/src/components/Reports/Shared/CalculationReports/SubmitModal/SubmitModal.test.tsx
+++ b/src/components/Reports/Shared/CalculationReports/SubmitModal/SubmitModal.test.tsx
@@ -58,12 +58,12 @@ const TestComponent: React.FC = ({
describe('ConfirmationModal', () => {
it('renders submit confirmation modal correctly', async () => {
- const { getByText, getByRole } = render(
+ const { getByText, getByRole, findByText } = render(
,
);
expect(
- getByText('Are you ready to submit your Main Title?'),
+ await findByText('Are you ready to submit your Main Title?'),
).toBeInTheDocument();
expect(
getByText('You are submitting your Main Title for board approval.'),
@@ -76,12 +76,12 @@ describe('ConfirmationModal', () => {
});
it('renders update confirmation modal correctly', async () => {
- const { getByText, getByRole } = render(
+ const { getByText, getByRole, findByRole } = render(
,
);
expect(
- getByRole('heading', {
+ await findByRole('heading', {
name: 'Are you ready to submit your updated Main Title?',
}),
).toBeInTheDocument();
@@ -95,10 +95,10 @@ describe('ConfirmationModal', () => {
});
it('calls handleClose when modal is closed', async () => {
- const { getByRole } = render( );
+ const { getByRole, findByRole } = render( );
expect(
- getByRole('heading', { name: 'Do you want to cancel?' }),
+ await findByRole('heading', { name: 'Do you want to cancel?' }),
).toBeInTheDocument();
await userEvent.click(getByRole('button', { name: /NO/i }));
@@ -106,7 +106,7 @@ describe('ConfirmationModal', () => {
});
it('should override title, content, and subcontent when provided', async () => {
- const { getByText } = render(
+ const { getByText, findByText } = render(
{
/>,
);
- expect(getByText(title)).toBeInTheDocument();
+ expect(await findByText(title)).toBeInTheDocument();
expect(getByText(content)).toBeInTheDocument();
expect(getByText(subContent)).toBeInTheDocument();
});
From 48c05c868236a84fa4a58df841abd469bf0897bd Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 10 Dec 2025 07:13:46 -0500
Subject: [PATCH 12/36] Fix more broken tests
---
.../salaryCalculator.page.test.tsx | 6 +--
.../PersonalInformationSection.test.tsx | 6 +--
.../ReceiptStep/Receipt.test.tsx | 46 ++++++++++---------
3 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/pages/accountLists/[accountListId]/reports/salaryCalculator/salaryCalculator.page.test.tsx b/pages/accountLists/[accountListId]/reports/salaryCalculator/salaryCalculator.page.test.tsx
index bdfde72fc3..d6276a6f83 100644
--- a/pages/accountLists/[accountListId]/reports/salaryCalculator/salaryCalculator.page.test.tsx
+++ b/pages/accountLists/[accountListId]/reports/salaryCalculator/salaryCalculator.page.test.tsx
@@ -11,10 +11,10 @@ const TestComponent = () => (
);
describe('SalaryCalculatorPage', () => {
- it('renders the Salary Calculator header', () => {
- const { getByRole } = render( );
+ it('renders the Salary Calculator header', async () => {
+ const { findByRole } = render( );
expect(
- getByRole('heading', { name: /Salary Calculator/i }),
+ await findByRole('heading', { name: /Salary Calculator/i }),
).toBeInTheDocument();
});
diff --git a/src/components/Reports/SalaryCalculator/PersonalInformationSection/PersonalInformationSection.test.tsx b/src/components/Reports/SalaryCalculator/PersonalInformationSection/PersonalInformationSection.test.tsx
index fe7eb4abce..8d59f7ad16 100644
--- a/src/components/Reports/SalaryCalculator/PersonalInformationSection/PersonalInformationSection.test.tsx
+++ b/src/components/Reports/SalaryCalculator/PersonalInformationSection/PersonalInformationSection.test.tsx
@@ -18,10 +18,10 @@ describe('PersonalInformationSection', () => {
).toBeInTheDocument();
});
- it('should display all category row headers', () => {
- const { getByRole } = render( );
+ it('should display all category row headers', async () => {
+ const { getByRole, findByRole } = render( );
- expect(getByRole('cell', { name: 'Location' })).toBeInTheDocument();
+ expect(await findByRole('cell', { name: 'Location' })).toBeInTheDocument();
expect(getByRole('cell', { name: 'Tenure' })).toBeInTheDocument();
expect(getByRole('cell', { name: 'Age' })).toBeInTheDocument();
expect(getByRole('cell', { name: 'Children' })).toBeInTheDocument();
diff --git a/src/components/Reports/Shared/CalculationReports/ReceiptStep/Receipt.test.tsx b/src/components/Reports/Shared/CalculationReports/ReceiptStep/Receipt.test.tsx
index 45b576c59e..ca5d497ac1 100644
--- a/src/components/Reports/Shared/CalculationReports/ReceiptStep/Receipt.test.tsx
+++ b/src/components/Reports/Shared/CalculationReports/ReceiptStep/Receipt.test.tsx
@@ -64,11 +64,13 @@ const TestComponent: React.FC = ({
);
describe('Receipt', () => {
- it('renders the component in new page', () => {
- const { getByRole } = render( );
+ it('renders the component in new page', async () => {
+ const { getByRole, findByRole } = render(
+ ,
+ );
expect(
- getByRole('heading', {
+ await findByRole('heading', {
name: 'Thank you for Submitting your Test Title!',
}),
).toBeInTheDocument();
@@ -83,13 +85,13 @@ describe('Receipt', () => {
expect(getByRole('button', { name: /view form/i })).toBeInTheDocument();
});
- it('renders the component in edit page', () => {
- const { getByRole } = render(
+ it('renders the component in edit page', async () => {
+ const { getByRole, findByRole } = render(
,
);
expect(
- getByRole('heading', {
+ await findByRole('heading', {
name: 'Thank you for updating your Test Title!',
}),
).toBeInTheDocument();
@@ -104,8 +106,8 @@ describe('Receipt', () => {
expect(getByRole('button', { name: /view form/i })).toBeInTheDocument();
});
- it('should change text when dates are null', () => {
- const { getByText } = render(
+ it('should change text when dates are null', async () => {
+ const { findByText } = render(
{
);
expect(
- getByText(
+ await findByText(
/we will review your information and you will receive notice for your approval soon./i,
),
).toBeInTheDocument();
});
- it('should go to edit link when clicked', () => {
- const { getByRole } = render(
+ it('should go to edit link when clicked', async () => {
+ const { findByRole } = render(
,
);
- const editButton = getByRole('link', {
+ const editButton = await findByRole('link', {
name: /edit your mha request \(not available after/i,
});
@@ -135,12 +137,12 @@ describe('Receipt', () => {
);
});
- it('should render custom alert text when provided', () => {
- const { getByText } = render(
+ it('should render custom alert text when provided', async () => {
+ const { findByText } = render(
,
);
- expect(getByText(alertText)).toBeInTheDocument();
+ expect(await findByText(alertText)).toBeInTheDocument();
});
it('should not render edit link when not provided', () => {
@@ -153,12 +155,12 @@ describe('Receipt', () => {
expect(editButton).not.toBeInTheDocument();
});
- it('should render edit link when provided', () => {
- const { getByRole } = render(
+ it('should render edit link when provided', async () => {
+ const { findByRole } = render(
,
);
- const editButton = getByRole('link', {
+ const editButton = await findByRole('link', {
name: /edit your mha request \(not available after/i,
});
@@ -167,11 +169,11 @@ describe('Receipt', () => {
});
it('should go to view link when View clicked', async () => {
- const { getByRole } = render(
+ const { findByRole } = render(
,
);
- const viewButton = getByRole('link', { name: /view form/i });
+ const viewButton = await findByRole('link', { name: /view form/i });
expect(viewButton).toHaveAttribute(
'href',
@@ -183,11 +185,11 @@ describe('Receipt', () => {
});
it('should go to view link when Print clicked', async () => {
- const { getByRole } = render(
+ const { findByRole } = render(
,
);
- const viewButton = getByRole('link', { name: /print a copy/i });
+ const viewButton = await findByRole('link', { name: /print a copy/i });
expect(viewButton).toHaveAttribute(
'href',
From e8c1c9eec9150af8ebc95600725e442bf0b54d9b Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 10 Dec 2025 07:37:49 -0500
Subject: [PATCH 13/36] Claude review suggestions
---
.../AdditionalSalaryRequest/CurrentStep.tsx | 33 ++++++++-----------
.../Shared/AdditionalSalaryRequestContext.tsx | 12 ++++++-
.../Shared/AutoSave/useSaveField.ts | 7 ++--
.../Reports/SalaryCalculator/CurrentStep.tsx | 31 +++++++++--------
4 files changed, 47 insertions(+), 36 deletions(-)
diff --git a/src/components/Reports/AdditionalSalaryRequest/CurrentStep.tsx b/src/components/Reports/AdditionalSalaryRequest/CurrentStep.tsx
index 9bff0e677d..9e35908b66 100644
--- a/src/components/Reports/AdditionalSalaryRequest/CurrentStep.tsx
+++ b/src/components/Reports/AdditionalSalaryRequest/CurrentStep.tsx
@@ -14,23 +14,18 @@ export const CurrentStep: React.FC = () => {
const pageLink = `/accountLists/${accountListId}/reports/additionalSalaryRequest`;
- switch (currentIndex) {
- case 0:
- return ;
- case 1:
- return ;
- case 2:
- return (
-
-
-
- );
- default:
- return null;
- }
+ const steps = [
+ ,
+ ,
+
+
+ ,
+ ];
+
+ return steps[currentIndex] ?? null;
};
diff --git a/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx b/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
index b5dce8c994..ba4e6b7115 100644
--- a/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
+++ b/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
@@ -157,7 +157,17 @@ export const AdditionalSalaryRequestProvider: React.FC = ({
setIsDrawerOpen,
handleCancel,
}),
- [steps, currentIndex, percentComplete, isDrawerOpen, toggleDrawer],
+ [
+ steps,
+ currentIndex,
+ percentComplete,
+ nextStep,
+ previousStep,
+ isDrawerOpen,
+ toggleDrawer,
+ setIsDrawerOpen,
+ handleCancel,
+ ],
);
return (
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
index 18d049b3d5..451d4a8645 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
@@ -24,7 +24,7 @@ export const useSaveField = ({ formValues }: UseSaveFieldOptions) => {
async (
attributes: Partial,
) => {
- if (!requestData?.id) {
+ if (!requestData || !requestData.id) {
return;
}
@@ -53,6 +53,7 @@ export const useSaveField = ({ formValues }: UseSaveFieldOptions) => {
ministryHousingAllowanceRequest: {
...requestData,
requestAttributes: {
+ __typename: 'MhaRequestAttributes',
...values,
...attributes,
overallAmount,
@@ -62,7 +63,9 @@ export const useSaveField = ({ formValues }: UseSaveFieldOptions) => {
},
});
enqueueSnackbar(t('Saved successfully'), { variant: 'success' });
- } catch (error) {}
+ } catch (error) {
+ // If failed, snackbar is already handled elsewhere
+ }
},
[formValues, updateMinistryHousingAllowanceRequest, requestData],
);
diff --git a/src/components/Reports/SalaryCalculator/CurrentStep.tsx b/src/components/Reports/SalaryCalculator/CurrentStep.tsx
index e01425e072..45612d3815 100644
--- a/src/components/Reports/SalaryCalculator/CurrentStep.tsx
+++ b/src/components/Reports/SalaryCalculator/CurrentStep.tsx
@@ -7,18 +7,21 @@ export const CurrentStep: React.FC = () => {
const { currentIndex } = useSalaryCalculator();
const { t } = useTranslation();
- switch (currentIndex) {
- case 0:
- return {t('Effective Date')} ;
- case 1:
- return ;
- case 2:
- return {t('Salary Calculation')} ;
- case 3:
- return {t('Summary')} ;
- case 4:
- return {t('Receipt')} ;
- default:
- return null;
- }
+ const steps = [
+
+ {t('Effective Date')}
+ ,
+ ,
+
+ {t('Salary Calculation')}
+ ,
+
+ {t('Summary')}
+ ,
+
+ {t('Receipt')}
+ ,
+ ];
+
+ return steps[currentIndex] ?? null;
};
From 831dc696c314e208f53a7d2915d2eb793acdbbd7 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 31 Dec 2025 09:10:24 -0500
Subject: [PATCH 14/36] Review changes based on suggestions
---
.../Shared/AdditionalSalaryRequestContext.tsx | 17 ++-
.../EditRequest/EditRequestPage.tsx | 13 +-
.../MinisterHousingAllowance.graphql | 119 +++++-------------
.../NewRequest/NewRequestPage.tsx | 13 +-
.../Shared/AutoSave/useSaveField.ts | 49 ++++----
.../MinisterHousingAllowanceContext.test.tsx | 16 +--
.../MinisterHousingAllowanceContext.tsx | 12 +-
.../CurrentBoardApproved.test.tsx | 36 +++---
.../SharedComponents/CurrentBoardApproved.tsx | 42 +++----
.../Steps/StepThree/Calculation.test.tsx | 49 ++++----
.../SalaryCalculatorContext.tsx | 17 ++-
.../DirectionButtons.test.tsx | 6 +-
.../StatusCard/StatusCard.test.tsx | 10 +-
.../StatusCard/StatusCard.tsx | 2 +-
src/hooks/useStepList.test.ts | 8 +-
src/hooks/useStepList.ts | 16 +--
16 files changed, 186 insertions(+), 239 deletions(-)
diff --git a/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx b/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
index f0ce25e563..0ddaa23ee4 100644
--- a/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
+++ b/src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx
@@ -46,9 +46,8 @@ export const AdditionalSalaryRequestProvider: React.FC = ({
initialValues: providedInitialValues,
}) => {
const { t } = useTranslation();
- const { steps, nextStep, previousStep, currentIndex } = useStepList(
- FormEnum.AdditionalSalary,
- );
+ const { steps, handleNextStep, handlePreviousStep, currentIndex } =
+ useStepList(FormEnum.AdditionalSalary);
const locale = useLocale();
const createCurrencyValidation = useCallback(
@@ -140,9 +139,9 @@ export const AdditionalSalaryRequestProvider: React.FC = ({
const handleSubmit = useCallback(
(_values: CompleteFormValues) => {
//TODO: Submit form values
- nextStep();
+ handleNextStep();
},
- [nextStep],
+ [handleNextStep],
);
const formik = useFormik({
@@ -162,8 +161,8 @@ export const AdditionalSalaryRequestProvider: React.FC = ({
steps,
currentIndex,
percentComplete,
- handleNextStep: nextStep,
- handlePreviousStep: previousStep,
+ handleNextStep,
+ handlePreviousStep,
isDrawerOpen,
toggleDrawer,
setIsDrawerOpen,
@@ -173,8 +172,8 @@ export const AdditionalSalaryRequestProvider: React.FC = ({
steps,
currentIndex,
percentComplete,
- nextStep,
- previousStep,
+ handleNextStep,
+ handlePreviousStep,
isDrawerOpen,
toggleDrawer,
setIsDrawerOpen,
diff --git a/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.tsx
index 90c60a7fba..e9fe82324d 100644
--- a/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/EditRequest/EditRequestPage.tsx
@@ -81,14 +81,14 @@ export const EditRequestPage: React.FC = () => {
{({ values }) => (
- {currentIndex === 0 ? (
+ {currentIndex === 0 && (
- ) : currentIndex === 1 ? (
-
- ) : currentIndex === 2 ? (
+ )}
+ {currentIndex === 1 && }
+ {currentIndex === 2 && (
{
}
rentOrOwn={values.rentOrOwn}
/>
- ) : currentIndex === 3 ? (
+ )}
+ {currentIndex === 3 && (
{
deadlineDate={deadlineDate}
setIsComplete={setIsComplete}
/>
- ) : null}
+ )}
)}
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
index 54fbb8b09d..8c1f80bf21 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
@@ -1,3 +1,28 @@
+fragment RequestAttributes on MhaRequestAttributes {
+ rentOrOwn
+ rentalValue
+ furnitureCostsOne
+ avgUtilityOne
+ mortgageOrRentPayment
+ furnitureCostsTwo
+ repairCosts
+ avgUtilityTwo
+ unexpectedExpenses
+ overallAmount
+ phoneNumber
+ emailAddress
+ iUnderstandMhaPolicy
+ approvedDate
+ approvedOverallAmount
+ availableDate
+ boardApprovedDate
+ deadlineDate
+ lastApprovedDate
+ spouseSpecific
+ staffSpecific
+ submittedDate
+}
+
query MinistryHousingAllowanceRequests {
ministryHousingAllowanceRequests {
nodes {
@@ -5,28 +30,7 @@ query MinistryHousingAllowanceRequests {
personNumber
updatedAt
requestAttributes {
- rentOrOwn
- rentalValue
- furnitureCostsOne
- avgUtilityOne
- mortgageOrRentPayment
- furnitureCostsTwo
- repairCosts
- avgUtilityTwo
- unexpectedExpenses
- overallAmount
- phoneNumber
- emailAddress
- iUnderstandMhaPolicy
- approvedDate
- approvedOverallAmount
- availableDate
- boardApprovedDate
- deadlineDate
- lastApprovedDate
- spouseSpecific
- staffSpecific
- submittedDate
+ ...RequestAttributes
}
status
user {
@@ -45,28 +49,7 @@ query MinistryHousingAllowanceRequest($ministryHousingAllowanceRequestId: ID!) {
personNumber
updatedAt
requestAttributes {
- rentOrOwn
- rentalValue
- furnitureCostsOne
- avgUtilityOne
- mortgageOrRentPayment
- furnitureCostsTwo
- repairCosts
- avgUtilityTwo
- unexpectedExpenses
- overallAmount
- phoneNumber
- emailAddress
- iUnderstandMhaPolicy
- approvedDate
- approvedOverallAmount
- availableDate
- boardApprovedDate
- deadlineDate
- lastApprovedDate
- spouseSpecific
- staffSpecific
- submittedDate
+ ...RequestAttributes
}
status
user {
@@ -89,10 +72,7 @@ mutation CreateHousingAllowanceRequest(
status
personNumber
requestAttributes {
- rentOrOwn
- rentalValue
- furnitureCostsOne
- avgUtilityOne
+ ...RequestAttributes
}
user {
id
@@ -110,19 +90,7 @@ mutation UpdateMinistryHousingAllowanceRequest(
ministryHousingAllowanceRequest {
id
requestAttributes {
- rentOrOwn
- rentalValue
- furnitureCostsOne
- avgUtilityOne
- mortgageOrRentPayment
- furnitureCostsTwo
- repairCosts
- avgUtilityTwo
- unexpectedExpenses
- overallAmount
- phoneNumber
- emailAddress
- iUnderstandMhaPolicy
+ ...RequestAttributes
}
}
}
@@ -142,20 +110,7 @@ mutation SubmitMinistryHousingAllowanceRequest(
submitMinistryHousingAllowanceRequest(input: $input) {
ministryHousingAllowanceRequest {
requestAttributes {
- rentOrOwn
- rentalValue
- furnitureCostsOne
- avgUtilityOne
- mortgageOrRentPayment
- furnitureCostsTwo
- repairCosts
- avgUtilityTwo
- unexpectedExpenses
- overallAmount
- phoneNumber
- emailAddress
- iUnderstandMhaPolicy
- submittedDate
+ ...RequestAttributes
}
}
}
@@ -168,19 +123,7 @@ mutation DuplicateMinistryHousingAllowanceRequest(
ministryHousingAllowanceRequest {
id
requestAttributes {
- rentOrOwn
- rentalValue
- furnitureCostsOne
- avgUtilityOne
- mortgageOrRentPayment
- furnitureCostsTwo
- repairCosts
- avgUtilityTwo
- unexpectedExpenses
- overallAmount
- phoneNumber
- emailAddress
- iUnderstandMhaPolicy
+ ...RequestAttributes
}
}
}
diff --git a/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.tsx
index d648b48e1b..695dbdc15b 100644
--- a/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/NewRequest/NewRequestPage.tsx
@@ -76,21 +76,22 @@ export const NewRequestPage: React.FC = () => {
{({ values }) => (
- {currentIndex === 0 ? (
+ {currentIndex === 0 && (
- ) : currentIndex === 1 ? (
-
- ) : currentIndex === 2 ? (
+ )}
+ {currentIndex === 1 && }
+ {currentIndex === 2 && (
- ) : currentIndex === 3 ? (
+ )}
+ {currentIndex === 3 && (
{
}
setIsComplete={setIsComplete}
/>
- ) : null}
+ )}
)}
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
index 451d4a8645..f1b706902b 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
@@ -24,7 +24,7 @@ export const useSaveField = ({ formValues }: UseSaveFieldOptions) => {
async (
attributes: Partial,
) => {
- if (!requestData || !requestData.id) {
+ if (!requestData?.id) {
return;
}
@@ -35,37 +35,34 @@ export const useSaveField = ({ formValues }: UseSaveFieldOptions) => {
const { annualTotal: overallAmount } =
calculateAnnualTotals(updatedValues);
- try {
- await updateMinistryHousingAllowanceRequest({
- variables: {
- input: {
- requestId: requestData.id,
+ await updateMinistryHousingAllowanceRequest({
+ variables: {
+ input: {
+ requestId: requestData.id,
+ requestAttributes: {
+ ...attributes,
+ overallAmount,
+ },
+ },
+ },
+ optimisticResponse: {
+ updateMinistryHousingAllowanceRequest: {
+ __typename: 'MinistryHousingAllowanceRequestUpdateMutationPayload',
+ ministryHousingAllowanceRequest: {
+ ...requestData,
requestAttributes: {
+ __typename: 'MhaRequestAttributes',
+ ...values,
...attributes,
overallAmount,
},
},
},
- optimisticResponse: {
- updateMinistryHousingAllowanceRequest: {
- __typename:
- 'MinistryHousingAllowanceRequestUpdateMutationPayload',
- ministryHousingAllowanceRequest: {
- ...requestData,
- requestAttributes: {
- __typename: 'MhaRequestAttributes',
- ...values,
- ...attributes,
- overallAmount,
- },
- },
- },
- },
- });
- enqueueSnackbar(t('Saved successfully'), { variant: 'success' });
- } catch (error) {
- // If failed, snackbar is already handled elsewhere
- }
+ },
+ onCompleted: () => {
+ enqueueSnackbar(t('Saved successfully'), { variant: 'success' });
+ },
+ });
},
[formValues, updateMinistryHousingAllowanceRequest, requestData],
);
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.test.tsx b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.test.tsx
index 7ce619cfb7..b6c4a870d9 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.test.tsx
@@ -71,19 +71,19 @@ describe('MinisterHousingAllowanceContext', () => {
expect(getByTestId('currentIndex')).toHaveTextContent('0');
expect(getByTestId('percentComplete')).toHaveTextContent('25');
- await userEvent.click(getByRole('button', { name: 'Next' }));
+ userEvent.click(getByRole('button', { name: 'Next' }));
expect(getByTestId('currentIndex')).toHaveTextContent('1');
expect(getByTestId('percentComplete')).toHaveTextContent('50');
- await userEvent.click(getByRole('button', { name: 'Next' }));
+ userEvent.click(getByRole('button', { name: 'Next' }));
expect(getByTestId('currentIndex')).toHaveTextContent('2');
expect(getByTestId('percentComplete')).toHaveTextContent('75');
- await userEvent.click(getByRole('button', { name: 'Next' }));
+ userEvent.click(getByRole('button', { name: 'Next' }));
expect(getByTestId('currentIndex')).toHaveTextContent('3');
expect(getByTestId('percentComplete')).toHaveTextContent('100');
- await userEvent.click(getByRole('button', { name: 'Previous' }));
+ userEvent.click(getByRole('button', { name: 'Previous' }));
expect(getByTestId('currentIndex')).toHaveTextContent('2');
expect(getByTestId('percentComplete')).toHaveTextContent('75');
});
@@ -97,19 +97,19 @@ describe('MinisterHousingAllowanceContext', () => {
expect(getByTestId('currentIndex')).toHaveTextContent('0');
expect(getByTestId('percentComplete')).toHaveTextContent('25');
- await userEvent.click(getByRole('button', { name: 'Next' }));
+ userEvent.click(getByRole('button', { name: 'Next' }));
expect(getByTestId('currentIndex')).toHaveTextContent('1');
expect(getByTestId('percentComplete')).toHaveTextContent('50');
- await userEvent.click(getByRole('button', { name: 'Next' }));
+ userEvent.click(getByRole('button', { name: 'Next' }));
expect(getByTestId('currentIndex')).toHaveTextContent('2');
expect(getByTestId('percentComplete')).toHaveTextContent('75');
- await userEvent.click(getByRole('button', { name: 'Next' }));
+ userEvent.click(getByRole('button', { name: 'Next' }));
expect(getByTestId('currentIndex')).toHaveTextContent('3');
expect(getByTestId('percentComplete')).toHaveTextContent('100');
- await userEvent.click(getByRole('button', { name: 'Previous' }));
+ userEvent.click(getByRole('button', { name: 'Previous' }));
expect(getByTestId('currentIndex')).toHaveTextContent('2');
expect(getByTestId('percentComplete')).toHaveTextContent('75');
});
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
index 376236bea7..bc6b7e6dcd 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
@@ -113,8 +113,8 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
const pageType = type;
const {
steps: initialSteps,
- nextStep,
- previousStep,
+ handleNextStep,
+ handlePreviousStep,
currentIndex,
percentComplete,
} = useStepList(FormEnum.MHA, type);
@@ -174,8 +174,8 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
steps,
currentIndex,
percentComplete,
- handleNextStep: nextStep,
- handlePreviousStep: previousStep,
+ handleNextStep,
+ handlePreviousStep,
pageType,
hasCalcValues,
setHasCalcValues,
@@ -202,8 +202,8 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
steps,
currentIndex,
percentComplete,
- nextStep,
- previousStep,
+ handleNextStep,
+ handlePreviousStep,
pageType,
hasCalcValues,
setHasCalcValues,
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.test.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.test.tsx
index fd1c2483d1..febe2682ca 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.test.tsx
@@ -62,7 +62,7 @@ const TestComponent: React.FC = ({
describe('CurrentBoardApproved Component', () => {
it('should render correctly for married person', () => {
- const { getByText, getByRole, getAllByText } = render(
+ const { queryByText, queryByRole, getAllByText } = render(
{
/>,
);
- expect(getByText('Current Board Approved MHA')).toBeInTheDocument();
- expect(getByRole('columnheader', { name: /spouse/i })).toBeInTheDocument();
+ expect(queryByText('Current Board Approved MHA')).toBeInTheDocument();
expect(
- getByRole('columnheader', { name: /mha approved by board/i }),
+ queryByRole('columnheader', { name: /spouse/i }),
).toBeInTheDocument();
expect(
- getByRole('columnheader', { name: /mha claimed in salary/i }),
+ queryByRole('columnheader', { name: /mha approved by board/i }),
+ ).toBeInTheDocument();
+ expect(
+ queryByRole('columnheader', { name: /mha claimed in salary/i }),
).toBeInTheDocument();
- expect(getByRole('cell', { name: 'John' })).toBeInTheDocument();
+ expect(queryByRole('cell', { name: 'John' })).toBeInTheDocument();
expect(getAllByText('$1,500.00')).toHaveLength(2);
expect(getAllByText('Approved on: 1/15/2023')).toHaveLength(2);
- expect(getByText('$1,000.00')).toBeInTheDocument();
+ expect(queryByText('$1,000.00')).toBeInTheDocument();
expect(getAllByText('Last updated: 12/1/2022')).toHaveLength(2);
- expect(getByRole('cell', { name: 'Jane' })).toBeInTheDocument();
- expect(getByText('$500.00')).toBeInTheDocument();
+ expect(queryByRole('cell', { name: 'Jane' })).toBeInTheDocument();
+ expect(queryByText('$500.00')).toBeInTheDocument();
});
it('should render correctly for single person', () => {
- const { getByText, queryByText, getByRole, getAllByText } = render(
+ const { queryByText, queryByRole, getAllByText } = render(
{
/>,
);
- expect(getByText('Current Board Approved MHA')).toBeInTheDocument();
- expect(getByRole('columnheader', { name: /spouse/i })).toBeInTheDocument();
+ expect(queryByText('Current Board Approved MHA')).toBeInTheDocument();
+ expect(
+ queryByRole('columnheader', { name: /spouse/i }),
+ ).toBeInTheDocument();
expect(
- getByRole('columnheader', { name: /mha approved by board/i }),
+ queryByRole('columnheader', { name: /mha approved by board/i }),
).toBeInTheDocument();
expect(
- getByRole('columnheader', { name: /mha claimed in salary/i }),
+ queryByRole('columnheader', { name: /mha claimed in salary/i }),
).toBeInTheDocument();
- expect(getByRole('cell', { name: 'John' })).toBeInTheDocument();
+ expect(queryByRole('cell', { name: 'John' })).toBeInTheDocument();
expect(getAllByText('$1,500.00')).toHaveLength(1);
- expect(getByText('$1,000.00')).toBeInTheDocument();
+ expect(queryByText('$1,000.00')).toBeInTheDocument();
// Spouse data should not be rendered
expect(queryByText('Jane')).not.toBeInTheDocument();
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
index 75c89974e3..936e09c146 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
@@ -54,25 +54,23 @@ export const CurrentBoardApproved: React.FC = ({
return;
}
- try {
- const result = await duplicateMHA({
- variables: {
- input: {
- requestId: requestId,
- },
+ const result = await duplicateMHA({
+ variables: {
+ input: {
+ requestId: requestId,
},
- });
+ },
+ });
- const newRequestId =
- result.data?.duplicateMinistryHousingAllowanceRequest
- ?.ministryHousingAllowanceRequest?.id;
+ const newRequestId =
+ result.data?.duplicateMinistryHousingAllowanceRequest
+ ?.ministryHousingAllowanceRequest.id;
- if (newRequestId) {
- router.push(
- `/accountLists/${accountListId}/reports/housingAllowance/${newRequestId}/edit`,
- );
- }
- } catch (error) {}
+ if (newRequestId) {
+ router.push(
+ `/accountLists/${accountListId}/reports/housingAllowance/${newRequestId}/edit`,
+ );
+ }
};
return (
@@ -101,14 +99,14 @@ export const CurrentBoardApproved: React.FC = ({
>
-
- {t('Spouse')}
+
+ {t('Spouse')}
-
- {t('MHA Approved by Board')}
+
+ {t('MHA Approved by Board')}
-
- {t('MHA Claimed in Salary')}
+
+ {t('MHA Claimed in Salary')}
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
index 93ce92fad5..9b659a221e 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
@@ -134,19 +134,19 @@ describe('Calculation', () => {
});
const input = within(row).getByPlaceholderText(/\$0/i);
- await userEvent.type(input, '100');
+ userEvent.type(input, '100');
expect(input).toHaveValue('100');
- await userEvent.clear(input);
+ userEvent.clear(input);
expect(input).toHaveValue('');
input.focus();
- await userEvent.tab();
+ userEvent.tab();
expect(await findByText('Required field.')).toBeInTheDocument();
const submitButton = getByRole('button', { name: /submit/i });
- await userEvent.click(submitButton);
+ userEvent.click(submitButton);
expect(await findByRole('alert')).toBeInTheDocument();
expect(
@@ -169,7 +169,7 @@ describe('Calculation', () => {
const submitButton = await findByRole('button', { name: /submit/i });
- await userEvent.click(submitButton);
+ userEvent.click(submitButton);
expect(
await findByText('This box must be checked to continue.'),
@@ -209,20 +209,20 @@ describe('Calculation', () => {
expect(phone).toHaveValue('1234567890');
expect(email).toHaveValue('john.doe@cru.org');
- await userEvent.clear(phone);
- await userEvent.tab();
+ userEvent.clear(phone);
+ userEvent.tab();
expect(await findByText('Phone Number is required.')).toBeInTheDocument();
- await userEvent.clear(email);
- await userEvent.tab();
+ userEvent.clear(email);
+ userEvent.tab();
expect(await findByText('Email is required.')).toBeInTheDocument();
- await userEvent.type(phone, 'abc');
- await userEvent.tab();
+ userEvent.type(phone, 'abc');
+ userEvent.tab();
expect(await findByText('Invalid phone number.')).toBeInTheDocument();
- await userEvent.type(email, 'invalid-email');
- await userEvent.tab();
+ userEvent.type(email, 'invalid-email');
+ userEvent.tab();
expect(await findByText('Invalid email address.')).toBeInTheDocument();
});
@@ -250,10 +250,10 @@ describe('Calculation', () => {
});
const input = within(row).getByPlaceholderText(/\$0/i);
- await userEvent.type(input, '0');
+ userEvent.type(input, '0');
input.focus();
- await userEvent.tab();
+ userEvent.tab();
expect(input).toHaveValue('$0.00');
@@ -312,21 +312,20 @@ describe('Calculation', () => {
});
const input5 = within(row5).getByPlaceholderText(/\$0/i);
- await userEvent.type(input1, '1000');
- await userEvent.type(input2, '200');
- await userEvent.type(input3, '300');
- await userEvent.type(input4, '400');
- await userEvent.type(input5, '500');
+ userEvent.type(input1, '1000');
+ userEvent.type(input2, '200');
+ userEvent.type(input3, '300');
+ userEvent.type(input4, '400');
+ userEvent.type(input5, '500');
const checkbox = getByRole('checkbox', {
name: /i understand that my approved/i,
});
- await userEvent.click(checkbox);
+ userEvent.click(checkbox);
const submitButton = getByRole('button', { name: /submit/i });
- await userEvent.click(submitButton);
-
+ userEvent.click(submitButton);
expect(await findByRole('dialog')).toBeInTheDocument();
expect(
@@ -347,7 +346,7 @@ describe('Calculation', () => {
const confirmButton = getByRole('button', { name: /yes, continue/i });
- await userEvent.click(confirmButton);
+ userEvent.click(confirmButton);
await waitFor(() => {
expect(mutationSpy).toHaveBeenCalledTimes(6);
@@ -417,7 +416,7 @@ describe('Calculation', () => {
});
expect(checkbox).not.toBeChecked();
- await userEvent.click(checkbox);
+ userEvent.click(checkbox);
expect(checkbox).toBeChecked();
await waitFor(() =>
diff --git a/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx b/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx
index ced4383953..0a1034fdda 100644
--- a/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx
+++ b/src/components/Reports/SalaryCalculator/SalaryCalculatorContext/SalaryCalculatorContext.tsx
@@ -59,8 +59,13 @@ interface SalaryCalculatorContextProps {
export const SalaryCalculatorProvider: React.FC<
SalaryCalculatorContextProps
> = ({ children }) => {
- const { steps, nextStep, previousStep, currentIndex, percentComplete } =
- useStepList(FormEnum.SalaryCalc);
+ const {
+ steps,
+ handleNextStep,
+ handlePreviousStep,
+ currentIndex,
+ percentComplete,
+ } = useStepList(FormEnum.SalaryCalc);
const [isDrawerOpen, setDrawerOpen] = useState(true);
const { data: hcmData } = useHcmQuery();
@@ -75,8 +80,8 @@ export const SalaryCalculatorProvider: React.FC<
steps,
currentIndex,
percentComplete,
- handleNextStep: nextStep,
- handlePreviousStep: previousStep,
+ handleNextStep,
+ handlePreviousStep,
isDrawerOpen,
setDrawerOpen,
toggleDrawer,
@@ -87,8 +92,8 @@ export const SalaryCalculatorProvider: React.FC<
steps,
currentIndex,
percentComplete,
- nextStep,
- previousStep,
+ handleNextStep,
+ handlePreviousStep,
isDrawerOpen,
toggleDrawer,
hcmData,
diff --git a/src/components/Reports/Shared/CalculationReports/DirectionButtons/DirectionButtons.test.tsx b/src/components/Reports/Shared/CalculationReports/DirectionButtons/DirectionButtons.test.tsx
index 329710506c..48ec0786c8 100644
--- a/src/components/Reports/Shared/CalculationReports/DirectionButtons/DirectionButtons.test.tsx
+++ b/src/components/Reports/Shared/CalculationReports/DirectionButtons/DirectionButtons.test.tsx
@@ -79,7 +79,7 @@ describe('DirectionButtons', () => {
it('calls handleNext when Continue is clicked', async () => {
const { findByRole } = render( );
- await userEvent.click(await findByRole('button', { name: 'Continue' }));
+ userEvent.click(await findByRole('button', { name: 'Continue' }));
expect(handleNextStep).toHaveBeenCalled();
});
@@ -89,7 +89,7 @@ describe('DirectionButtons', () => {
,
);
- await userEvent.click(await findByRole('button', { name: 'Continue' }));
+ userEvent.click(await findByRole('button', { name: 'Continue' }));
expect(handleNextStep).not.toHaveBeenCalled();
expect(overrideNext).toHaveBeenCalled();
@@ -98,7 +98,7 @@ describe('DirectionButtons', () => {
it('calls handlePreviousStep when Back is clicked', async () => {
const { findByRole } = render( );
- await userEvent.click(await findByRole('button', { name: /back/i }));
+ userEvent.click(await findByRole('button', { name: /back/i }));
expect(handlePreviousStep).toHaveBeenCalled();
});
diff --git a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx
index 894a3a23d2..26e4e37681 100644
--- a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx
+++ b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx
@@ -143,12 +143,12 @@ describe('CardSkeleton', () => {
);
const cancelButton = await findByRole('button', { name: 'Cancel Request' });
- await userEvent.click(cancelButton);
+ userEvent.click(cancelButton);
expect(await findByRole('dialog')).toBeInTheDocument();
expect(getByText('Do you want to cancel?')).toBeInTheDocument();
- await userEvent.click(getByRole('button', { name: /yes, cancel/i }));
+ userEvent.click(getByRole('button', { name: /yes, cancel/i }));
expect(queryByRole('dialog')).not.toBeInTheDocument();
});
@@ -171,7 +171,7 @@ describe('CardSkeleton', () => {
const downloadIcon = await findByTestId('FileDownloadIcon');
- await userEvent.click(downloadIcon);
+ userEvent.click(downloadIcon);
expect(handleDownload).toHaveBeenCalled();
});
@@ -182,12 +182,12 @@ describe('CardSkeleton', () => {
);
const cancelButton = await findByRole('button', { name: 'Cancel Request' });
- await userEvent.click(cancelButton);
+ userEvent.click(cancelButton);
expect(await findByRole('dialog')).toBeInTheDocument();
expect(getByText('Do you want to cancel?')).toBeInTheDocument();
- await userEvent.click(getByRole('button', { name: /yes, cancel/i }));
+ userEvent.click(getByRole('button', { name: /yes, cancel/i }));
expect(handleConfirmCancel).toHaveBeenCalled();
diff --git a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
index be1a292d88..5743a98136 100644
--- a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
+++ b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
@@ -122,7 +122,7 @@ export const StatusCard: React.FC = ({
{
expect(result.current.percentComplete).toBe(25);
act(() => {
- result.current.nextStep();
+ result.current.handleNextStep();
});
expect(result.current.currentIndex).toBe(1);
expect(result.current.percentComplete).toBe(50);
@@ -163,7 +163,7 @@ describe('useStepList', () => {
]);
act(() => {
- result.current.nextStep();
+ result.current.handleNextStep();
});
expect(result.current.currentIndex).toBe(2);
expect(result.current.percentComplete).toBe(75);
@@ -191,7 +191,7 @@ describe('useStepList', () => {
]);
act(() => {
- result.current.previousStep();
+ result.current.handlePreviousStep();
});
expect(result.current.currentIndex).toBe(1);
expect(result.current.percentComplete).toBe(50);
@@ -219,7 +219,7 @@ describe('useStepList', () => {
]);
act(() => {
- result.current.previousStep();
+ result.current.handlePreviousStep();
});
expect(result.current.currentIndex).toBe(0);
expect(result.current.percentComplete).toBe(25);
diff --git a/src/hooks/useStepList.ts b/src/hooks/useStepList.ts
index 2e6b8ef5f6..540cf26fec 100644
--- a/src/hooks/useStepList.ts
+++ b/src/hooks/useStepList.ts
@@ -11,8 +11,8 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
const [currentIndex, setCurrentIndex] = useState(0);
- const [steps, setSteps] = useState(() => {
- return formType === FormEnum.MHA
+ const [steps, setSteps] = useState(() =>
+ formType === FormEnum.MHA
? [
{
title: t('1. About this Form'),
@@ -84,15 +84,15 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
complete: false,
},
]
- : [];
- });
+ : [],
+ );
const percentComplete = useMemo(
() => ((currentIndex + 1) / steps.length) * 100,
[currentIndex, steps.length],
);
- const nextStep = useCallback(() => {
+ const handleNextStep = useCallback(() => {
const newIndex = currentIndex + 1;
setSteps((prevSteps) =>
prevSteps.map((step, index) => {
@@ -117,7 +117,7 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
setCurrentIndex(newIndex);
}, [currentIndex]);
- const previousStep = useCallback(() => {
+ const handlePreviousStep = useCallback(() => {
const newIndex = currentIndex - 1;
setSteps((prevSteps) =>
prevSteps.map((step, index) => {
@@ -140,8 +140,8 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
return {
steps,
- nextStep,
- previousStep,
+ handleNextStep,
+ handlePreviousStep,
currentIndex,
percentComplete,
};
From 12f94ed5bda77fc86fe52c0a18737cd04dfa8a9f Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 31 Dec 2025 09:26:38 -0500
Subject: [PATCH 15/36] Fixed failing test
---
.../MhaRequestSection/MhaRequestSection.test.tsx | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/components/Reports/SalaryCalculator/MhaRequestSection/MhaRequestSection.test.tsx b/src/components/Reports/SalaryCalculator/MhaRequestSection/MhaRequestSection.test.tsx
index a3d8be794e..2a614b154e 100644
--- a/src/components/Reports/SalaryCalculator/MhaRequestSection/MhaRequestSection.test.tsx
+++ b/src/components/Reports/SalaryCalculator/MhaRequestSection/MhaRequestSection.test.tsx
@@ -1,4 +1,4 @@
-import { render, waitFor } from '@testing-library/react';
+import { render } from '@testing-library/react';
import { SalaryCalculatorTestWrapper } from '../SalaryCalculatorTestWrapper';
import { MhaRequestSection } from './MhaRequestSection';
@@ -33,11 +33,13 @@ describe('MhaRequestSection', () => {
});
it('should render new requested MHA input fields for both spouses', async () => {
- const { getAllByRole } = render( );
+ const { findAllByRole } = render( );
- await waitFor(() => {
- expect(getAllByRole('textbox')).toHaveLength(2);
- });
+ const enabledTextbox = (await findAllByRole('textbox')).filter(
+ (textbox) => !textbox.hasAttribute('disabled'),
+ );
+
+ expect(enabledTextbox).toHaveLength(2);
});
it('should display progress bar', async () => {
From 0a5a33d47b6e2bc858c9fa5f08549a005cd017ad Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 31 Dec 2025 12:28:25 -0500
Subject: [PATCH 16/36] Fixed broken test
---
.../EffectiveDateStep.test.tsx | 26 ++++++++++---------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/src/components/Reports/SalaryCalculator/EffectiveDateStep/EffectiveDateStep.test.tsx b/src/components/Reports/SalaryCalculator/EffectiveDateStep/EffectiveDateStep.test.tsx
index 4395ad40b1..d655f4f213 100644
--- a/src/components/Reports/SalaryCalculator/EffectiveDateStep/EffectiveDateStep.test.tsx
+++ b/src/components/Reports/SalaryCalculator/EffectiveDateStep/EffectiveDateStep.test.tsx
@@ -9,36 +9,38 @@ const TestComponent = () => (
);
describe('EffectiveDateStep', () => {
- it('renders the heading', () => {
- const { getByRole } = render( );
+ it('renders the heading', async () => {
+ const { findByRole } = render( );
expect(
- getByRole('heading', { name: 'Effective Date' }),
+ await findByRole('heading', { name: 'Effective Date' }),
).toBeInTheDocument();
});
- it('renders the date selection dropdown', () => {
- const { getByRole } = render( );
+ it('renders the date selection dropdown', async () => {
+ const { findByRole } = render( );
expect(
- getByRole('combobox', { name: 'Select a future date' }),
+ await findByRole('combobox', { name: 'Select a future date' }),
).toBeInTheDocument();
});
- it('renders text content', () => {
- const { getByText } = render( );
+ it('renders text content', async () => {
+ const { findByText } = render( );
expect(
- getByText(
+ await findByText(
'Please select the date of the paycheck you would like this change to first occur.',
),
).toBeInTheDocument();
});
- it('renders an empty dropdown when no effective dates are available', () => {
- const { getByRole } = render( );
+ it('renders an empty dropdown when no effective dates are available', async () => {
+ const { findByRole } = render( );
- const dropdown = getByRole('combobox', { name: 'Select a future date' });
+ const dropdown = await findByRole('combobox', {
+ name: 'Select a future date',
+ });
// The dropdown should be empty since hcm.effectiveDates doesn't exist yet
expect(dropdown).toBeInTheDocument();
});
From 2c494fd3ed6416ecd7b21aebd0d8ca738f4757f5 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 31 Dec 2025 14:14:40 -0500
Subject: [PATCH 17/36] Added loading functionality
---
.../MinisterHousingAllowance.tsx | 9 ++--
.../MinisterHousingAllowanceSkeleton.tsx | 8 ++--
.../MinisterHousingAllowanceContext.tsx | 20 +++++---
.../Steps/StepTwo/RentOwn.tsx | 48 +++++++++++--------
.../Steps/StepTwo/RentOwnSkeleton.tsx | 19 ++++++++
src/hooks/useStepList.ts | 10 +---
6 files changed, 71 insertions(+), 43 deletions(-)
create mode 100644 src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwnSkeleton.tsx
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
index 273b282ef9..bb0a8333b8 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
@@ -29,8 +29,11 @@ export const MinisterHousingAllowanceReport = () => {
const { enqueueSnackbar } = useSnackbar();
const accountListId = useAccountListId();
- const { data, error: requestsError } =
- useMinistryHousingAllowanceRequestsQuery();
+ const {
+ data,
+ error: requestsError,
+ loading,
+ } = useMinistryHousingAllowanceRequestsQuery();
const requests = data?.ministryHousingAllowanceRequests.nodes ?? [];
const {
@@ -121,7 +124,7 @@ export const MinisterHousingAllowanceReport = () => {
{requestsError ? (
- ) : !requests ? (
+ ) : loading ? (
) : (
<>
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowanceSkeleton.tsx b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowanceSkeleton.tsx
index 2fa037b925..40271ba4de 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowanceSkeleton.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowanceSkeleton.tsx
@@ -6,7 +6,7 @@ export const MinisterHousingAllowanceReportSkeleton: React.FC = () => {
return (
<>
{
}}
/>
{
}}
/>
{
}}
/>
= ({
type,
children,
}) => {
- const { data: requestData, error: requestError } =
- useMinistryHousingAllowanceRequestQuery({
- variables: {
- ministryHousingAllowanceRequestId: requestId ?? '',
- },
- skip: !requestId,
- });
+ const {
+ data: requestData,
+ error: requestError,
+ loading,
+ } = useMinistryHousingAllowanceRequestQuery({
+ variables: {
+ ministryHousingAllowanceRequestId: requestId ?? '',
+ },
+ skip: !requestId,
+ });
const hasValues = hasPopulatedValues(
requestData?.ministryHousingAllowanceRequest?.requestAttributes ?? null,
@@ -180,6 +184,7 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
setIsComplete,
requestData: requestData?.ministryHousingAllowanceRequest ?? null,
requestError,
+ loading,
requestId,
updateMutation,
}),
@@ -205,6 +210,7 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
setIsComplete,
requestData,
requestError,
+ loading,
requestId,
updateMutation,
],
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx
index 19c2305f43..af99b72cf2 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepTwo/RentOwn.tsx
@@ -17,6 +17,7 @@ import { DirectionButtons } from '../../../Shared/CalculationReports/DirectionBu
import { SubmitModal } from '../../../Shared/CalculationReports/SubmitModal/SubmitModal';
import { FormValues } from '../../RequestPage/RequestPage';
import { useMinisterHousingAllowance } from '../../Shared/Context/MinisterHousingAllowanceContext';
+import { RentOwnSkeleton } from './RentOwnSkeleton';
export const RentOwn: React.FC = () => {
const { t } = useTranslation();
@@ -39,6 +40,7 @@ export const RentOwn: React.FC = () => {
setHasCalcValues,
handlePreviousStep,
requestData,
+ loading,
updateMutation,
} = useMinisterHousingAllowance();
@@ -155,28 +157,32 @@ export const RentOwn: React.FC = () => {
)}
-
-
+ ) : (
+
- }
- label={t('Rent')}
- />
- }
- label={t('Own')}
- />
-
-
+
+ }
+ label={t('Rent')}
+ />
+ }
+ label={t('Own')}
+ />
+
+
+ )}
{isRequestingChange && (
{
+ return (
+ <>
+
+
+ >
+ );
+};
diff --git a/src/hooks/useStepList.ts b/src/hooks/useStepList.ts
index d571c0360e..f2ef4c3a5a 100644
--- a/src/hooks/useStepList.ts
+++ b/src/hooks/useStepList.ts
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
FormEnum,
@@ -10,7 +10,7 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
const { t } = useTranslation();
const isEdit = type === PageEnum.Edit;
- const [currentIndex, setCurrentIndex] = useState(0);
+ const [currentIndex, setCurrentIndex] = useState(() => (isEdit ? 1 : 0));
const [steps, setSteps] = useState(() =>
formType === FormEnum.MHA
@@ -136,12 +136,6 @@ export function useStepList(formType: FormEnum, type?: PageEnum) {
setCurrentIndex(newIndex);
}, [currentIndex]);
- useEffect(() => {
- if (isEdit) {
- handleNextStep();
- }
- }, [isEdit]);
-
return {
steps,
handleNextStep,
From 7c6aab6de224d98bd122a026036fcd3c775012fe Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 31 Dec 2025 14:20:57 -0500
Subject: [PATCH 18/36] Added optional back arrow icon to empty panel
---
.../RequestPage/RequestPage.tsx | 2 +-
.../PanelLayout/PanelLayout.tsx | 38 +++++++++++--------
2 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
index 08489ac42e..5138a5d489 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
@@ -68,7 +68,7 @@ export const RequestPage: React.FC = () => {
panelType={PanelTypeEnum.Empty}
sidebarTitle={t('Your MHA')}
percentComplete={0}
- backHref=""
+ backHref={`/accountLists/${accountListId}/reports/housingAllowance`}
mainContent={
diff --git a/src/components/Reports/Shared/CalculationReports/PanelLayout/PanelLayout.tsx b/src/components/Reports/Shared/CalculationReports/PanelLayout/PanelLayout.tsx
index 1d7f069f50..bd2b385a84 100644
--- a/src/components/Reports/Shared/CalculationReports/PanelLayout/PanelLayout.tsx
+++ b/src/components/Reports/Shared/CalculationReports/PanelLayout/PanelLayout.tsx
@@ -58,11 +58,31 @@ export const PanelLayout: React.FC = ({
const isLastStep = steps ? currentIndex === steps.length - 1 : false;
+ const backArrow = (
+
+ ({
+ color: theme.palette.cruGrayDark.main,
+ })}
+ >
+
+
+
+ );
+
return (
{panelType === PanelTypeEnum.Empty ? (
<>
-
+
+ {backHref !== '' && backArrow}
+
{sidebarTitle && (
@@ -106,21 +126,7 @@ export const PanelLayout: React.FC = ({
{item.icon}
))}
-
- ({
- color: theme.palette.cruGrayDark.main,
- })}
- >
-
-
-
+ {backArrow}
>
)}
From 8da8ccd5d31ba720db7c7174da2cb9c8cecd3c2e Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 31 Dec 2025 14:26:25 -0500
Subject: [PATCH 19/36] Fixed test are adding back arrow
---
.../MinisterHousingAllowance/RequestPage/RequestPage.test.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
index e0be497a59..4ba49cd30f 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
@@ -353,7 +353,7 @@ describe('RequestPage', () => {
describe('View Page', () => {
it('renders empty panel layout,', () => {
- const { getByText, queryByRole, queryByTestId } = render(
+ const { getByText, queryByRole, getByTestId } = render(
{
expect(getByText('Your MHA')).toBeInTheDocument();
expect(queryByRole('progressbar')).not.toBeInTheDocument();
- expect(queryByTestId('ArrowBackIcon')).not.toBeInTheDocument();
+ expect(getByTestId('ArrowBackIcon')).toBeInTheDocument();
});
it('should have disabled text fields', () => {
From b117c1c08d489416e11d0bfdb0d8be4364d36f09 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 31 Dec 2025 14:35:18 -0500
Subject: [PATCH 20/36] Fixed annual total mha not showing up
---
.../Steps/StepThree/Calculation.tsx | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
index 7e7a617151..e37e935138 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
@@ -18,6 +18,7 @@ import { DateTime } from 'luxon';
import { useSnackbar } from 'notistack';
import { Trans, useTranslation } from 'react-i18next';
import * as yup from 'yup';
+import Loading from 'src/components/Loading';
import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
import {
SimpleScreenOnly,
@@ -147,6 +148,7 @@ export const Calculation: React.FC = ({
setIsPrint,
isPrint,
requestData,
+ loading,
updateMutation,
userHcmData,
} = useMinisterHousingAllowance();
@@ -227,6 +229,10 @@ export const Calculation: React.FC = ({
const schema = getValidationSchema(rentOrOwn);
+ if (loading) {
+ ;
+ }
+
return (
initialValues={initialValues}
From 856169c67007fb9a2bf59262945e0ec1ff2e9a0d Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Wed, 31 Dec 2025 14:42:24 -0500
Subject: [PATCH 21/36] More review changes
---
.../SharedComponents/CurrentBoardApproved.tsx | 2 +-
.../Steps/StepThree/CalcComponents/CostOfHome.tsx | 10 +++++-----
.../Steps/StepThree/CalcComponents/FairRentalValue.tsx | 6 +++---
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
index 1a06f61aa6..cb91d3d0b3 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
@@ -175,7 +175,7 @@ export const CurrentBoardApproved: React.FC = ({
{isMarried && (
- {spousePreferredName}
+ {spousePreferredName ? spousePreferredName : 'N/A'}
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.tsx
index 6937a67a1a..e337082bfb 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/CostOfHome.tsx
@@ -56,7 +56,7 @@ export const CostOfHome: React.FC = ({
fullWidth
size="small"
variant="standard"
- placeholder={t('$0')}
+ placeholder={currencyFormat(0, currency, locale)}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="mortgageOrRentPayment"
schema={schema}
@@ -87,7 +87,7 @@ export const CostOfHome: React.FC = ({
fullWidth
size="small"
variant="standard"
- placeholder={t('$0')}
+ placeholder={currencyFormat(0, currency, locale)}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="furnitureCostsTwo"
schema={schema}
@@ -116,7 +116,7 @@ export const CostOfHome: React.FC = ({
fullWidth
size="small"
variant="standard"
- placeholder={t('$0')}
+ placeholder={currencyFormat(0, currency, locale)}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="repairCosts"
schema={schema}
@@ -150,7 +150,7 @@ export const CostOfHome: React.FC = ({
fullWidth
size="small"
variant="standard"
- placeholder={t('$0')}
+ placeholder={currencyFormat(0, currency, locale)}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="avgUtilityTwo"
schema={schema}
@@ -179,7 +179,7 @@ export const CostOfHome: React.FC = ({
fullWidth
size="small"
variant="standard"
- placeholder={t('$0')}
+ placeholder={currencyFormat(0, currency, locale)}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="unexpectedExpenses"
schema={schema}
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.tsx
index 443bac6eb3..b22f4e7f16 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/CalcComponents/FairRentalValue.tsx
@@ -54,7 +54,7 @@ export const FairRentalValue: React.FC = ({ schema }) => {
fullWidth
size="small"
variant="standard"
- placeholder={t('$0')}
+ placeholder={currencyFormat(0, currency, locale)}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="rentalValue"
schema={schema}
@@ -91,7 +91,7 @@ export const FairRentalValue: React.FC = ({ schema }) => {
fullWidth
size="small"
variant="standard"
- placeholder={t('$0')}
+ placeholder={currencyFormat(0, currency, locale)}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="furnitureCostsOne"
schema={schema}
@@ -120,7 +120,7 @@ export const FairRentalValue: React.FC = ({ schema }) => {
fullWidth
size="small"
variant="standard"
- placeholder={t('$0')}
+ placeholder={currencyFormat(0, currency, locale)}
InputProps={{ disableUnderline: true, inputMode: 'decimal' }}
fieldName="avgUtilityOne"
schema={schema}
From 43b1b5f7951d95538ae6def5f2a8a3a42f190be3 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Fri, 2 Jan 2026 14:22:34 -0500
Subject: [PATCH 22/36] Added missing loading
---
.../MinisterHousingAllowance/RequestPage/RequestPage.tsx | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
index 5138a5d489..f170f68400 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
@@ -2,6 +2,7 @@ import { Container, Stack } from '@mui/material';
import { Formik } from 'formik';
import { useTranslation } from 'react-i18next';
import * as yup from 'yup';
+import Loading from 'src/components/Loading/Loading';
import { MhaRentOrOwnEnum } from 'src/graphql/types.generated';
import { useAccountListId } from 'src/hooks/useAccountListId';
import i18n from 'src/lib/i18n';
@@ -45,6 +46,7 @@ export const RequestPage: React.FC = () => {
currentIndex,
setIsComplete,
requestData,
+ loading,
} = useMinisterHousingAllowance();
const request = requestData?.requestAttributes;
@@ -63,6 +65,10 @@ export const RequestPage: React.FC = () => {
const availableDate = mocks[4].mhaDetails.staffMHA?.availableDate ?? '';
const deadlineDate = mocks[4].mhaDetails.staffMHA?.deadlineDate ?? '';
+ if (loading) {
+ return ;
+ }
+
return isView ? (
Date: Tue, 6 Jan 2026 10:48:14 -0500
Subject: [PATCH 23/36] Third round of review changes
---
.../AdditionalSalaryRequest.tsx | 4 ++-
.../RequestPage/RequestPage.tsx | 4 ++-
.../MinisterHousingAllowanceContext.test.tsx | 4 +--
.../Steps/StepThree/Calculation.tsx | 2 +-
.../PanelLayout/BackArrow.test.tsx | 34 ++++++++++++++++++
.../PanelLayout/BackArrow.tsx | 35 +++++++++++++++++++
.../PanelLayout/PanelLayout.tsx | 32 ++++-------------
7 files changed, 84 insertions(+), 31 deletions(-)
create mode 100644 src/components/Reports/Shared/CalculationReports/PanelLayout/BackArrow.test.tsx
create mode 100644 src/components/Reports/Shared/CalculationReports/PanelLayout/BackArrow.tsx
diff --git a/src/components/Reports/AdditionalSalaryRequest/AdditionalSalaryRequest.tsx b/src/components/Reports/AdditionalSalaryRequest/AdditionalSalaryRequest.tsx
index 31937368de..57fd374ee4 100644
--- a/src/components/Reports/AdditionalSalaryRequest/AdditionalSalaryRequest.tsx
+++ b/src/components/Reports/AdditionalSalaryRequest/AdditionalSalaryRequest.tsx
@@ -74,13 +74,15 @@ export const AdditionalSalaryRequest: React.FC = () => {
const { isDrawerOpen, toggleDrawer, steps, currentIndex, percentComplete } =
useAdditionalSalaryRequest();
+ const iconPanelItems = useIconPanelItems(isDrawerOpen, toggleDrawer);
+
return (
}
sidebarTitle={t('Additional Salary Request')}
isSidebarOpen={isDrawerOpen}
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
index f170f68400..bd2ee8b88f 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
@@ -65,6 +65,8 @@ export const RequestPage: React.FC = () => {
const availableDate = mocks[4].mhaDetails.staffMHA?.availableDate ?? '';
const deadlineDate = mocks[4].mhaDetails.staffMHA?.deadlineDate ?? '';
+ const iconPanelItems = useIconPanelItems(isDrawerOpen, toggleDrawer);
+
if (loading) {
return ;
}
@@ -93,7 +95,7 @@ export const RequestPage: React.FC = () => {
) : (
{
expect(getByTestId('currentIndex')).toHaveTextContent('2');
expect(getByTestId('percentComplete')).toHaveTextContent('75');
- await userEvent.click(getByRole('button', { name: 'Previous' }));
+ userEvent.click(getByRole('button', { name: 'Previous' }));
expect(getByTestId('currentIndex')).toHaveTextContent('1');
expect(getByTestId('percentComplete')).toHaveTextContent('50');
- await userEvent.click(getByRole('button', { name: 'Previous' }));
+ userEvent.click(getByRole('button', { name: 'Previous' }));
expect(getByTestId('currentIndex')).toHaveTextContent('0');
expect(getByTestId('percentComplete')).toHaveTextContent('25');
});
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
index e37e935138..7f2c538365 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
@@ -230,7 +230,7 @@ export const Calculation: React.FC = ({
const schema = getValidationSchema(rentOrOwn);
if (loading) {
- ;
+ return ;
}
return (
diff --git a/src/components/Reports/Shared/CalculationReports/PanelLayout/BackArrow.test.tsx b/src/components/Reports/Shared/CalculationReports/PanelLayout/BackArrow.test.tsx
new file mode 100644
index 0000000000..bcd9697ed5
--- /dev/null
+++ b/src/components/Reports/Shared/CalculationReports/PanelLayout/BackArrow.test.tsx
@@ -0,0 +1,34 @@
+import React from 'react';
+import { ThemeProvider } from '@mui/material/styles';
+import { render } from '__tests__/util/testingLibraryReactMock';
+import theme from 'src/theme';
+import { BackArrow } from './BackArrow';
+
+const href = '/test-back';
+const title = 'Go back';
+
+interface TestComponentProps {
+ backTitle?: string;
+}
+
+const TestComponent: React.FC = ({ backTitle }) => (
+
+
+
+);
+
+describe('BackArrow', () => {
+ it('renders BackArrow with provided title', () => {
+ const { getByRole } = render( );
+
+ expect(getByRole('button', { name: title })).toBeInTheDocument();
+ });
+
+ it('renders BackArrow with default title when backTitle is not provided', () => {
+ const { getByRole } = render( );
+
+ expect(
+ getByRole('button', { name: 'Back to dashboard' }),
+ ).toBeInTheDocument();
+ });
+});
diff --git a/src/components/Reports/Shared/CalculationReports/PanelLayout/BackArrow.tsx b/src/components/Reports/Shared/CalculationReports/PanelLayout/BackArrow.tsx
new file mode 100644
index 0000000000..8b1c67f857
--- /dev/null
+++ b/src/components/Reports/Shared/CalculationReports/PanelLayout/BackArrow.tsx
@@ -0,0 +1,35 @@
+import NextLink from 'next/link';
+import React from 'react';
+import ArrowBackIcon from '@mui/icons-material/ArrowBack';
+import { IconButton, Link } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+
+interface BackArrowProps {
+ backHref: string;
+ backTitle?: string;
+}
+
+export const BackArrow: React.FC = ({
+ backHref,
+ backTitle,
+}) => {
+ const { t } = useTranslation();
+
+ return (
+
+ ({
+ color: theme.palette.cruGrayDark.main,
+ })}
+ >
+
+
+
+ );
+};
diff --git a/src/components/Reports/Shared/CalculationReports/PanelLayout/PanelLayout.tsx b/src/components/Reports/Shared/CalculationReports/PanelLayout/PanelLayout.tsx
index bd2b385a84..5f4c732024 100644
--- a/src/components/Reports/Shared/CalculationReports/PanelLayout/PanelLayout.tsx
+++ b/src/components/Reports/Shared/CalculationReports/PanelLayout/PanelLayout.tsx
@@ -1,9 +1,6 @@
-import NextLink from 'next/link';
import React from 'react';
import { CheckCircleOutline } from '@mui/icons-material';
-import ArrowBackIcon from '@mui/icons-material/ArrowBack';
-import { Box, Divider, IconButton, Link, Stack } from '@mui/material';
-import { useTranslation } from 'react-i18next';
+import { Box, Divider, IconButton, Stack } from '@mui/material';
import { CircularProgressWithLabel } from 'src/components/Reports/Shared/CalculationReports/CircularProgressWithLabel/CircularProgressWithLabel';
import {
MainContent,
@@ -16,6 +13,7 @@ import {
import { Steps } from 'src/components/Reports/Shared/CalculationReports/StepsList/StepsList';
import theme from 'src/theme';
import { PanelTypeEnum } from '../Shared/sharedTypes';
+import { BackArrow } from './BackArrow';
export interface IconPanelItem {
key: string;
@@ -54,34 +52,16 @@ export const PanelLayout: React.FC = ({
currentIndex,
steps,
}) => {
- const { t } = useTranslation();
-
const isLastStep = steps ? currentIndex === steps.length - 1 : false;
- const backArrow = (
-
- ({
- color: theme.palette.cruGrayDark.main,
- })}
- >
-
-
-
- );
-
return (
{panelType === PanelTypeEnum.Empty ? (
<>
- {backHref !== '' && backArrow}
+ {backHref && (
+
+ )}
@@ -126,7 +106,7 @@ export const PanelLayout: React.FC = ({
{item.icon}
))}
- {backArrow}
+
>
)}
From 56bba2b18d6c69a9271dee649dbfecd03bd30016 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Tue, 6 Jan 2026 13:13:37 -0500
Subject: [PATCH 24/36] Update wrong refetch query names
---
.../SharedComponents/CurrentRequest.tsx | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
index edfccebd98..4f25ac4dc9 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
@@ -46,9 +46,10 @@ export const CurrentRequest: React.FC = ({ request }) => {
const [deleteRequestMutation] =
useDeleteMinistryHousingAllowanceRequestMutation({
refetchQueries: [
- 'GetMinistryHousingAllowanceRequests',
- 'GetMinistryHousingAllowanceRequest',
+ 'MinistryHousingAllowanceRequests',
+ 'MinistryHousingAllowanceRequest',
],
+ awaitRefetchQueries: true,
});
const handleCancelRequest = async () => {
From 2c9d23c48fdb4e46d4549495ac71187fbdcc9a72 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Fri, 9 Jan 2026 15:36:28 -0500
Subject: [PATCH 25/36] Disabled edit button in certain situations
---
.../housingAllowance/[requestId].page.tsx | 3 +-
.../RequestPage/RequestPage.tsx | 7 ++-
.../Shared/AutoSave/useSaveField.test.tsx | 30 ++++++++++
.../Shared/AutoSave/useSaveField.ts | 11 ++--
.../SharedComponents/CurrentRequest.test.tsx | 26 ++++----
.../SharedComponents/CurrentRequest.tsx | 59 ++++++++++++++++---
.../ReceiptStep/Receipt.tsx | 2 +-
.../StatusCard/StatusCard.test.tsx | 9 +++
.../StatusCard/StatusCard.tsx | 25 ++++----
9 files changed, 132 insertions(+), 40 deletions(-)
diff --git a/pages/accountLists/[accountListId]/reports/housingAllowance/[requestId].page.tsx b/pages/accountLists/[accountListId]/reports/housingAllowance/[requestId].page.tsx
index ff93fe8a63..5200730408 100644
--- a/pages/accountLists/[accountListId]/reports/housingAllowance/[requestId].page.tsx
+++ b/pages/accountLists/[accountListId]/reports/housingAllowance/[requestId].page.tsx
@@ -26,6 +26,7 @@ const RequestPageWrapper = styled(Box)(({ theme }) => ({
const HousingAllowanceRequestPage: React.FC = () => {
const { t } = useTranslation();
const router = useRouter();
+ const [isNavListOpen, setIsNavListOpen] = useState(false);
const { requestId, mode } = router.query;
if (!requestId) {
@@ -54,8 +55,6 @@ const HousingAllowanceRequestPage: React.FC = () => {
mode: pageType,
});
- const [isNavListOpen, setIsNavListOpen] = useState(false);
-
const handleNavListToggle = () => {
setIsNavListOpen(!isNavListOpen);
};
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
index bd2ee8b88f..132a68d7c8 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
@@ -67,6 +67,9 @@ export const RequestPage: React.FC = () => {
const iconPanelItems = useIconPanelItems(isDrawerOpen, toggleDrawer);
+ const editLink = getRequestUrl(accountListId, requestId, 'edit');
+ const viewLink = getRequestUrl(accountListId, requestId, 'view');
+
if (loading) {
return ;
}
@@ -136,9 +139,9 @@ export const RequestPage: React.FC = () => {
{
),
);
});
+
+ it('should not show snackbar if all values are null', async () => {
+ const { result } = renderHook(
+ () =>
+ useSaveField({
+ formValues: { rentalValue: 50 },
+ }),
+ {
+ wrapper: TestComponent,
+ },
+ );
+
+ result.current({ rentalValue: null });
+
+ await waitFor(() =>
+ expect(mutationSpy).toHaveGraphqlOperation(
+ 'UpdateMinistryHousingAllowanceRequest',
+ {
+ input: {
+ requestId: 'request-id',
+ requestAttributes: {
+ rentalValue: null,
+ },
+ },
+ },
+ ),
+ );
+
+ expect(mockEnqueue).not.toHaveBeenCalled();
+ });
});
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
index 15e3b1cc0e..ff36be9ab5 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
@@ -17,9 +17,7 @@ export const useSaveField = ({ formValues }: UseSaveFieldOptions) => {
const { requestData } = useMinisterHousingAllowance();
const [updateMinistryHousingAllowanceRequest] =
- useUpdateMinistryHousingAllowanceRequestMutation({
- refetchQueries: ['MinistryHousingAllowanceRequest'],
- });
+ useUpdateMinistryHousingAllowanceRequestMutation({});
const values = requestData?.requestAttributes;
const saveField = useCallback(
@@ -62,7 +60,12 @@ export const useSaveField = ({ formValues }: UseSaveFieldOptions) => {
},
},
onCompleted: () => {
- enqueueSnackbar(t('Saved successfully'), { variant: 'success' });
+ const hasValue = Object.values(attributes).some(
+ (value) => value !== null,
+ );
+ if (hasValue) {
+ enqueueSnackbar(t('Saved successfully'), { variant: 'success' });
+ }
},
});
},
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx
index 0b97854f67..b5deb47c85 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.test.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
-import { render, waitFor } from '@testing-library/react';
+import { render, screen, waitFor } from '@testing-library/react';
import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
@@ -48,22 +48,26 @@ const TestComponent: React.FC = () => {
describe('CurrentRequest Component', () => {
it('should render correctly', () => {
- const { getByText } = render( );
+ const { getByText, queryByText } = render( );
expect(getByText('Current MHA Request')).toBeInTheDocument();
expect(getByText('View Request')).toBeInTheDocument();
- expect(getByText('Edit Request')).toBeInTheDocument();
+
+ expect(
+ getByText(/this request is still pending board approval/i),
+ ).toBeInTheDocument();
+ expect(queryByText('Edit Request')).not.toBeInTheDocument();
expect(getByText('$15,000.00')).toBeInTheDocument();
- expect(getByText(/Requested on/i)).toBeInTheDocument();
- expect(getByText(/Oct 1, 2019/i)).toBeInTheDocument();
- expect(getByText(/Deadline for changes/i)).toBeInTheDocument();
- expect(getByText(/Oct 23, 2019/i)).toBeInTheDocument();
- expect(getByText(/Board Approval on/i)).toBeInTheDocument();
- expect(getByText(/Oct 30, 2019/i)).toBeInTheDocument();
- expect(getByText(/MHA Available on/i)).toBeInTheDocument();
- expect(getByText(/Nov 20, 2019/i)).toBeInTheDocument();
+ screen.logTestingPlaygroundURL();
+
+ expect(getByText(/Requested on: Oct 1, 2019/i)).toBeInTheDocument();
+ expect(
+ getByText(/Deadline for changes: Oct 23, 2019/i),
+ ).toBeInTheDocument();
+ expect(getByText(/Board Approval on: Oct 30, 2019/i)).toBeInTheDocument();
+ expect(getByText(/MHA Available on: Nov 20, 2019/i)).toBeInTheDocument();
});
it('should call delete mutation on cancel request', async () => {
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
index 4f25ac4dc9..69168e02c0 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
@@ -7,7 +7,7 @@ import {
TimelineItem,
TimelineSeparator,
} from '@mui/lab';
-import { Box, Typography } from '@mui/material';
+import { Alert, Box, Typography } from '@mui/material';
import { DateTime } from 'luxon';
import { useSnackbar } from 'notistack';
import { useTranslation } from 'react-i18next';
@@ -35,6 +35,16 @@ export const CurrentRequest: React.FC = ({ request }) => {
const { status, requestAttributes } = request;
+ const canEdit =
+ status === MhaStatusEnum.InProgress ||
+ status === MhaStatusEnum.ActionRequired;
+ const approved =
+ status === MhaStatusEnum.HrApproved ||
+ status === MhaStatusEnum.BoardApproved;
+
+ const editLink = getRequestUrl(accountListId, requestId, 'edit');
+ const viewLink = getRequestUrl(accountListId, requestId, 'view');
+
const {
boardApprovedDate,
deadlineDate,
@@ -43,6 +53,11 @@ export const CurrentRequest: React.FC = ({ request }) => {
approvedOverallAmount,
} = requestAttributes || {};
+ const pastDeadlineDate = deadlineDate
+ ? DateTime.fromISO(deadlineDate) < DateTime.now()
+ : false;
+ const hideEditButton = !canEdit || pastDeadlineDate;
+
const [deleteRequestMutation] =
useDeleteMinistryHousingAllowanceRequestMutation({
refetchQueries: [
@@ -78,13 +93,31 @@ export const CurrentRequest: React.FC = ({ request }) => {
icon={AddHomeSharp}
iconColor="warning.main"
linkOneText={t('View Request')}
- linkOne={getRequestUrl(accountListId, requestId, 'view')}
+ linkOne={viewLink}
linkTwoText={t('Edit Request')}
- linkTwo={getRequestUrl(accountListId, requestId, 'edit')}
+ linkTwo={editLink}
+ hideLinkTwoButton={hideEditButton}
isRequest={true}
handleConfirmCancel={handleCancelRequest}
>
+ {status === MhaStatusEnum.Pending && (
+
+ {t(
+ 'This request is still pending board approval. You cannot make changes at this time.',
+ )}
+
+ )}
+ {pastDeadlineDate && !approved && (
+
+ {t(
+ 'The deadline to make changes to this request was {{date}}. Please contact support if you need further assistance.',
+ {
+ date: dateFormat(DateTime.fromISO(deadlineDate ?? ''), locale),
+ },
+ )}
+
+ )}
{currencyFormat(approvedOverallAmount || 0, currency, locale, {
@@ -108,7 +141,9 @@ export const CurrentRequest: React.FC = ({ request }) => {
@@ -130,7 +165,9 @@ export const CurrentRequest: React.FC = ({ request }) => {
@@ -146,7 +183,9 @@ export const CurrentRequest: React.FC = ({ request }) => {
@@ -162,7 +201,9 @@ export const CurrentRequest: React.FC = ({ request }) => {
@@ -178,7 +219,9 @@ export const CurrentRequest: React.FC = ({ request }) => {
diff --git a/src/components/Reports/Shared/CalculationReports/ReceiptStep/Receipt.tsx b/src/components/Reports/Shared/CalculationReports/ReceiptStep/Receipt.tsx
index 4cbd9678a5..6ca5253c9d 100644
--- a/src/components/Reports/Shared/CalculationReports/ReceiptStep/Receipt.tsx
+++ b/src/components/Reports/Shared/CalculationReports/ReceiptStep/Receipt.tsx
@@ -46,7 +46,7 @@ export const Receipt: React.FC = ({
? t(`approval effective ${available}`)
: t('approval soon');
- const printLink = `${viewLink}?print=true`;
+ const printLink = `${viewLink}&print=true`;
return (
diff --git a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx
index 26e4e37681..cd0f989201 100644
--- a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx
+++ b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.test.tsx
@@ -30,6 +30,7 @@ interface TestComponentProps {
subtitle?: string;
isRequest?: boolean;
hideDownload?: boolean;
+ hideLinkTwoButton?: boolean;
hideActions?: boolean;
linkOne?: string;
linkTwo?: string;
@@ -40,6 +41,7 @@ const TestComponent: React.FC = ({
isRequest,
hideDownload = false,
hideActions = false,
+ hideLinkTwoButton,
linkOne,
linkTwo,
}) => {
@@ -60,6 +62,7 @@ const TestComponent: React.FC = ({
isRequest={isRequest}
hideDownload={hideDownload}
hideActions={hideActions}
+ hideLinkTwoButton={hideLinkTwoButton}
linkOne={linkOne}
linkTwo={linkTwo}
handleDownload={handleDownload}
@@ -193,4 +196,10 @@ describe('CardSkeleton', () => {
expect(queryByRole('dialog')).not.toBeInTheDocument();
});
+
+ it('should hide second button when hideLinkTwoButton is true', () => {
+ const { queryByText } = render( );
+
+ expect(queryByText(titleTwo)).not.toBeInTheDocument();
+ });
});
diff --git a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
index 5743a98136..e4d137c639 100644
--- a/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
+++ b/src/components/Reports/Shared/CalculationReports/StatusCard/StatusCard.tsx
@@ -18,9 +18,6 @@ import {
import { useTranslation } from 'react-i18next';
import { SubmitModal } from '../SubmitModal/SubmitModal';
-//TODO: handle cancel request
-//TODO: handle duplicate last years mha and view current mha links
-
interface StatusCardProps {
formType: string;
title: string;
@@ -35,6 +32,7 @@ interface StatusCardProps {
isRequest?: boolean;
hideDownload?: boolean;
hideActions?: boolean;
+ hideLinkTwoButton?: boolean;
handleDownload?: () => void;
handleConfirmCancel: () => void;
handleLinkTwo?: () => void;
@@ -55,6 +53,7 @@ export const StatusCard: React.FC = ({
isRequest,
hideDownload,
hideActions,
+ hideLinkTwoButton,
handleDownload,
handleConfirmCancel,
handleLinkTwo,
@@ -120,15 +119,17 @@ export const StatusCard: React.FC = ({
>
{linkOneText}
-
- {linkTwoText}
-
+ {!hideLinkTwoButton && (
+
+ {linkTwoText}
+
+ )}
{isRequest && (
Date: Fri, 9 Jan 2026 16:25:47 -0500
Subject: [PATCH 26/36] Improved transitions between mutations
---
.../MinisterHousingAllowance.tsx | 11 +++++------
.../SharedComponents/CurrentBoardApproved.tsx | 17 +++++++----------
.../SharedComponents/CurrentRequest.tsx | 11 ++---------
3 files changed, 14 insertions(+), 25 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
index bb0a8333b8..cf9e29632e 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
@@ -153,14 +153,13 @@ export const MinisterHousingAllowanceReport = () => {
{t('Request New MHA')}
)}
+ {previousApprovedRequest && (
+
+
+
+ )}
>
)}
-
- {previousApprovedRequest && (
-
-
-
- )}
}
/>
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
index cb91d3d0b3..8d0082012f 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
@@ -35,12 +35,9 @@ export const CurrentBoardApproved: React.FC = ({
const router = useRouter();
const currency = 'USD';
- const [duplicateMHA] = useDuplicateMinistryHousingAllowanceRequestMutation({
- refetchQueries: [
- 'MinistryHousingAllowanceRequests',
- 'MinistryHousingAllowanceRequest',
- ],
- });
+ const [duplicateMHA] = useDuplicateMinistryHousingAllowanceRequestMutation(
+ {},
+ );
const { isMarried, preferredName, spousePreferredName } =
useMinisterHousingAllowance();
@@ -51,6 +48,8 @@ export const CurrentBoardApproved: React.FC = ({
const lastUpdated = request?.updatedAt ?? null;
+ const viewLink = getRequestUrl(accountListId, requestId, 'view');
+
const handleDuplicateRequest = async () => {
if (!requestId) {
return;
@@ -69,9 +68,7 @@ export const CurrentBoardApproved: React.FC = ({
?.ministryHousingAllowanceRequest.id;
if (newRequestId) {
- router.push(
- `/accountLists/${accountListId}/reports/housingAllowance/${newRequestId}/edit`,
- );
+ router.push(getRequestUrl(accountListId, newRequestId, 'edit'));
}
};
@@ -83,7 +80,7 @@ export const CurrentBoardApproved: React.FC = ({
icon={HomeSharp}
iconColor="success.main"
linkOneText={t('View Current MHA')}
- linkOne={getRequestUrl(accountListId, requestId, 'view')}
+ linkOne={viewLink}
linkTwoText={t('Update Current MHA')}
handleLinkTwo={handleDuplicateRequest}
isRequest={false}
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
index 69168e02c0..666cb7fc77 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
@@ -60,10 +60,7 @@ export const CurrentRequest: React.FC = ({ request }) => {
const [deleteRequestMutation] =
useDeleteMinistryHousingAllowanceRequestMutation({
- refetchQueries: [
- 'MinistryHousingAllowanceRequests',
- 'MinistryHousingAllowanceRequest',
- ],
+ refetchQueries: ['MinistryHousingAllowanceRequests'],
awaitRefetchQueries: true,
});
@@ -79,11 +76,7 @@ export const CurrentRequest: React.FC = ({ request }) => {
enqueueSnackbar(t('MHA request cancelled successfully.'), {
variant: 'success',
});
- } catch (error) {
- enqueueSnackbar(t('Failed to cancel your MHA request.'), {
- variant: 'error',
- });
- }
+ } catch (error) {}
};
return (
From 8eb6764418e2b29ee6ef14dc781ee9cf12772dd2 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Mon, 12 Jan 2026 12:09:04 -0500
Subject: [PATCH 27/36] Added no edit access page
---
.../MinisterHousingAllowance.tsx | 1 -
.../RequestPage/RequestPage.test.tsx | 83 +++++++++++++++----
.../RequestPage/RequestPage.tsx | 25 +++++-
.../CurrentBoardApproved.test.tsx | 2 +-
.../Steps/NoEditAccess/NoEditAccess.test.tsx | 28 +++++++
.../Steps/NoEditAccess/NoEditAccess.tsx | 40 +++++++++
6 files changed, 161 insertions(+), 18 deletions(-)
create mode 100644 src/components/Reports/MinisterHousingAllowance/Steps/NoEditAccess/NoEditAccess.test.tsx
create mode 100644 src/components/Reports/MinisterHousingAllowance/Steps/NoEditAccess/NoEditAccess.tsx
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
index cf9e29632e..87e4fa14e6 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.tsx
@@ -66,7 +66,6 @@ export const MinisterHousingAllowanceReport = () => {
emailAddress: userHcmData?.staffInfo.emailAddress,
},
},
- refetchQueries: ['MinistryHousingAllowanceRequests'],
onCompleted: ({ createMinistryHousingAllowanceRequest: newRequest }) => {
enqueueSnackbar(
t("Successfully created MHA Request. You'll be redirected shortly."),
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
index 4ba49cd30f..c297ab87d3 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
@@ -5,10 +5,13 @@ import userEvent from '@testing-library/user-event';
import { SnackbarProvider } from 'notistack';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
-import { MhaRentOrOwnEnum } from 'src/graphql/types.generated';
+import { MhaRentOrOwnEnum, MhaStatusEnum } from 'src/graphql/types.generated';
import theme from 'src/theme';
import { PageEnum } from '../../Shared/CalculationReports/Shared/sharedTypes';
-import { UpdateMinistryHousingAllowanceRequestMutation } from '../MinisterHousingAllowance.generated';
+import {
+ MinistryHousingAllowanceRequestQuery,
+ UpdateMinistryHousingAllowanceRequestMutation,
+} from '../MinisterHousingAllowance.generated';
import {
ContextType,
MinisterHousingAllowanceContext,
@@ -72,6 +75,7 @@ const TestComponent: React.FC = ({
onCall={mutationSpy}
@@ -87,7 +91,18 @@ const TestComponent: React.FC = ({
describe('RequestPage', () => {
it('renders steps list', async () => {
const { getByText, findByText } = render(
- ,
+ ,
);
expect(await findByText(/1. about this form/i)).toBeInTheDocument();
@@ -97,20 +112,22 @@ describe('RequestPage', () => {
});
describe('Edit Page', () => {
- it('starts on step 2 and updates steps when Continue clicked', () => {
- const { getByRole, getAllByRole, getByText, queryByTestId } = render(
- ,
- );
+ it('starts on step 2 and updates steps when Continue clicked', async () => {
+ const { getByRole, getAllByRole, getByText, queryByTestId, findByRole } =
+ render( );
- expect(getByRole('progressbar')).toHaveAttribute('aria-valuenow', '50');
+ expect(await findByRole('progressbar')).toHaveAttribute(
+ 'aria-valuenow',
+ '50',
+ );
expect(queryByTestId('ArrowBackIcon')).toBeInTheDocument();
const continueButton = getByRole('button', { name: 'Continue' });
userEvent.click(continueButton);
- const steps = getAllByRole('listitem');
+ const stepItems = getAllByRole('listitem');
- const [firstStep, secondStep, thirdStep] = steps;
+ const [firstStep, secondStep, thirdStep] = stepItems;
expect(firstStep).toHaveTextContent('1. About this Form');
expect(
@@ -156,6 +173,7 @@ describe('RequestPage', () => {
handlePreviousStep,
requestData: {
id: 'request-id',
+ status: MhaStatusEnum.InProgress,
requestAttributes: {
rentOrOwn: MhaRentOrOwnEnum.Rent,
},
@@ -187,6 +205,7 @@ describe('RequestPage', () => {
updateMutation,
requestData: {
id: 'request-id',
+ status: MhaStatusEnum.InProgress,
requestAttributes: {
rentOrOwn: MhaRentOrOwnEnum.Rent,
rentalValue: 1000,
@@ -276,11 +295,17 @@ describe('RequestPage', () => {
it('should show validation error if continue is clicked without selecting an option', async () => {
const { getByRole, findByRole } = render(
,
);
@@ -312,6 +337,7 @@ describe('RequestPage', () => {
setIsPrint,
requestData: {
id: 'request-id',
+ status: MhaStatusEnum.InProgress,
requestAttributes: {
rentOrOwn: null,
rentalValue: 1000,
@@ -387,4 +413,31 @@ describe('RequestPage', () => {
expect(input).toBeDisabled();
});
});
+
+ describe('Permission Denied', () => {
+ it('renders permission denied layout', () => {
+ const { getByText, queryByRole, getByTestId } = render(
+ ,
+ );
+
+ expect(getByText('Your MHA')).toBeInTheDocument();
+ expect(queryByRole('progressbar')).not.toBeInTheDocument();
+ expect(getByTestId('ArrowBackIcon')).toBeInTheDocument();
+ expect(
+ getByText('You do not have permission to edit this request.'),
+ ).toBeInTheDocument();
+ });
+ });
});
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
index 132a68d7c8..4966b8baf5 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
@@ -3,9 +3,10 @@ import { Formik } from 'formik';
import { useTranslation } from 'react-i18next';
import * as yup from 'yup';
import Loading from 'src/components/Loading/Loading';
-import { MhaRentOrOwnEnum } from 'src/graphql/types.generated';
+import { MhaRentOrOwnEnum, MhaStatusEnum } from 'src/graphql/types.generated';
import { useAccountListId } from 'src/hooks/useAccountListId';
import i18n from 'src/lib/i18n';
+import theme from 'src/theme';
import { PanelLayout } from '../../Shared/CalculationReports/PanelLayout/PanelLayout';
import { useIconPanelItems } from '../../Shared/CalculationReports/PanelLayout/useIconPanelItems';
import { Receipt } from '../../Shared/CalculationReports/ReceiptStep/Receipt';
@@ -18,10 +19,13 @@ import { mainContentWidth } from '../MinisterHousingAllowance';
import { useMinisterHousingAllowance } from '../Shared/Context/MinisterHousingAllowanceContext';
import { getRequestUrl } from '../Shared/Helper/getRequestUrl';
import { mocks } from '../Shared/mockData';
+import { NoEditAccess } from '../Steps/NoEditAccess/NoEditAccess';
import { AboutForm } from '../Steps/StepOne/AboutForm';
import { Calculation } from '../Steps/StepThree/Calculation';
import { RentOwn } from '../Steps/StepTwo/RentOwn';
+const permissionDeniedWidth = theme.spacing(100);
+
export interface FormValues {
rentOrOwn: MhaRentOrOwnEnum | undefined;
}
@@ -49,6 +53,11 @@ export const RequestPage: React.FC = () => {
loading,
} = useMinisterHousingAllowance();
+ const canEdit =
+ !requestData ||
+ requestData.status === MhaStatusEnum.InProgress ||
+ requestData.status === MhaStatusEnum.ActionRequired;
+
const request = requestData?.requestAttributes;
const value = request?.rentOrOwn ?? undefined;
@@ -95,6 +104,20 @@ export const RequestPage: React.FC = () => {
}
/>
+ ) : !canEdit ? (
+
+
+
+
+
+ }
+ />
) : (
{
await waitFor(() => {
expect(mockPush).toHaveBeenCalledWith(
- `/accountLists/account-list-1/reports/housingAllowance/${newRequestId}/edit`,
+ `/accountLists/account-list-1/reports/housingAllowance/${newRequestId}?mode=edit`,
);
});
});
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/NoEditAccess/NoEditAccess.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/NoEditAccess/NoEditAccess.test.tsx
new file mode 100644
index 0000000000..e35658638d
--- /dev/null
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/NoEditAccess/NoEditAccess.test.tsx
@@ -0,0 +1,28 @@
+import { ThemeProvider } from '@mui/material/styles';
+import { render } from '@testing-library/react';
+import theme from 'src/theme';
+import { NoEditAccess } from './NoEditAccess';
+
+const Components = () => (
+
+
+
+);
+
+describe('NoEditAccess', () => {
+ it('should render the NoEditAccess component and support link', () => {
+ const { getByText, getByRole } = render( );
+
+ expect(
+ getByRole('heading', {
+ name: 'You do not have permission to edit this request.',
+ }),
+ ).toBeInTheDocument();
+ expect(
+ getByText(
+ /our records show that this request is either approved or under review/i,
+ ),
+ ).toBeInTheDocument();
+ expect(getByRole('link', { name: 'support@mpdx.org' })).toBeInTheDocument();
+ });
+});
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/NoEditAccess/NoEditAccess.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/NoEditAccess/NoEditAccess.tsx
new file mode 100644
index 0000000000..c18076889d
--- /dev/null
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/NoEditAccess/NoEditAccess.tsx
@@ -0,0 +1,40 @@
+import Link from 'next/link';
+import React from 'react';
+import { Box, Container, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import theme from 'src/theme';
+
+export const NoEditAccess: React.FC = () => {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ {t('You do not have permission to edit this request.')}
+
+
+
+ {t(
+ 'Our records show that this request is either approved or under review. If you believe you should have access to edit this request, please contact ',
+ )}
+
+ support@mpdx.org
+
+ .
+
+
+
+ );
+};
From eb8d8b8cc4b5e57f6d57d7fa145ecc3b18150397 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Mon, 12 Jan 2026 12:43:12 -0500
Subject: [PATCH 28/36] Added no request access component
---
.../RequestPage/RequestPage.test.tsx | 34 +++++++++++++--
.../RequestPage/RequestPage.tsx | 16 ++++++++
.../MinisterHousingAllowanceContext.tsx | 8 ++++
.../NoRequestAccess/NoRequestAccess.test.tsx | 26 ++++++++++++
.../Steps/NoRequestAccess/NoRequestAccess.tsx | 41 +++++++++++++++++++
.../Reports/Shared/HcmData/HCMData.graphql | 3 ++
.../Reports/Shared/HcmData/mockData.ts | 3 ++
7 files changed, 127 insertions(+), 4 deletions(-)
create mode 100644 src/components/Reports/MinisterHousingAllowance/Steps/NoRequestAccess/NoRequestAccess.test.tsx
create mode 100644 src/components/Reports/MinisterHousingAllowance/Steps/NoRequestAccess/NoRequestAccess.tsx
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
index c297ab87d3..e6a1e0dcb5 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
@@ -8,6 +8,8 @@ import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { MhaRentOrOwnEnum, MhaStatusEnum } from 'src/graphql/types.generated';
import theme from 'src/theme';
import { PageEnum } from '../../Shared/CalculationReports/Shared/sharedTypes';
+import { HcmDataQuery } from '../../Shared/HcmData/HCMData.generated';
+import { singleMhaNoException } from '../../Shared/HcmData/mockData';
import {
MinistryHousingAllowanceRequestQuery,
UpdateMinistryHousingAllowanceRequestMutation,
@@ -52,11 +54,17 @@ const steps = [
interface TestComponentProps {
type?: PageEnum;
contextValue?: Partial;
+ mocks?: {
+ HcmData?: HcmDataQuery;
+ MinistryHousingAllowanceRequest?: MinistryHousingAllowanceRequestQuery;
+ UpdateMinistryHousingAllowanceRequest?: UpdateMinistryHousingAllowanceRequestMutation;
+ };
}
const TestComponent: React.FC = ({
type,
contextValue,
+ mocks,
}) => {
const content = contextValue ? (
= ({
+ mocks={mocks}
onCall={mutationSpy}
>
{content}
@@ -96,6 +106,7 @@ describe('RequestPage', () => {
contextValue={
{
steps,
+ userEligibleForMHA: true,
requestData: {
id: 'request-id',
status: MhaStatusEnum.InProgress,
@@ -171,6 +182,7 @@ describe('RequestPage', () => {
steps,
handleNextStep,
handlePreviousStep,
+ userEligibleForMHA: true,
requestData: {
id: 'request-id',
status: MhaStatusEnum.InProgress,
@@ -203,6 +215,7 @@ describe('RequestPage', () => {
hasCalcValues: true,
setHasCalcValues,
updateMutation,
+ userEligibleForMHA: true,
requestData: {
id: 'request-id',
status: MhaStatusEnum.InProgress,
@@ -238,11 +251,22 @@ describe('RequestPage', () => {
describe('New Page', () => {
it('updates steps when Continue clicked', async () => {
- const { getByRole, getAllByRole, getByText, queryByTestId } = render(
- ,
- );
+ const { getByRole, getAllByRole, getByText, queryByTestId, findByRole } =
+ render(
+ ,
+ );
- expect(getByRole('progressbar')).toHaveAttribute('aria-valuenow', '25');
+ expect(await findByRole('progressbar')).toHaveAttribute(
+ 'aria-valuenow',
+ '25',
+ );
expect(queryByTestId('ArrowBackIcon')).toBeInTheDocument();
const continueButton = getByRole('button', { name: 'Continue' });
@@ -300,6 +324,7 @@ describe('RequestPage', () => {
steps,
currentIndex: 1,
pageType: PageEnum.New,
+ userEligibleForMHA: true,
requestData: {
id: 'request-id',
status: MhaStatusEnum.InProgress,
@@ -335,6 +360,7 @@ describe('RequestPage', () => {
setHasCalcValues,
updateMutation,
setIsPrint,
+ userEligibleForMHA: true,
requestData: {
id: 'request-id',
status: MhaStatusEnum.InProgress,
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
index 4966b8baf5..eda8fc8ca4 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
@@ -20,6 +20,7 @@ import { useMinisterHousingAllowance } from '../Shared/Context/MinisterHousingAl
import { getRequestUrl } from '../Shared/Helper/getRequestUrl';
import { mocks } from '../Shared/mockData';
import { NoEditAccess } from '../Steps/NoEditAccess/NoEditAccess';
+import { NoRequestAccess } from '../Steps/NoRequestAccess/NoRequestAccess';
import { AboutForm } from '../Steps/StepOne/AboutForm';
import { Calculation } from '../Steps/StepThree/Calculation';
import { RentOwn } from '../Steps/StepTwo/RentOwn';
@@ -51,6 +52,7 @@ export const RequestPage: React.FC = () => {
setIsComplete,
requestData,
loading,
+ userEligibleForMHA,
} = useMinisterHousingAllowance();
const canEdit =
@@ -118,6 +120,20 @@ export const RequestPage: React.FC = () => {
}
/>
+ ) : !userEligibleForMHA ? (
+
+
+
+
+
+ }
+ />
) : (
= ({
[spouseHcmData],
);
+ const userEligibleForMHA = useMemo(
+ () => userHcmData?.mhaEit?.mhaEligibility ?? false,
+ [userHcmData],
+ );
+
const [isDrawerOpen, setIsDrawerOpen] = useState(true);
const toggleDrawer = useCallback(() => {
setIsDrawerOpen((prev) => !prev);
@@ -179,6 +185,7 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
spouseHcmData,
preferredName,
spousePreferredName,
+ userEligibleForMHA,
isPrint,
setIsPrint,
setIsComplete,
@@ -205,6 +212,7 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
spouseHcmData,
preferredName,
spousePreferredName,
+ userEligibleForMHA,
isPrint,
setIsPrint,
setIsComplete,
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/NoRequestAccess/NoRequestAccess.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/NoRequestAccess/NoRequestAccess.test.tsx
new file mode 100644
index 0000000000..01585ec5f0
--- /dev/null
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/NoRequestAccess/NoRequestAccess.test.tsx
@@ -0,0 +1,26 @@
+import { ThemeProvider } from '@mui/material/styles';
+import { render } from '@testing-library/react';
+import theme from 'src/theme';
+import { NoRequestAccess } from './NoRequestAccess';
+
+const Components = () => (
+
+
+
+);
+
+describe('NoRequestAccess', () => {
+ it('should render the NoRequestAccess component and support link', () => {
+ const { getByText, getByRole } = render( );
+
+ expect(
+ getByRole('heading', {
+ name: 'You do not have permission to request a ministry housing allowance.',
+ }),
+ ).toBeInTheDocument();
+ expect(
+ getByText(/our records show that you are not eligible to apply for/i),
+ ).toBeInTheDocument();
+ expect(getByRole('link', { name: 'support@mpdx.org' })).toBeInTheDocument();
+ });
+});
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/NoRequestAccess/NoRequestAccess.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/NoRequestAccess/NoRequestAccess.tsx
new file mode 100644
index 0000000000..96e70f8556
--- /dev/null
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/NoRequestAccess/NoRequestAccess.tsx
@@ -0,0 +1,41 @@
+import Link from 'next/link';
+import React from 'react';
+import { Box, Container, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import theme from 'src/theme';
+
+export const NoRequestAccess: React.FC = () => {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ {t(
+ 'You do not have permission to request a ministry housing allowance.',
+ )}
+
+
+
+ {t(
+ "Our records show that you are not eligible to apply for Minister's Housing Allowance. If you believe otherwise, please contact ",
+ )}
+
+ support@mpdx.org
+
+
+
+
+ );
+};
diff --git a/src/components/Reports/Shared/HcmData/HCMData.graphql b/src/components/Reports/Shared/HcmData/HCMData.graphql
index a2ba094540..c068fb40fc 100644
--- a/src/components/Reports/Shared/HcmData/HCMData.graphql
+++ b/src/components/Reports/Shared/HcmData/HCMData.graphql
@@ -29,6 +29,9 @@ query HcmData {
lastUpdatedDate
currentApprovedAmountForStaff
}
+ mhaEit {
+ mhaEligibility
+ }
exceptionSalaryCap {
amount
effectiveDate
diff --git a/src/components/Reports/Shared/HcmData/mockData.ts b/src/components/Reports/Shared/HcmData/mockData.ts
index 393b130ee5..9deabdea7a 100644
--- a/src/components/Reports/Shared/HcmData/mockData.ts
+++ b/src/components/Reports/Shared/HcmData/mockData.ts
@@ -46,6 +46,9 @@ const noMhaAndNoException: HcmDataQuery['hcm'][0] = {
lastUpdatedDate: null,
currentApprovedAmountForStaff: null,
},
+ mhaEit: {
+ mhaEligibility: true,
+ },
exceptionSalaryCap: {
amount: null,
effectiveDate: null,
From 8b4eec2183c665a5861cab01787eb226f789b319 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Mon, 12 Jan 2026 12:50:15 -0500
Subject: [PATCH 29/36] Fixed missed error
---
.../SalaryCalculator/StepNavigation/StepNavigation.tsx | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/src/components/Reports/SalaryCalculator/StepNavigation/StepNavigation.tsx b/src/components/Reports/SalaryCalculator/StepNavigation/StepNavigation.tsx
index f7882cdae6..3fe744266f 100644
--- a/src/components/Reports/SalaryCalculator/StepNavigation/StepNavigation.tsx
+++ b/src/components/Reports/SalaryCalculator/StepNavigation/StepNavigation.tsx
@@ -4,7 +4,6 @@ import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import { Box, Button, Stack, Typography } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { useTranslation } from 'react-i18next';
-import { SalaryCalculatorSectionEnum } from '../SalaryCalculatorContext/Helper/sharedTypes';
import { useSalaryCalculator } from '../SalaryCalculatorContext/SalaryCalculatorContext';
import { useSubmitSalaryCalculationMutation } from './SubmitSalaryCalculation.generated';
@@ -76,17 +75,13 @@ export const SubmitButton: React.FC = () => {
export const StepNavigation: React.FC = () => {
const theme = useTheme();
- const { currentStep } = useSalaryCalculator();
+ const { currentIndex } = useSalaryCalculator();
return (
- {currentStep === SalaryCalculatorSectionEnum.Summary ? (
-
- ) : (
-
- )}
+ {currentIndex === 3 ? : }
);
From c2b0491e863d3239bf4a68e517796a9cfea6c67b Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Mon, 12 Jan 2026 14:39:09 -0500
Subject: [PATCH 30/36] Claude review suggestions part 2
---
.../MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts | 2 +-
.../Shared/Context/MinisterHousingAllowanceContext.tsx | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
index ff36be9ab5..4364c1d72a 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/AutoSave/useSaveField.ts
@@ -69,7 +69,7 @@ export const useSaveField = ({ formValues }: UseSaveFieldOptions) => {
},
});
},
- [formValues, updateMinistryHousingAllowanceRequest, requestData],
+ [formValues, updateMinistryHousingAllowanceRequest, requestData, t],
);
return saveField;
diff --git a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
index c14dd39d8f..94ded2bac7 100644
--- a/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx
@@ -164,7 +164,7 @@ export const MinisterHousingAllowanceProvider: React.FC = ({
setIsDrawerOpen((prev) => !prev);
}, []);
- const [hasCalcValues, setHasCalcValues] = useState(hasValues ? true : false);
+ const [hasCalcValues, setHasCalcValues] = useState(hasValues);
const [isPrint, setIsPrint] = useState(false);
const contextValue = useMemo(
From 6dae0358582c5288c54090994bde6e51119af1e8 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Mon, 12 Jan 2026 15:01:21 -0500
Subject: [PATCH 31/36] Fixed failing tests
---
.../Steps/StepThree/Calculation.test.tsx | 2 +-
.../Reports/SalaryCalculator/Receipt/Receipt.test.tsx | 6 +++---
.../SalaryCalculator/Summary/ContactInfoForm.test.tsx | 8 +++++---
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
index 9b659a221e..e5134ef417 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
@@ -219,7 +219,7 @@ describe('Calculation', () => {
userEvent.type(phone, 'abc');
userEvent.tab();
- expect(await findByText('Invalid phone number.')).toBeInTheDocument();
+ expect(await findByText('Invalid phone number')).toBeInTheDocument();
userEvent.type(email, 'invalid-email');
userEvent.tab();
diff --git a/src/components/Reports/SalaryCalculator/Receipt/Receipt.test.tsx b/src/components/Reports/SalaryCalculator/Receipt/Receipt.test.tsx
index 8e441c39a5..9a211ed840 100644
--- a/src/components/Reports/SalaryCalculator/Receipt/Receipt.test.tsx
+++ b/src/components/Reports/SalaryCalculator/Receipt/Receipt.test.tsx
@@ -31,10 +31,10 @@ describe('Receipt step', () => {
).toBeInTheDocument();
});
- it('should show summary when user clicks to view receipt', () => {
- const { getByText, getByRole } = render( );
+ it('should show summary when user clicks to view receipt', async () => {
+ const { getByText, findByRole } = render( );
- userEvent.click(getByRole('button', { name: /View or print/ }));
+ userEvent.click(await findByRole('button', { name: /View or print/ }));
expect(getByText('New Salary Calculation Summary')).toBeInTheDocument();
});
});
diff --git a/src/components/Reports/SalaryCalculator/Summary/ContactInfoForm.test.tsx b/src/components/Reports/SalaryCalculator/Summary/ContactInfoForm.test.tsx
index 502d1ab7d8..961e062d4d 100644
--- a/src/components/Reports/SalaryCalculator/Summary/ContactInfoForm.test.tsx
+++ b/src/components/Reports/SalaryCalculator/Summary/ContactInfoForm.test.tsx
@@ -9,10 +9,12 @@ const TestComponent: React.FC = () => (
);
describe('ContactInfoForm', () => {
- it('renders the inputs', () => {
- const { getByRole } = render( );
+ it('renders the inputs', async () => {
+ const { getByRole, findByRole } = render( );
- expect(getByRole('textbox', { name: 'Phone Number' })).toBeInTheDocument();
+ expect(
+ await findByRole('textbox', { name: 'Phone Number' }),
+ ).toBeInTheDocument();
expect(getByRole('textbox', { name: 'Email' })).toBeInTheDocument();
});
});
From 9fc1fc79e69fdaea4e969f8bfab2b020a59df210 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Fri, 16 Jan 2026 10:39:28 -0500
Subject: [PATCH 32/36] Removed duplicate field
---
src/components/Reports/Shared/HcmData/mockData.ts | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/components/Reports/Shared/HcmData/mockData.ts b/src/components/Reports/Shared/HcmData/mockData.ts
index f4e46864d5..f0d8dc3419 100644
--- a/src/components/Reports/Shared/HcmData/mockData.ts
+++ b/src/components/Reports/Shared/HcmData/mockData.ts
@@ -78,9 +78,6 @@ const noMhaAndNoException: HcmDataQuery['hcm'][0] = {
grossSalaryAmount: 60000,
lastRegularPaymentDate: null,
},
- mhaEit: {
- mhaEligibility: true,
- },
};
const mhaAndNoException: HcmDataQuery['hcm'][0] = {
From c8646cf533dc0a842ea3a1863a966a98e3d78051 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Fri, 16 Jan 2026 10:50:12 -0500
Subject: [PATCH 33/36] Removed duplicate fields that were removed from backend
---
.../MinisterHousingAllowance.graphql | 8 ++--
.../RequestPage/RequestPage.tsx | 10 ++---
.../Shared/mockData.tsx | 42 ++++++++-----------
.../CurrentBoardApproved.test.tsx | 2 +-
.../SharedComponents/CurrentBoardApproved.tsx | 10 ++---
.../SharedComponents/CurrentRequest.tsx | 12 +++---
.../Steps/StepOne/AboutForm.test.tsx | 4 +-
.../Steps/StepOne/AboutForm.tsx | 8 ++--
.../Steps/StepThree/Calculation.test.tsx | 8 ++--
.../Steps/StepThree/Calculation.tsx | 8 ++--
.../MinisterHousingAllowance/mockData.ts | 8 ++--
11 files changed, 57 insertions(+), 63 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
index 8c1f80bf21..6bc9659b6d 100644
--- a/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
+++ b/src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance.graphql
@@ -12,15 +12,15 @@ fragment RequestAttributes on MhaRequestAttributes {
phoneNumber
emailAddress
iUnderstandMhaPolicy
- approvedDate
+ hrApprovedAt
approvedOverallAmount
availableDate
- boardApprovedDate
+ boardApprovedAt
deadlineDate
- lastApprovedDate
spouseSpecific
staffSpecific
- submittedDate
+ submittedAt
+ changesRequestedAt
}
query MinistryHousingAllowanceRequests {
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
index eda8fc8ca4..59ffc4418c 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.tsx
@@ -72,7 +72,7 @@ export const RequestPage: React.FC = () => {
window.print();
};
- const boardDate = mocks[4].mhaDetails.staffMHA?.boardApprovalDate ?? '';
+ const boardDate = mocks[4].mhaDetails.staffMHA?.boardApprovedAt ?? '';
const availableDate = mocks[4].mhaDetails.staffMHA?.availableDate ?? '';
const deadlineDate = mocks[4].mhaDetails.staffMHA?.deadlineDate ?? '';
@@ -95,8 +95,8 @@ export const RequestPage: React.FC = () => {
{
{currentIndex === 0 && (
)}
{currentIndex === 1 && }
{currentIndex === 2 && (
= ({
updatedAt: '2022-12-01',
requestAttributes: {
...mockMHARequest.requestAttributes,
- approvedDate: '2023-01-15',
+ hrApprovedAt: '2023-01-15',
approvedOverallAmount: 1500,
staffSpecific: 1000,
spouseSpecific: 500,
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
index 8d0082012f..3a43f25388 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
@@ -43,7 +43,7 @@ export const CurrentBoardApproved: React.FC = ({
useMinisterHousingAllowance();
const requestId = request?.id;
- const { approvedDate, approvedOverallAmount, staffSpecific, spouseSpecific } =
+ const { hrApprovedAt, approvedOverallAmount, staffSpecific, spouseSpecific } =
request?.requestAttributes || {};
const lastUpdated = request?.updatedAt ?? null;
@@ -126,8 +126,8 @@ export const CurrentBoardApproved: React.FC = ({
{t('Approved on')}:{' '}
- {approvedDate ? (
- dateFormatShort(DateTime.fromISO(approvedDate), locale)
+ {hrApprovedAt ? (
+ dateFormatShort(DateTime.fromISO(hrApprovedAt), locale)
) : (
= ({
{t('Approved on')}:{' '}
- {approvedDate ? (
+ {hrApprovedAt ? (
dateFormatShort(
- DateTime.fromISO(approvedDate),
+ DateTime.fromISO(hrApprovedAt),
locale,
)
) : (
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
index 666cb7fc77..73e2241144 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
@@ -46,9 +46,9 @@ export const CurrentRequest: React.FC = ({ request }) => {
const viewLink = getRequestUrl(accountListId, requestId, 'view');
const {
- boardApprovedDate,
+ boardApprovedAt,
deadlineDate,
- submittedDate,
+ submittedAt,
availableDate,
approvedOverallAmount,
} = requestAttributes || {};
@@ -148,8 +148,8 @@ export const CurrentRequest: React.FC = ({ request }) => {
) : (
<>
{t('Requested on')}
- {submittedDate &&
- `: ${dateFormat(DateTime.fromISO(submittedDate), locale)}`}
+ {submittedAt &&
+ `: ${dateFormat(DateTime.fromISO(submittedAt), locale)}`}
>
)}
@@ -204,8 +204,8 @@ export const CurrentRequest: React.FC = ({ request }) => {
{t('Board Approval on')}
- {boardApprovedDate &&
- `: ${dateFormat(DateTime.fromISO(boardApprovedDate), locale)}`}
+ {boardApprovedAt &&
+ `: ${dateFormat(DateTime.fromISO(boardApprovedAt), locale)}`}
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.test.tsx
index ea1b9d7bf8..2172ea9089 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.test.tsx
@@ -10,7 +10,7 @@ import { MinisterHousingAllowanceProvider } from '../../Shared/Context/MinisterH
import { AboutForm } from './AboutForm';
const submit = jest.fn();
-const boardApprovalDate = '2024-09-15';
+const boardApprovedAt = '2024-09-15';
const availabilityDate = '2024-10-01';
const TestComponent: React.FC = () => (
@@ -20,7 +20,7 @@ const TestComponent: React.FC = () => (
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.tsx
index f9906285f5..35c4657833 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepOne/AboutForm.tsx
@@ -9,12 +9,12 @@ import { DirectionButtons } from '../../../Shared/CalculationReports/DirectionBu
import { useMinisterHousingAllowance } from '../../Shared/Context/MinisterHousingAllowanceContext';
interface AboutFormProps {
- boardApprovalDate: string | null;
+ boardApprovedAt: string | null;
availableDate: string | null;
}
export const AboutForm: React.FC = ({
- boardApprovalDate,
+ boardApprovedAt,
availableDate,
}) => {
const { t } = useTranslation();
@@ -27,8 +27,8 @@ export const AboutForm: React.FC = ({
const nextYear = DateTime.now().year + 1;
- const boardDateFormatted = boardApprovalDate
- ? dateFormatShort(DateTime.fromISO(boardApprovalDate), locale)
+ const boardDateFormatted = boardApprovedAt
+ ? dateFormatShort(DateTime.fromISO(boardApprovedAt), locale)
: null;
const availableDateFormatted = availableDate
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
index e5134ef417..71f0d1d2e8 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.test.tsx
@@ -42,14 +42,14 @@ jest.mock('notistack', () => ({
interface TestComponentProps {
contextValue: Partial;
- boardApprovalDate?: string | null;
+ boardApprovedAt?: string | null;
availableDate?: string | null;
rentOrOwn?: MhaRentOrOwnEnum;
}
const TestComponent: React.FC = ({
contextValue,
- boardApprovalDate = '2024-06-15',
+ boardApprovedAt = '2024-06-15',
availableDate = '2024-07-01',
rentOrOwn = MhaRentOrOwnEnum.Own,
}) => (
@@ -68,7 +68,7 @@ const TestComponent: React.FC = ({
value={contextValue as ContextType}
>
@@ -379,7 +379,7 @@ describe('Calculation', () => {
setIsPrint,
} as unknown as ContextType
}
- boardApprovalDate={null}
+ boardApprovedAt={null}
availableDate={null}
/>,
);
diff --git a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
index 0047bfe9ef..7403eab3a8 100644
--- a/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/Steps/StepThree/Calculation.tsx
@@ -42,7 +42,7 @@ import { RequestSummaryCard } from './CalcComponents/RequestSummaryCard';
// TODO: get correct link for "What expenses can I claim on my MHA?"
interface CalculationProps {
- boardApprovalDate: string | null;
+ boardApprovedAt: string | null;
availableDate: string | null;
deadlineDate?: string | null;
rentOrOwn?: MhaRentOrOwnEnum;
@@ -119,7 +119,7 @@ const getValidationSchema = (rentOrOwn?: MhaRentOrOwnEnum) => {
};
export const Calculation: React.FC = ({
- boardApprovalDate,
+ boardApprovedAt,
availableDate,
deadlineDate,
rentOrOwn,
@@ -201,8 +201,8 @@ export const Calculation: React.FC = ({
iUnderstandMhaPolicy: false,
};
- const boardDateFormatted = boardApprovalDate
- ? dateFormatShort(DateTime.fromISO(boardApprovalDate), locale)
+ const boardDateFormatted = boardApprovedAt
+ ? dateFormatShort(DateTime.fromISO(boardApprovedAt), locale)
: null;
const availableDateFormatted = availableDate
diff --git a/src/components/Reports/MinisterHousingAllowance/mockData.ts b/src/components/Reports/MinisterHousingAllowance/mockData.ts
index 8f31da3bc2..b408163ff4 100644
--- a/src/components/Reports/MinisterHousingAllowance/mockData.ts
+++ b/src/components/Reports/MinisterHousingAllowance/mockData.ts
@@ -14,9 +14,9 @@ export const mockMHARequest: MHARequest = {
},
requestAttributes: {
approvedOverallAmount: 15000,
- submittedDate: '2019-10-01T15:30:45.123Z',
+ submittedAt: '2019-10-01T15:30:45.123Z',
deadlineDate: '2019-10-23T15:30:45.123Z',
- boardApprovedDate: '2019-10-30T15:30:45.123Z',
+ boardApprovedAt: '2019-10-30T15:30:45.123Z',
availableDate: '2019-11-20T15:30:45.123Z',
rentOrOwn: null,
rentalValue: null,
@@ -31,9 +31,9 @@ export const mockMHARequest: MHARequest = {
phoneNumber: null,
emailAddress: null,
iUnderstandMhaPolicy: true,
- approvedDate: '2019-11-01T15:30:45.123Z',
- lastApprovedDate: '2019-11-01T15:30:45.123Z',
+ hrApprovedAt: '2019-11-01T15:30:45.123Z',
spouseSpecific: null,
staffSpecific: 15000,
+ changesRequestedAt: null,
},
};
From 2711ab0df910add741e93503f1a8aeb8eeffe7a6 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Tue, 20 Jan 2026 15:07:10 -0500
Subject: [PATCH 34/36] Review changes part 2
---
.../SharedComponents/CurrentBoardApproved.tsx | 23 ++++++------
.../SharedComponents/CurrentRequest.tsx | 36 ++++++++++---------
2 files changed, 30 insertions(+), 29 deletions(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
index 3a43f25388..cbd8aef87d 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentBoardApproved.tsx
@@ -35,9 +35,7 @@ export const CurrentBoardApproved: React.FC = ({
const router = useRouter();
const currency = 'USD';
- const [duplicateMHA] = useDuplicateMinistryHousingAllowanceRequestMutation(
- {},
- );
+ const [duplicateMHA] = useDuplicateMinistryHousingAllowanceRequestMutation();
const { isMarried, preferredName, spousePreferredName } =
useMinisterHousingAllowance();
@@ -55,21 +53,22 @@ export const CurrentBoardApproved: React.FC = ({
return;
}
- const result = await duplicateMHA({
+ await duplicateMHA({
variables: {
input: {
requestId: requestId,
},
},
- });
-
- const newRequestId =
- result.data?.duplicateMinistryHousingAllowanceRequest
- ?.ministryHousingAllowanceRequest.id;
+ onCompleted: (data) => {
+ const newRequestId =
+ data?.duplicateMinistryHousingAllowanceRequest
+ ?.ministryHousingAllowanceRequest.id;
- if (newRequestId) {
- router.push(getRequestUrl(accountListId, newRequestId, 'edit'));
- }
+ if (newRequestId) {
+ router.push(getRequestUrl(accountListId, newRequestId, 'edit'));
+ }
+ },
+ });
};
return (
diff --git a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
index 73e2241144..bece438545 100644
--- a/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/SharedComponents/CurrentRequest.tsx
@@ -35,12 +35,14 @@ export const CurrentRequest: React.FC = ({ request }) => {
const { status, requestAttributes } = request;
- const canEdit =
- status === MhaStatusEnum.InProgress ||
- status === MhaStatusEnum.ActionRequired;
- const approved =
- status === MhaStatusEnum.HrApproved ||
- status === MhaStatusEnum.BoardApproved;
+ const canEdit = [
+ MhaStatusEnum.InProgress,
+ MhaStatusEnum.ActionRequired,
+ ].includes(status);
+ const approved = [
+ MhaStatusEnum.HrApproved,
+ MhaStatusEnum.BoardApproved,
+ ].includes(status);
const editLink = getRequestUrl(accountListId, requestId, 'edit');
const viewLink = getRequestUrl(accountListId, requestId, 'view');
@@ -65,18 +67,18 @@ export const CurrentRequest: React.FC = ({ request }) => {
});
const handleCancelRequest = async () => {
- try {
- await deleteRequestMutation({
- variables: {
- input: {
- requestId: requestId ?? '',
- },
+ await deleteRequestMutation({
+ variables: {
+ input: {
+ requestId: requestId ?? '',
},
- });
- enqueueSnackbar(t('MHA request cancelled successfully.'), {
- variant: 'success',
- });
- } catch (error) {}
+ },
+ onCompleted: () => {
+ enqueueSnackbar(t('MHA request cancelled successfully.'), {
+ variant: 'success',
+ });
+ },
+ });
};
return (
From c1cf6de46c98167d89c619a48edcb8ec91793c37 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Tue, 20 Jan 2026 15:20:39 -0500
Subject: [PATCH 35/36] Fixed broken test
---
.../RequestPage/RequestPage.test.tsx | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
index e6a1e0dcb5..a70104f31b 100644
--- a/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
+++ b/src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage.test.tsx
@@ -125,7 +125,16 @@ describe('RequestPage', () => {
describe('Edit Page', () => {
it('starts on step 2 and updates steps when Continue clicked', async () => {
const { getByRole, getAllByRole, getByText, queryByTestId, findByRole } =
- render( );
+ render(
+ ,
+ );
expect(await findByRole('progressbar')).toHaveAttribute(
'aria-valuenow',
From 1ab7e8545583c58ca2b4de09e9d0822a3c32f3f1 Mon Sep 17 00:00:00 2001
From: Katelyn Grimes
Date: Tue, 20 Jan 2026 15:28:37 -0500
Subject: [PATCH 36/36] Fixed other failing test
---
.../RequestSummaryCard/RequestSummaryCard.test.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/components/Reports/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx b/src/components/Reports/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx
index 1b96c9878a..0a0654b789 100644
--- a/src/components/Reports/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx
+++ b/src/components/Reports/SalaryCalculator/SalaryCalculation/RequestSummaryCard/RequestSummaryCard.test.tsx
@@ -38,9 +38,9 @@ const TestComponent: React.FC = (props) => (
describe('RequestSummaryCard', () => {
it('renders status message', async () => {
- const { getByTestId } = render( );
+ const { findByTestId } = render( );
- expect(getByTestId('RequestSummaryCard-status')).toHaveTextContent(
+ expect(await findByTestId('RequestSummaryCard-status')).toHaveTextContent(
'Your gross request is within your Maximum Allowable Salary.',
);
});