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
49 changes: 28 additions & 21 deletions src/components/Layouts/Primary/TopBar/Items/NavMenu/NavMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,76 +129,83 @@
: 0;
}, [loading]);

const [reportsMenuOpen, setReportsMenuOpen] = useState(false);
const [toolsMenuOpen, setToolsMenuOpen] = useState(false);
enum MenuId {
Reports = 'reports',
Tools = 'tools',
RequestForms = 'requestForms',
}

const handleReportsMenuToggle = () => {
setReportsMenuOpen((prevOpen) => !prevOpen);
handleToolsMenuClose();
};

const handleReportsMenuClose = () => {
setReportsMenuOpen(false);
};
const [openMenu, setOpenMenu] = useState<MenuId | null>(null);

const handleToolsMenuToggle = () => {
setToolsMenuOpen((prevOpen) => !prevOpen);
handleReportsMenuClose();
const handleMenuToggle = (menu: MenuId) => {
setOpenMenu((prev) => (prev === menu ? null : menu));
};

const handleToolsMenuClose = () => {
setToolsMenuOpen(false);
const handleMenuClose = () => {
setOpenMenu(null);
};
const { pathname } = useRouter();

const isCoaching = !!coachingAccounts?.totalCount;
const { navPages } = useNavPages(isCoaching);
const coachingIndex = navPages.findIndex(
(page) => page.id === 'coaching-page',
);

return accountListId ? (
<Grid container item alignItems="center" xs="auto">
{navPages.map(
(page) =>
page.isDropdown === false && (
<Grid key={page.id} item className={classes.navListItem}>
<MenuItem
component={NextLink}
href={page.href ?? ''}
tabIndex={0}
className={classes.menuItem}
aria-current={pathname === page.pathname ? 'page' : undefined}
>
<ListItemText primary={page.title} />
</MenuItem>
</Grid>
),
)}

<NavMenuDropdown
page={navPages[3]}
menuOpen={reportsMenuOpen}
handleMenuToggle={handleReportsMenuToggle}
handleMenuClose={handleReportsMenuClose}
menuOpen={openMenu === MenuId.Reports}
handleMenuToggle={() => handleMenuToggle(MenuId.Reports)}
handleMenuClose={handleMenuClose}
testId="ReportMenuToggle"
sum={sum}
toolData={toolData}
loading={loading}
isTool={false}
/>
<NavMenuDropdown
page={navPages[4]}
menuOpen={toolsMenuOpen}
handleMenuToggle={handleToolsMenuToggle}
handleMenuClose={handleToolsMenuClose}
menuOpen={openMenu === MenuId.Tools}
handleMenuToggle={() => handleMenuToggle(MenuId.Tools)}
handleMenuClose={handleMenuClose}
testId="ToolsMenuToggle"
sum={sum}
toolData={toolData}
loading={loading}
isTool={true}
/>

<NavMenuDropdown
page={navPages[5]}
menuOpen={openMenu === MenuId.RequestForms}
handleMenuToggle={() => handleMenuToggle(MenuId.RequestForms)}
handleMenuClose={handleMenuClose}
testId="RequestFormsMenuToggle"
sum={sum}
toolData={toolData}
loading={loading}
isTool={false}
/>

Check warning on line 208 in src/components/Layouts/Primary/TopBar/Items/NavMenu/NavMenu.tsx

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ Getting worse: Complex Method

NavMenu:React.FC increases in cyclomatic complexity from 18 to 19, threshold = 10. 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.
{isCoaching && (
<Grid item className={classes.navListItem}>
<MenuItem
Expand Down
22 changes: 22 additions & 0 deletions src/hooks/useNavPages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { useTranslation } from 'react-i18next';
import { useAccountListId } from 'src/hooks/useAccountListId';
import { useReportNavItems } from './useReportNavItems';
import { useRequestFormsNavItems } from './useRequestFormsNavItems';
import { useSettingsNavItems } from './useSettingsNavItems';
import { useToolsNavItems } from './useToolsNavItems';

Expand Down Expand Up @@ -48,151 +49,172 @@
const accountListId = useAccountListId();
const { t } = useTranslation();
const reportItems = useReportNavItems();
const requestFormsItems = useRequestFormsNavItems();
const toolsItems = useToolsNavItems();
const settingsItems = useSettingsNavItems();

const allNavPages = useMemo<NavPage[]>(() => {
const navPages: NavPage[] = [
{
id: 'dashboard-page',
title: t('Dashboard'),
href: `/accountLists/${accountListId}`,
pathname: '/accountLists/[accountListId]',
showInNav: true,
isDropdown: false,
},
{
id: 'contacts-page',
title: t('Contacts'),
searchIcon: <CompassIcon />,
href: `/accountLists/${accountListId}/contacts`,
pathname: '/accountLists/[accountListId]/contacts/[[...contactId]]',
showInNav: true,
isDropdown: false,
showInSearchDialog: true,
},
{
id: 'tasks-page',
title: t('Tasks'),
searchIcon: <CompassIcon />,
href: `/accountLists/${accountListId}/tasks`,
pathname: '/accountLists/[accountListId]/tasks/[[...contactId]]',
showInNav: true,
isDropdown: false,
showInSearchDialog: true,
},
{
id: 'reports-page',
title: t('Reports'),
pathname: '/accountLists/[accountListId]/reports',
items: reportItems.map((item) => ({
...item,
href: `/accountLists/${accountListId}/reports/${item.id}`,
searchIcon: <CompassIcon />,
searchName: t(`Reports - {{ title }}`, { title: item.title }),
showInSearchDialog: true,
})),
showInNav: true,
},
{
id: 'tools-page',
title: t('Tools'),
searchIcon: <CompassIcon />,
href: `/accountLists/${accountListId}/tools`,
pathname: '/accountLists/[accountListId]/tools',
items: toolsItems.flatMap((toolsGroup) =>
toolsGroup.items.map((tool) => ({
...tool,
title: tool.tool,
href: `/accountLists/${accountListId}/tools/${tool.url}`,
searchIcon: <CompassIcon />,
searchName: t(`Tools - {{ title }}`, { title: tool.tool }),
showInSearchDialog: true,
})),
),
showInNav: true,
showInSearchDialog: true,
},
{
id: 'request-forms-page',
title: t('Request Forms'),
pathname: '/accountLists/[accountListId]/reports',
items: requestFormsItems.map((item) => ({
...item,
href: `/accountLists/${accountListId}/reports/${item.id}`,
searchIcon: <CompassIcon />,
searchName: t(`Request Forms - {{ title }}`, { title: item.title }),
showInSearchDialog: true,
})),
showInNav: true,
},
{
id: 'settings-page',
title: t('Preferences'),
searchIcon: <CompassIcon />,
href: `/accountLists/${accountListId}/settings/preferences`,
items: settingsItems.map((item) => ({
id: item.id,
title: item.title,
subtitle: item.subTitle,
href: `/accountLists/${accountListId}/settings/${item.id}`,
searchIcon: <CompassIcon />,
searchName:
item.id === 'preferences'
? item.title
: t(`Preferences - {{ title }}`, { title: item.title }),
grantedAccess: item.grantedAccess,
subItems: item.subItems,
oauth: item.oauth,
showInSearchDialog: true,
})),
pathname: '/accountLists/[accountListId]/settings/preferences',
showInPanel: true,
},
];

if (coachingAccountCount || isSearch) {
navPages.push({
id: 'coaching-page',
title: t('Coaching'),
searchIcon: <CompassIcon />,
href: `/accountLists/${accountListId}/coaching`,
pathname: '/accountLists/[accountListId]/coaching',
showInNav: true,
showInSearchDialog: true,
});
}

if (process.env.HELP_WHATS_NEW_URL) {
navPages.push({
id: 'whats-new-page',
title: t("What's New"),
href: process.env.HELP_WHATS_NEW_URL,
whatsNewLink: true,
showInNav: true,
});
}

return navPages;
}, [accountListId, coachingAccountCount, t]);

const navPages = useMemo(
() => allNavPages.filter((page) => page.showInNav),
[allNavPages],
);

const searchDialogPages = useMemo(() => {
const pages: NavPage[] = [];

for (const page of allNavPages) {
// include search pages
if (page.showInSearchDialog) {
pages.push(page);
}

// get report sub items
if (page.id === 'reports-page' && page.items) {
page.items.forEach((item) => {
pages.push({ ...item, title: item.searchName ?? item.title });
});
}

// get tool sub items
if (page.id === 'tools-page' && page.items) {
if (page.items) {
page.items.forEach((item) => {
pages.push({ ...item, title: item.searchName ?? item.title });
});
}
}

// get request forms sub items
if (page.id === 'request-forms-page' && page.items) {
page.items.forEach((item) => {
pages.push({ ...item, title: item.searchName ?? item.title });
});
}

Check warning on line 217 in src/hooks/useNavPages.tsx

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ Getting worse: Complex Method

useNavPages increases in cyclomatic complexity from 14 to 16, threshold = 10. 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.
// get settings sub items without granted access
if (page.id === 'settings-page' && page.items) {
page.items
Expand Down
32 changes: 21 additions & 11 deletions src/hooks/useReportNavItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,27 @@ export function useReportNavItems(): NavItems[] {
id: 'coaching',
title: t('Coaching'),
},
// Goal Calculator
// {
// id: 'goalCalculator',
// title: t('Goal Calculator'),
// subTitle: t('Reports - Goal Calculation'),
// },
// {
// id: 'mpgaIncomeExpenses',
// title: t('MPGA Monthly Report'),
// subTitle: t('Income & Expenses'),
// },
{
id: 'mpgaIncomeExpenses',
title: t('MPGA Monthly Report'),
subTitle: t('Income & Expenses'),
},
{
id: 'staffSavingFund',
title: t('Staff Saving Fund'),
},
{
id: 'staffExpense',
title: t('Staff Expense'),
},
{
id: 'goalCalculator',
title: t('Goal Calculator'),
},
{
id: 'mpReminders',
title: t('Ministry Partner Reminders'),
},
];

return useMemo(() => reportNavItems, [t]);
Expand Down
24 changes: 24 additions & 0 deletions src/hooks/useRequestFormsNavItems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { NavItems } from './useReportNavItems';

export function useRequestFormsNavItems(): NavItems[] {
const { t } = useTranslation();

const requestFormsNavItems: NavItems[] = [
{
id: 'additionalSalaryRequest',
title: t('Additional Salary Request'),
},
{
id: 'housingAllowance',
title: t('Housing Allowance'),
},
{
id: 'salaryCalculator',
title: t('Salary Calculator'),
},
];

return useMemo(() => requestFormsNavItems, [t]);
}
Loading