Skip to content
Open
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Note: there is a test account you can use. Get this from another developer if yo
- `HS_HOME_SUGGESTIONS` - Comma-separated IDs of the HelpScout articles to suggest on the dashboard page
- `HS_REPORTS_SUGGESTIONS` - Comma-separated IDs of the HelpScout articles to suggest on the reports pages
- `HS_TASKS_SUGGESTIONS` - Comma-separated IDs of the HelpScout articles to suggest on the tasks page
- `SHOW_BANNER` - Display a hard-coded banner on the Dashboard. Set to `true` or `false`

#### Auth provider

Expand Down
1 change: 1 addition & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ module.exports = withPlugins([
HS_REPORTS_SUGGESTIONS: process.env.HS_REPORTS_SUGGESTIONS,
HS_TASKS_SUGGESTIONS: process.env.HS_TASKS_SUGGESTIONS,
ALERT_MESSAGE: process.env.ALERT_MESSAGE,
SHOW_BANNER: process.env.SHOW_BANNER,
},
experimental: {
modularizeImports: {
Expand Down
7 changes: 6 additions & 1 deletion pages/accountLists/[accountListId].page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const AccountListIdPage = ({
const { openTaskModal } = useTaskModal();
const [selectedMenuItem, setSelectedMenuItem] = useState(-1);
const [dialogOpen, setDialogOpen] = useState(false);
const shouldShowBanner = process.env.SHOW_BANNER === 'true';

useEffect(() => {
suggestArticles('HS_HOME_SUGGESTIONS');
Expand Down Expand Up @@ -65,7 +66,11 @@ const AccountListIdPage = ({
{appName} | {data.accountList.name}
</title>
</Head>
<Dashboard data={data} accountListId={accountListId} />
<Dashboard
data={data}
accountListId={accountListId}
shouldShowBanner={shouldShowBanner}
/>

{modal && renderDialog(selectedMenuItem, dialogOpen, setDialogOpen)}
</>
Expand Down
46 changes: 46 additions & 0 deletions src/components/Dashboard/Dashboard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,49 @@ describe('Dashboard', () => {
).toEqual('Committed $700');
});
});

describe('Static Banner', () => {
beforeEach(() => {
beforeTestResizeObserver();
});

afterAll(() => {
afterTestResizeObserver();
});

it('should show the banner if the shouldShowBanner prop is true', () => {
const shouldShowBanner = true;

const { getByTestId } = render(
<ThemeProvider theme={theme}>
<MockedProvider>
<Dashboard
accountListId="abc"
data={data}
shouldShowBanner={shouldShowBanner}
/>
</MockedProvider>
</ThemeProvider>,
);

expect(getByTestId('staticBanner')).toBeInTheDocument();
});

it('should NOT show the banner if the shouldShowBanner prop is false', () => {
const shouldShowBanner = false;

const { queryByTestId } = render(
<ThemeProvider theme={theme}>
<MockedProvider>
<Dashboard
accountListId="abc"
data={data}
shouldShowBanner={shouldShowBanner}
/>
</MockedProvider>
</ThemeProvider>,
);

expect(queryByTestId('staticBanner')).not.toBeInTheDocument();
});
});
9 changes: 8 additions & 1 deletion src/components/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import MonthlyGoal from './MonthlyGoal/MonthlyGoal';
import Balance from './Balance';
import DonationHistories from './DonationHistories';
import ThisWeek from './ThisWeek';
import { StaticBanner } from '../Shared/staticBanner/StaticBanner';

interface Props {
data: GetDashboardQuery;
accountListId: string;
shouldShowBanner?: boolean;
}

const variants = {
Expand All @@ -27,7 +29,11 @@ const variants = {
},
};

const Dashboard = ({ data, accountListId }: Props): ReactElement => {
const Dashboard = ({
data,
accountListId,
shouldShowBanner = false,
}: Props): ReactElement => {
return (
<>
<Welcome firstName={data.user.firstName ?? undefined} />
Expand All @@ -39,6 +45,7 @@ const Dashboard = ({ data, accountListId }: Props): ReactElement => {
exit="exit"
variants={variants}
>
{shouldShowBanner && <StaticBanner />}
<Grid container spacing={3} alignItems="stretch">
<Grid xs={12} sm={8} item>
<MonthlyGoal
Expand Down
73 changes: 73 additions & 0 deletions src/components/Shared/staticBanner/StaticBanner.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { render, waitFor } from '@testing-library/react';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { GetUsersOrganizationsQuery } from './getOrganizationType.generated';
import { StaticBanner } from './StaticBanner';

const mockResponseNonCru = {
GetUsersOrganizations: {
userOrganizationAccounts: [
{
organization: {
organizationType: 'Non-Cru',
},
},
{
organization: {
organizationType: 'Non-Cru',
},
},
],
},
};
const mockResponseCru = {
GetUsersOrganizations: {
userOrganizationAccounts: [
{
organization: {
organizationType: 'Cru',
},
},
{
organization: {
organizationType: 'Non-Cru',
},
},
],
},
};

test('static banner displays for user in Non-Cru org', async () => {
const { queryByTestId } = render(
<GqlMockedProvider<{
GetUsersOrganizations: GetUsersOrganizationsQuery;
}>
mocks={{
mockResponseNonCru,
}}
>
<StaticBanner />
</GqlMockedProvider>,
);

await waitFor(() =>
expect(queryByTestId('nonCruOrgReminder')).toBeInTheDocument(),
);
});

test('static banner does not display for user in a Cru org', async () => {
const { queryByTestId } = render(
<GqlMockedProvider<{
GetUsersOrganizations: GetUsersOrganizationsQuery;
}>
mocks={{
mockResponseCru,
}}
>
<StaticBanner />
</GqlMockedProvider>,
);

await waitFor(() =>
expect(queryByTestId('nonCruOrgReminder')).not.toBeInTheDocument(),
);
});
53 changes: 53 additions & 0 deletions src/components/Shared/staticBanner/StaticBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import Alert from '@mui/material/Alert';
import { Link } from '@mui/material';
import { useGetUsersOrganizationsQuery } from './getOrganizationType.generated';

interface StaticBannerProps {
severity?: 'error' | 'info' | 'success' | 'warning';
}

export const StaticBanner: React.FC<StaticBannerProps> = ({
severity = 'warning',
}) => {
const { t } = useTranslation();

const { data, loading } = useGetUsersOrganizationsQuery();
const nonCruUser = useMemo(() => {
const foundCruOrg = data?.userOrganizationAccounts.some(
(org) =>
org.organization.organizationType === 'Cru-International' ||
org.organization.organizationType === 'Cru',
);
return !foundCruOrg;
}, [data]);

return (
<div data-testid="staticBanner">
{!loading && nonCruUser ? (
<Alert severity={severity}>
{t(
`Due to data privacy regulations and costs, Cru will no longer be able to host MPDX data for non-Cru/non-CCCI ministries. `,
)}
<b>
{t(
`Your data in MPDX will be deleted if you don’t export from MPDX by January 31, 2024,`,
)}
</b>
{t(
` or let us know why you might need an extension. For more information and to take action, read `,
)}
<Link
data-testid="nonCruOrgReminder"
href="https://docs.google.com/document/d/18TnQGmshg71l3J9Gd-4ltjIjhK2PLtuG_Vc94bt6xzE/"
target="_blank"
rel="noreferrer"
>
{t('this communication.')}
</Link>
</Alert>
) : null}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
query GetUsersOrganizations {
userOrganizationAccounts {
organization {
organizationType
}
}
}