Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import { styled } from '@mui/material/styles';
import { useTranslation } from 'react-i18next';
import { blockImpersonatingNonDevelopers } from 'pages/api/utils/pagePropsHelpers';
import { SidePanelsLayout } from 'src/components/Layouts/SidePanelsLayout';
import { DynamicExpensesClaim } from 'src/components/Reports/MinisterHousingAllowance/DynamicExpensesClaim/DynamicExpensesClaim';
import { RequestPage } from 'src/components/Reports/MinisterHousingAllowance/RequestPage/RequestPage';
import { MinisterHousingAllowanceProvider } from 'src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext';
import {
MinisterHousingAllowanceProvider,
useMinisterHousingAllowance,
} from 'src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext';
import { PageEnum } from 'src/components/Reports/Shared/CalculationReports/Shared/sharedTypes';
import { SimpleScreenOnly } from 'src/components/Reports/styledComponents';
import {
Expand All @@ -23,11 +27,61 @@ const RequestPageWrapper = styled(Box)(({ theme }) => ({
backgroundColor: theme.palette.common.white,
}));

interface HousingAllowanceRequestContentProps {
isNavListOpen: boolean;
onNavListToggle: () => void;
}

const HousingAllowanceRequestContent: React.FC<
HousingAllowanceRequestContentProps
> = ({ isNavListOpen, onNavListToggle }) => {
const { t } = useTranslation();
const { isRightPanelOpen } = useMinisterHousingAllowance();

return (
<SidePanelsLayout
isScrollBox={false}
leftPanel={
<MultiPageMenu
isOpen={isNavListOpen}
selectedId="housingAllowance"
onClose={onNavListToggle}
navType={NavTypeEnum.Reports}
/>
}
leftOpen={isNavListOpen}
leftWidth="290px"
mainContent={
<>
<SimpleScreenOnly>
<MultiPageHeader
isNavListOpen={isNavListOpen}
onNavListToggle={onNavListToggle}
title={t("Minister's Housing Allowance Request")}
headerType={HeaderTypeEnum.Report}
/>
</SimpleScreenOnly>
<RequestPage />
</>
}
rightPanel={isRightPanelOpen ? <DynamicExpensesClaim /> : undefined}
rightOpen={isRightPanelOpen}
rightWidth="35%"
/>
);
};

const HousingAllowanceRequestPage: React.FC = () => {
const { t } = useTranslation();
const router = useRouter();
const { requestId, mode } = router.query;

const [isNavListOpen, setIsNavListOpen] = useState(false);

const handleNavListToggle = () => {
setIsNavListOpen(!isNavListOpen);
};

if (!requestId) {
return <CircularProgress />;
}
Expand All @@ -54,49 +108,21 @@ const HousingAllowanceRequestPage: React.FC = () => {
mode: pageType,
});

const [isNavListOpen, setIsNavListOpen] = useState(false);

const handleNavListToggle = () => {
setIsNavListOpen(!isNavListOpen);
};

return (
<>
<Head>
<title>{title}</title>
</Head>
<RequestPageWrapper>
<SidePanelsLayout
isScrollBox={false}
leftPanel={
<MultiPageMenu
isOpen={isNavListOpen}
selectedId={'housingAllowance' + pageType}
onClose={handleNavListToggle}
navType={NavTypeEnum.Reports}
/>
}
leftOpen={isNavListOpen}
leftWidth="290px"
mainContent={
<>
<SimpleScreenOnly>
<MultiPageHeader
isNavListOpen={isNavListOpen}
onNavListToggle={handleNavListToggle}
title={t("Minister's Housing Allowance Request")}
headerType={HeaderTypeEnum.Report}
/>
</SimpleScreenOnly>
<MinisterHousingAllowanceProvider
type={pageType}
requestId={requestId as string}
>
<RequestPage />
</MinisterHousingAllowanceProvider>
</>
}
/>
<MinisterHousingAllowanceProvider
type={pageType}
requestId={requestId as string}
>
<HousingAllowanceRequestContent
isNavListOpen={isNavListOpen}
onNavListToggle={handleNavListToggle}
/>
</MinisterHousingAllowanceProvider>
</RequestPageWrapper>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import { useTranslation } from 'react-i18next';
import { blockImpersonatingNonDevelopers } from 'pages/api/utils/pagePropsHelpers';
import { SidePanelsLayout } from 'src/components/Layouts/SidePanelsLayout';
import Loading from 'src/components/Loading';
import { DynamicExpensesClaim } from 'src/components/Reports/MinisterHousingAllowance/DynamicExpensesClaim/DynamicExpensesClaim';
import { MinisterHousingAllowanceReport } from 'src/components/Reports/MinisterHousingAllowance/MinisterHousingAllowance';
import { MinisterHousingAllowanceProvider } from 'src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext';
import {
MinisterHousingAllowanceProvider,
useMinisterHousingAllowance,
} from 'src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext';
import { NoStaffAccount } from 'src/components/Reports/Shared/NoStaffAccount/NoStaffAccount';
import { useStaffAccountQuery } from 'src/components/Reports/StaffAccount.generated';
import {
Expand All @@ -20,6 +24,49 @@ import {
import { ReportPageWrapper } from 'src/components/Shared/styledComponents/ReportPageWrapper';
import useGetAppSettings from 'src/hooks/useGetAppSettings';

interface MinisterHousingAllowanceContentProps {
isNavListOpen: boolean;
onNavListToggle: () => void;
}

const MinisterHousingAllowanceContent: React.FC<
MinisterHousingAllowanceContentProps
> = ({ isNavListOpen, onNavListToggle }) => {
const { t } = useTranslation();
const { isRightPanelOpen } = useMinisterHousingAllowance();

return (
<SidePanelsLayout
isScrollBox={false}
leftPanel={
<MultiPageMenu
isOpen={isNavListOpen}
selectedId="housingAllowance"
onClose={onNavListToggle}
navType={NavTypeEnum.Reports}
/>
}
leftOpen={isNavListOpen}
leftWidth="290px"
headerHeight={multiPageHeaderHeight}
mainContent={
<>
<MultiPageHeader
isNavListOpen={isNavListOpen}
onNavListToggle={onNavListToggle}
title={t("Minister's Housing Allowance Request")}
headerType={HeaderTypeEnum.Report}
/>
<MinisterHousingAllowanceReport />
</>
}
rightPanel={isRightPanelOpen ? <DynamicExpensesClaim /> : undefined}
rightOpen={isRightPanelOpen}
rightWidth="35%"
/>
);
};

const MinisterHousingAllowancePage: React.FC = () => {
const { t } = useTranslation();
const { appName } = useGetAppSettings();
Expand All @@ -38,33 +85,12 @@ const MinisterHousingAllowancePage: React.FC = () => {
</Head>
{staffAccountData?.staffAccount?.id ? (
<ReportPageWrapper>
<SidePanelsLayout
isScrollBox={false}
leftPanel={
<MultiPageMenu
isOpen={isNavListOpen}
selectedId="housingAllowance"
onClose={handleNavListToggle}
navType={NavTypeEnum.Reports}
/>
}
leftOpen={isNavListOpen}
leftWidth="290px"
headerHeight={multiPageHeaderHeight}
mainContent={
<>
<MultiPageHeader
isNavListOpen={isNavListOpen}
onNavListToggle={handleNavListToggle}
title={t("Minister's Housing Allowance Request")}
headerType={HeaderTypeEnum.Report}
/>
<MinisterHousingAllowanceProvider>
<MinisterHousingAllowanceReport />
</MinisterHousingAllowanceProvider>
</>
}
/>
<MinisterHousingAllowanceProvider>
<MinisterHousingAllowanceContent
isNavListOpen={isNavListOpen}
onNavListToggle={handleNavListToggle}
/>
</MinisterHousingAllowanceProvider>
</ReportPageWrapper>
) : loading ? (
<Loading loading />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import dynamic from 'next/dynamic';
import { DynamicComponentPlaceholder } from 'src/components/DynamicPlaceholders/DynamicComponentPlaceholder';

export const preloadExpensesClaim = () =>
import(/* webpackChunkName: "ExpensesClaim" */ './ExpensesClaim').then(
({ ExpensesClaim }) => ExpensesClaim,
);

export const DynamicExpensesClaim = dynamic(preloadExpensesClaim, {
loading: DynamicComponentPlaceholder,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import theme from 'src/theme';
import {
ContextType,
MinisterHousingAllowanceContext,
} from '../Shared/Context/MinisterHousingAllowanceContext';
import { ExpensesClaim } from './ExpensesClaim';

const setIsRightPanelOpen = jest.fn();

interface TestComponentProps {
contextValue?: Partial<ContextType>;
}

const TestComponent: React.FC<TestComponentProps> = ({ contextValue }) => (
<ThemeProvider theme={theme}>
<GqlMockedProvider>
<MinisterHousingAllowanceContext.Provider
value={contextValue as ContextType}
>
<ExpensesClaim />
</MinisterHousingAllowanceContext.Provider>
</GqlMockedProvider>
</ThemeProvider>
);

describe('ExpensesClaim', () => {
it('renders component', () => {
const { getByText, getByTestId } = render(
<TestComponent contextValue={{ setIsRightPanelOpen }} />,
);

expect(
getByText('What expenses can I claim on my MHA?'),
).toBeInTheDocument();
expect(getByTestId('CloseIcon')).toBeInTheDocument();
expect(getByText('Allowable Expenses for MHA')).toBeInTheDocument();
});

it('closes the panel when close icon is clicked', async () => {
const { getByTestId } = render(
<TestComponent contextValue={{ setIsRightPanelOpen }} />,
);

const closeIcon = getByTestId('CloseIcon');
userEvent.click(closeIcon);

expect(setIsRightPanelOpen).toHaveBeenCalledWith(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import { Close, RequestPageSharp } from '@mui/icons-material';
import { Box, Container, IconButton, Typography } from '@mui/material';
import { useTranslation } from 'react-i18next';
import theme from 'src/theme';
import { useMinisterHousingAllowance } from '../Shared/Context/MinisterHousingAllowanceContext';

export const ExpensesClaim: React.FC = () => {
const { t } = useTranslation();
const { setIsRightPanelOpen } = useMinisterHousingAllowance();

return (
<Container sx={{ padding: 2 }}>
<Box display="flex" alignItems="center" justifyContent="space-between">
<Typography variant="h6">
{t('What expenses can I claim on my MHA?')}
</Typography>
<IconButton onClick={() => setIsRightPanelOpen(false)}>
<Close />
</IconButton>
</Box>

<Box mt={4}>
<Box display="flex" alignItems="center" gap={1}>
<RequestPageSharp sx={{ color: theme.palette.orange.main }} />
<Typography variant="h6" sx={{ fontWeight: 'bold' }}>
{t('Allowable Expenses for MHA')}
</Typography>
</Box>
</Box>
</Container>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
spouseHcmData?: HcmData | null;
preferredName: string;
spousePreferredName: string;
isRightPanelOpen: boolean;
setIsRightPanelOpen: Dispatch<SetStateAction<boolean>>;

requestData?:
| MinistryHousingAllowanceRequestQuery['ministryHousingAllowanceRequest']
Expand Down Expand Up @@ -112,125 +114,130 @@
} = useStepList(FormEnum.MHA, type);

const [isComplete, setIsComplete] = useState(false);
const [isRightPanelOpen, setIsRightPanelOpen] = useState(false);

const steps = useMemo(() => {
if (!isComplete) {
return initialSteps;
}

return initialSteps.map((step, index, arr) => ({
...step,
complete: true,
current: index === arr.length - 1,
}));
}, [initialSteps, isComplete]);

const { data: hcmData } = useHcmDataQuery();

const [userHcmData, setUserHcmData] = useState<HcmData>();
const [spouseHcmData, setSpouseHcmData] = useState<HcmData | null>(null);
const [isMarried, setIsMarried] = useState(false);

useEffect(() => {
if (!hcmData?.hcm?.length) {
setUserHcmData(undefined);
setSpouseHcmData(null);
setIsMarried(false);
return;
}
const [user, spouse] = hcmData.hcm;
setUserHcmData(user);
setSpouseHcmData(spouse ?? null);
setIsMarried(!!spouse);
}, [hcmData]);

const preferredName = useMemo(
() => userHcmData?.staffInfo?.preferredName || '',
[userHcmData],
);
const spousePreferredName = useMemo(
() => spouseHcmData?.staffInfo?.preferredName || '',
[spouseHcmData],
);

const [isDrawerOpen, setIsDrawerOpen] = useState(true);
const toggleDrawer = useCallback(() => {
setIsDrawerOpen((prev) => !prev);
}, []);

const [hasCalcValues, setHasCalcValues] = useState(hasValues ? true : false);
const [isPrint, setIsPrint] = useState(false);

const [currentStep, setCurrentStep] = useState(StepsEnum.AboutForm);

useEffect(() => {
if (type === PageEnum.Edit) {
setCurrentStep(StepsEnum.RentOrOwn);
}
}, [type]);

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,
pageType,
hasCalcValues,
setHasCalcValues,
isDrawerOpen,
toggleDrawer,
setIsDrawerOpen,
isMarried,
userHcmData,
spouseHcmData,
preferredName,
spousePreferredName,
isPrint,
setIsPrint,
setIsComplete,
isRightPanelOpen,
setIsRightPanelOpen,
requestData: requestData?.ministryHousingAllowanceRequest ?? null,
requestError,
requestId,
updateMutation,
}),
[
steps,
currentIndex,
currentStep,
percentComplete,
handleNextStep,
handlePreviousStep,
pageType,
hasCalcValues,
setHasCalcValues,
isDrawerOpen,
toggleDrawer,
setIsDrawerOpen,
isMarried,
userHcmData,
spouseHcmData,
preferredName,
spousePreferredName,
isPrint,
setIsPrint,
setIsComplete,
isRightPanelOpen,
setIsRightPanelOpen,

Check warning on line 240 in src/components/Reports/MinisterHousingAllowance/Shared/Context/MinisterHousingAllowanceContext.tsx

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ Getting worse: Complex Method

MinisterHousingAllowanceProvider:React.FC<Props> already has high cyclomatic complexity, and now it increases in Lines of Code from 141 to 146. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
requestData,
requestError,
requestId,
Expand Down
Loading
Loading