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

[MINT-3014] CR TDL Collab Card #1388

24 changes: 24 additions & 0 deletions src/components/ExternalLink/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,28 @@ describe('ExternalLink', () => {
expect(externalLink).toHaveAttribute('target', '_blank');
expect(externalLink).toHaveAttribute('rel', 'noopener noreferrer');
});

it('renders the modal with the correct text when toEchimp is true', () => {
render(
<ExternalLink href="https://echimp.cmsnet/" toEchimp>
Click me
</ExternalLink>
);

const linkElement = screen.getByText('Click me');

fireEvent.click(linkElement);

expect(
screen.getByText(i18next.t('externalLinkModal:heading'))
).toBeInTheDocument();

expect(
screen.getByText(
(_, element) =>
element?.textContent ===
i18next.t('externalLinkModal:descriptionEchimp')
)
).toBeInTheDocument();
});
});
16 changes: 11 additions & 5 deletions src/components/ExternalLink/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ import PageHeading from 'components/PageHeading';

type ExternalLinkModalTypes = {
children: React.ReactNode;
className?: string;
href: string;
variant?: 'external' | 'unstyled' | 'nav';
asButton?: boolean;
className?: string;
toEchimp?: boolean;
inlineText?: boolean;
};

const ExternalLink = ({
children,
href,
variant,
asButton,
className,
toEchimp,
inlineText = false
}: ExternalLinkModalTypes) => {
const { t: externalT } = useTranslation('externalLinkModal');
Expand All @@ -43,19 +47,21 @@ const ExternalLink = ({
className="font-body-md line-height-sans-4 margin-top-0 margin-bottom-4"
style={{ whiteSpace: 'break-spaces' }}
>
{externalT('description')}
{toEchimp ? externalT('descriptionEchimp') : externalT('description')}
</p>

<Link
href={href}
aria-label={externalT('continueButton')}
aria-label={
toEchimp ? externalT('continueEchimp') : externalT('continueButton')
}
target="_blank"
rel="noopener noreferrer"
className="usa-button text-white text-no-underline"
onClick={() => setIsModalOpen(false)}
variant={variant}
>
{externalT('leave')}
{toEchimp ? externalT('continueEchimp') : externalT('leave')}
</Link>

<Button
Expand Down Expand Up @@ -92,7 +98,7 @@ const ExternalLink = ({
) : (
<Button
type="button"
unstyled
unstyled={!asButton}
className={classNames(className, 'margin-right-2')}
onClick={() => {
setIsModalOpen(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import i18next from 'i18next';

import CRTDLCard, { CRTDLType } from './index';

const mockCrtdls: CRTDLType[] = [
{ id: 'crtdl1', __typename: 'EChimpCR' },
{ id: 'crtdl2', __typename: 'EChimpTDL' }
];

describe('CRTDLCard', () => {
it('renders the card with the correct heading', () => {
render(
<Router>
<CRTDLCard crtdls={mockCrtdls} modelID="model123" />
</Router>
);

expect(
screen.getByText(i18next.t('collaborationArea:crtdlsCard.heading'))
).toBeInTheDocument();
});

it('displays a message when there are no crtdls', () => {
render(
<Router>
<CRTDLCard crtdls={[]} modelID="model123" />
</Router>
);

expect(
screen.getByText(i18next.t('collaborationArea:crtdlsCard.noCrtdls'))
).toBeInTheDocument();
});

it('displays a list of crtdls when they are present', () => {
render(
<Router>
<CRTDLCard crtdls={mockCrtdls} modelID="model123" />
</Router>
);

expect(screen.getByText('crtdl1, crtdl2')).toBeInTheDocument();
});

it('renders the "View All" button when crtdls are present', () => {
render(
<Router>
<CRTDLCard crtdls={mockCrtdls} modelID="model123" />
</Router>
);

expect(
screen.getByText(i18next.t('collaborationArea:crtdlsCard.viewAll'))
).toBeInTheDocument();
});

it('does not render the "View All" button when there are no crtdls', () => {
render(
<Router>
<CRTDLCard crtdls={[]} modelID="model123" />
</Router>
);

expect(
screen.queryByText(i18next.t('collaborationArea:crtdlsCard.viewAll'))
).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import {
Card,
CardBody,
CardFooter,
CardHeader
} from '@trussworks/react-uswds';
import { GetModelPlanQuery } from 'gql/generated/graphql';

import ExternalLink from 'components/ExternalLink';
import UswdsReactLink from 'components/LinkWrapper';

import '../../index.scss';

export type CRTDLType = GetModelPlanQuery['modelPlan']['echimpCRsAndTDLs'][0];

type CRTDLCardType = {
crtdls: CRTDLType[];
modelID: string;
};

const CRTDLCard = ({ crtdls = [], modelID }: CRTDLCardType) => {
const { t: collaborationAreaT } = useTranslation('collaborationArea');

const firstFirstFiveCRTDLs = crtdls.slice(0, 5);

const remainingCRTDLs: number = crtdls.length - firstFirstFiveCRTDLs.length;

return (
<Card
gridLayout={{ mobile: { col: 12 }, desktop: { col: 4 } }}
className="collaboration-area__card"
>
<CardHeader>
<h3 className="usa-card__heading">
{collaborationAreaT('crtdlsCard.heading')}
</h3>
</CardHeader>

<CardBody>
{crtdls?.length === 0 ? (
<p className="text-base">
{collaborationAreaT('crtdlsCard.noCrtdls')}
</p>
) : (
<p className="text-base-dark">
{firstFirstFiveCRTDLs.map(crtdl => crtdl.id).join(', ')}
{remainingCRTDLs > 0 && (
<>
{' '}
{collaborationAreaT('crtdlsCard.andMore', {
count: remainingCRTDLs
})}
</>
)}
</p>
)}
</CardBody>

<CardFooter>
<ExternalLink
href="https://echimp.cmsnet/"
className="usa-button"
variant="unstyled"
asButton
toEchimp
>
{collaborationAreaT('crtdlsCard.addInEChimp')}
</ExternalLink>

{crtdls?.length !== 0 && (
<UswdsReactLink
className="usa-button usa-button--outline"
variant="unstyled"
to={`/models/${modelID}/collaboration-area/cr-and-tdl`}
>
{collaborationAreaT('crtdlsCard.viewAll')}
</UswdsReactLink>
)}
</CardFooter>
</Card>
);
};

export default CRTDLCard;
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const modelPlan = {
},
crs: [],
tdls: [],
echimpCRsAndTDLs: [],
operationalNeeds: [] as any,
documents: [
{
Expand Down
4 changes: 4 additions & 0 deletions src/features/ModelPlan/CollaborationArea/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import useMessage from 'hooks/useMessage';

import { UpdateFavoriteProps } from '../ModelPlanOverview';

import CRTDLCard from './Cards/CRTDLCard';
import DiscussionsCard from './Cards/DiscussionsCard';
import DocumentsCard from './Cards/DocumentsCard';
import ModelPlanCard from './Cards/ModelPlanCard';
Expand Down Expand Up @@ -59,6 +60,7 @@ const CollaborationArea = () => {
modelName,
discussions,
documents,
echimpCRsAndTDLs,
status,
collaborators,
isFavorite,
Expand Down Expand Up @@ -234,6 +236,8 @@ const CollaborationArea = () => {
<DiscussionsCard discussions={discussions} modelID={modelID} />

<DocumentsCard documents={documents} modelID={modelID} />

<CRTDLCard crtdls={echimpCRsAndTDLs} modelID={modelID} />
</CardGroup>
</GridContainer>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ describe('Model Plan Beneficiaries', () => {
);

await waitFor(() => {
expect(
screen.getByTestId('beneficiaries-precedence-rules-YES-note')
).toHaveValue('Yes precedence rules');
expect(screen.getByTestId('beneficiaries-precedence-note')).toHaveValue(
'Precedent note'
);
});

expect(asFragment()).toMatchSnapshot();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import React from 'react';
import { MemoryRouter, Route } from 'react-router-dom';
import { MockedProvider } from '@apollo/client/testing';
import { render, screen, waitFor } from '@testing-library/react';
import {
render,
screen,
waitFor,
waitForElementToBeRemoved
} from '@testing-library/react';
import {
ConfidenceType,
GetPeopleImpactedDocument,
Expand Down Expand Up @@ -93,9 +98,9 @@ describe('Model Plan Beneficiaries', () => {
</MemoryRouter>
);

await waitFor(() => {
expect(screen.getByTestId('expected-people-impacted')).toHaveValue(100);
});
await waitForElementToBeRemoved(() =>
screen.getByTestId('beneficiaries-selection-note-add-note-toggle')
);

expect(asFragment()).toMatchSnapshot();
});
Expand Down
1 change: 1 addition & 0 deletions src/features/ModelPlan/TaskList/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ describe('The Model Plan Task List', () => {
},
crs: [],
tdls: [],
echimpCRsAndTDLs: [],
operationalNeeds: [] as any,
documents: [
{
Expand Down
12 changes: 10 additions & 2 deletions src/gql/generated/graphql.ts

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions src/gql/operations/ModelPlan/GetModelPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ export default gql(/* GraphQL */ `
id
idNumber
}
echimpCRsAndTDLs {
... on EChimpCR {
id
}
... on EChimpTDL {
id
}
}
discussions {
id
content {
Expand Down
4 changes: 4 additions & 0 deletions src/i18n/en-US/externalLinkModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ const externalLinkModal = {
heading: 'Are you sure you want to leave MINT?',
description: `This link may require additional job codes, permissions, and/or connectivity via VPN to access content.

Please contact the CMS IT Service Desk at 410-786-2580 or 800-562-1963 if you need assistance.`,
descriptionEchimp: `ECHIMP requires additional job codes and/or permissions and connectivity via VPN to access content within the system.

Please contact the CMS IT Service Desk at 410-786-2580 or 800-562-1963 if you need assistance.`,
leave: 'Leave MINT',
continueEchimp: 'Continue to ECHIMP',
return: 'Go back to MINT',
document: {
heading: 'You are leaving MINT.',
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/en-US/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import homepageSettings from './home/settings';
import { basics, basicsMisc } from './modelPlan/basics';
import { beneficiaries, beneficiariesMisc } from './modelPlan/beneficiaries';
import changeHistory from './modelPlan/changeHistory';
import collaborationArea from './modelPlan/collaborationArea';
import { collaborators, collaboratorsMisc } from './modelPlan/collaborators';
import crs from './modelPlan/crs';
import crtdlsMisc from './modelPlan/crtdlsMisc';
Expand Down Expand Up @@ -49,7 +50,6 @@ import modelSummary from './readOnly/modelSummary';
import readOnlyModelPlan from './readOnly/readOnlyModelPlan';
import accessibilityStatement from './accessibilityStatement';
import auth from './auth';
import collaborationArea from './collaborationArea';
import cookies from './cookies';
import error from './error';
import externalLinkModal from './externalLinkModal';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ const collaborationArea = {
discussion: '{{count}} discussion',
discussion_other: '{{count}} discussions',
noDiscussions: 'No discussions started'
},
crtdlsCard: {
heading: 'FFS CRs and TDLS',
addInEChimp: 'Add in ECHIMP',
viewAll: 'View all',
noCrtdls: 'No CRs or TDLs',
andMore: ' + {{count}} more'
}
};

Expand Down