Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MPDX-8057 - tools sidebar #1010

Merged
merged 10 commits into from
Sep 4, 2024
Merged
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
15 changes: 3 additions & 12 deletions pages/accountLists/[accountListId]/tools.page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
import Head from 'next/head';
import React, { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import { loadSession } from 'pages/api/utils/pagePropsHelpers';
import ToolHome from 'src/components/Tool/Home/Home';
import useGetAppSettings from 'src/hooks/useGetAppSettings';
import { ToolsWrapper } from './tools/ToolsWrapper';

Check warning on line 4 in pages/accountLists/[accountListId]/tools.page.tsx

View check run for this annotation

Codecov / codecov/patch

pages/accountLists/[accountListId]/tools.page.tsx#L4

Added line #L4 was not covered by tests

const ToolsPage = (): ReactElement => {
const { t } = useTranslation();
const { appName } = useGetAppSettings();
return (
<>
<Head>
<title>
{appName} | {t('Tools')}
</title>
</Head>
<ToolsWrapper pageUrl={'tools'}>
<ToolHome />
</>
</ToolsWrapper>
);
};

Expand Down
36 changes: 31 additions & 5 deletions pages/accountLists/[accountListId]/tools/ToolsWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
import Head from 'next/head';
import React, { JSXElementConstructor, ReactElement } from 'react';
import React, { JSXElementConstructor, ReactElement, useState } from 'react';
import { DynamicContactsRightPanel } from 'src/components/Contacts/ContactsRightPanel/DynamicContactsRightPanel';
import { SidePanelsLayout } from 'src/components/Layouts/SidePanelsLayout';
import Loading from 'src/components/Loading';
import {
HeaderTypeEnum,
MultiPageHeader,
} from 'src/components/Shared/MultiPageLayout/MultiPageHeader';
import NavToolList from 'src/components/Tool/NavToolList/NavToolList';
import useGetAppSettings from 'src/hooks/useGetAppSettings';
import { ContactsWrapper } from '../contacts/ContactsWrapper';
import { useToolsHelper } from './useToolsHelper';

interface ToolsWrapperProps {
pageTitle: string;
pageTitle?: string;
pageUrl: string;
selectedMenuId: string; // for later use
selectedMenuId?: string;
children: ReactElement<unknown, string | JSXElementConstructor<unknown>>;
styles?: React.ReactNode;
}

export const ToolsWrapper: React.FC<ToolsWrapperProps> = ({
pageTitle,
pageUrl,
selectedMenuId,
children,
styles,
}) => {
const { appName } = useGetAppSettings();
const { accountListId, selectedContactId, handleSelectContact } =
useToolsHelper();
const [isToolDrawerOpen, setIsToolDrawerOpen] = useState<boolean>(false);

return (
<>
Expand All @@ -33,11 +40,30 @@
</title>
{styles}
</Head>

{accountListId ? (
<SidePanelsLayout
leftOpen={false}
leftOpen={isToolDrawerOpen}
isScrollBox={false}
leftPanel={
<NavToolList
selectedId={selectedMenuId || ''}
isOpen={isToolDrawerOpen}
toggle={setIsToolDrawerOpen}
/>
}
leftWidth="290px"
mainContent={children}
mainContent={
<>
<MultiPageHeader
isNavListOpen={isToolDrawerOpen}
onNavListToggle={() => setIsToolDrawerOpen(!isToolDrawerOpen)}

Check warning on line 60 in pages/accountLists/[accountListId]/tools/ToolsWrapper.tsx

View check run for this annotation

Codecov / codecov/patch

pages/accountLists/[accountListId]/tools/ToolsWrapper.tsx#L60

Added line #L60 was not covered by tests
title={pageTitle || ''}
headerType={HeaderTypeEnum.Tools}
/>
{children}
</>
}
rightPanel={
selectedContactId ? (
<ContactsWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const useStyles = makeStyles()(() => ({
},
}));

enum ToolName {
export enum ToolName {
FixCommitmentInfo = 'fixCommitmentInfo',
FixMailingAddresses = 'fixMailingAddresses',
FixSendNewsletter = 'fixSendNewsletter',
Expand Down
17 changes: 17 additions & 0 deletions src/components/Shared/MultiPageLayout/MultiPageHeader.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,21 @@ describe('MultiPageHeader', () => {
expect(getByText('Toggle Preferences Menu')).toBeInTheDocument();
expect(getByTestId('SettingsMenuIcon')).toBeInTheDocument();
});

it('should render the Tools menu', async () => {
const { getByTestId, getByText } = render(
<ThemeProvider theme={theme}>
<MultiPageHeader
isNavListOpen={true}
title={title}
onNavListToggle={onNavListToggle}
rightExtra={undefined}
headerType={HeaderTypeEnum.Tools}
/>
</ThemeProvider>,
);

expect(getByText('Toggle Tools Menu')).toBeInTheDocument();
expect(getByTestId('ToolsMenuIcon')).toBeInTheDocument();
});
});
9 changes: 9 additions & 0 deletions src/components/Shared/MultiPageLayout/MultiPageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import theme from 'src/theme';
export enum HeaderTypeEnum {
Report = 'reports',
Settings = 'settings',
Tools = 'tools',
}

export const multiPageHeaderHeight = theme.spacing(10);
Expand Down Expand Up @@ -70,6 +71,8 @@ export const MultiPageHeader: FC<MultiPageHeaderProps> = ({
titleAccess = t('Toggle Navigation Panel');
} else if (headerType === HeaderTypeEnum.Settings) {
titleAccess = t('Toggle Preferences Menu');
} else if (headerType === HeaderTypeEnum.Tools) {
titleAccess = t('Toggle Tools Menu');
}

return (
Expand All @@ -93,6 +96,12 @@ export const MultiPageHeader: FC<MultiPageHeaderProps> = ({
data-testid="SettingsMenuIcon"
/>
)}
{headerType === HeaderTypeEnum.Tools && (
<NavMenuIcon
titleAccess={titleAccess}
data-testid="ToolsMenuIcon"
/>
)}
</NavListButton>
<Typography variant="h5" sx={{ flex: 1 }}>
{title}
Expand Down
62 changes: 35 additions & 27 deletions src/components/Tool/Home/ToolList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
mdiTrophy,
mdiWrench,
} from '@mdi/js';
import i18n from 'src/lib/i18n';

export interface ToolItem {
tool: string;
Expand All @@ -29,104 +30,111 @@ interface ToolsGroup {

export const ToolsList: ToolsGroup[] = [
{
groupName: 'Appeals',
groupName: i18n.t('Appeals'),
groupIcon: mdiWrench,
items: [
{
tool: 'Appeal',
desc: 'Set goals, create asks, and track progress for one-time needs',
tool: i18n.t('Appeal'),
desc: i18n.t(
'Set goals, create asks, and track progress for one-time needs',
),
icon: mdiTrophy,
id: 'appeals',
url: 'appeals',
},
],
},
{
groupName: 'Contacts',
groupName: i18n.t('Contacts'),
groupIcon: mdiHome,
items: [
{
tool: 'Fix Commitment Info',
desc: 'Set the correct contacts commitment info for each contact',
tool: i18n.t('Fix Commitment Info'),
desc: i18n.t(
'Set the correct contacts commitment info for each contact',
),

icon: mdiCurrencyUsd,
id: 'fixCommitmentInfo',
url: 'fix/commitmentInfo',
},
{
tool: 'Fix Mailing Addresses',
desc: 'Set the correct primary mailing address for each contact',
tool: i18n.t('Fix Mailing Addresses'),
desc: i18n.t(
'Set the correct primary mailing address for each contact',
),
icon: mdiMap,
id: 'fixMailingAddresses',
url: 'fix/mailingAddresses',
},
{
tool: 'Fix Send Newsletter',
desc: 'Set the correct newsletter state for each contact',
tool: i18n.t('Fix Send Newsletter'),
desc: i18n.t('Set the correct newsletter state for each contact'),
icon: mdiNewspaperVariantOutline,
id: 'fixSendNewsletter',
url: 'fix/sendNewsletter',
},
{
tool: 'Merge Contacts',
desc: 'Review and merge duplicate contacts',
tool: i18n.t('Merge Contacts'),
desc: i18n.t('Review and merge duplicate contacts'),
icon: mdiHome,
id: 'mergeContacts',
url: 'merge/contacts',
},
],
},
{
groupName: 'People',
groupName: i18n.t('People'),
groupIcon: mdiAccountGroup,
items: [
{
tool: 'Fix Email Addresses',
desc: 'Set the correct primary email address for each person',
tool: i18n.t('Fix Email Addresses'),
desc: i18n.t('Set the correct primary email address for each person'),
icon: mdiEmail,
id: 'fixEmailAddresses',
url: 'fix/emailAddresses',
},
{
tool: 'Fix Phone Numbers',
desc: 'Set the correct primary phone number for each person',
tool: i18n.t('Fix Phone Numbers'),
desc: i18n.t('Set the correct primary phone number for each person'),
icon: mdiPhone,
id: 'fixPhoneNumbers',
url: 'fix/phoneNumbers',
},
{
tool: 'Merge People',
desc: 'Review and merge duplicate people',
tool: i18n.t('Merge People'),
desc: i18n.t('Review and merge duplicate people'),
icon: mdiAccountGroup,
id: 'mergePeople',
url: 'merge/people',
},
],
},
{
groupName: 'Imports',
groupName: i18n.t('Imports'),
groupIcon: mdiCloudUpload,
items: [
{
tool: 'Import from Google',
desc: 'Import your contact information from your Google account',
tool: i18n.t('Import from Google'),
desc: i18n.t(
'Import your contact information from your Google account',
),

icon: mdiGoogle,
id: 'import/google',
url: 'import/google',
},

{
tool: 'Import from TntConnect',
desc: 'Import your contacts from your TntConnect database',
tool: i18n.t('Import from TntConnect'),
desc: i18n.t('Import your contacts from your TntConnect database'),
icon: mdiCloudUpload,
id: 'import/tnt',
url: 'import/tnt',
},

{
tool: 'Import from CSV',
desc: 'Import contacts you have saved in a CSV file',
tool: i18n.t('Import from CSV'),
desc: i18n.t('Import contacts you have saved in a CSV file'),
icon: mdiTable,
id: 'import/csv',
url: 'import/csv',
Expand Down
45 changes: 40 additions & 5 deletions src/components/Tool/NavToolList/Item/Item.test.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,56 @@
import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import TestWrapper from '__tests__/util/TestWrapper';
import { render } from '__tests__/util/testingLibraryReactMock';
import theme from '../../../../theme';
import { Item } from './Item';

const item = {
url: 'testItem',
title: 'test title',
isSelected: false,
id: 'testItem',
};

const TestComponent = ({ totalCount = 0 }: { totalCount?: number }) => (
<ThemeProvider theme={theme}>
<TestWrapper>
<Item
url={item.url}
title={item.title}
isSelected={item.isSelected}
loading={false}
totalCount={totalCount}
toolId={item.id}
/>
</TestWrapper>
</ThemeProvider>
);

describe('ToolItem', () => {
it('default', () => {
wjames111 marked this conversation as resolved.
Show resolved Hide resolved
const { queryByText } = render(
<TestWrapper>
<Item url={item.url} title={item.title} isSelected={item.isSelected} />
</TestWrapper>,
);
const { queryByText } = render(<TestComponent />);
expect(queryByText(item.title)).toBeInTheDocument();
});

it('renders count less then 9', () => {
const { queryByText } = render(<TestComponent totalCount={8} />);
expect(queryByText(item.title)).toBeInTheDocument();
expect(queryByText('8')).toBeInTheDocument();
});

it('renders count greater then 9', () => {
const { queryByText } = render(<TestComponent totalCount={10} />);
expect(queryByText(item.title)).toBeInTheDocument();
expect(queryByText('9+')).toBeInTheDocument();
});

it('renders without Badge', () => {
const { queryByText, queryByTestId } = render(<TestComponent />);
expect(queryByText(item.title)).toBeInTheDocument();

expect(
queryByTestId('fixCommitmentInfo-notifications'),
).not.toBeInTheDocument();
});
});
Loading
Loading