Skip to content

Commit

Permalink
[EASI-4409] [FE] Add ATO information from GQL to System Tables (#2743)
Browse files Browse the repository at this point in the history
* Add `atoExpirationDate` to `GetMyCedarSystems`

* Add `atoEffectiveDate` to `GetCedarSystems`

* AtoStatus

* function getAtoStatus(dt)

* Col atoStatus atoExpirationDate || atoEffectiveDate

* AtoStatus#atoStatusColumn

* AtoStatusIconText
Additional DateFormat string

* Correct `atoExpirationDate` prop

* Ato column type
Restore original column hide

* Clean up column handling

* Reorder AtoStatus file

---------

Co-authored-by: ClayBenson94 <clay.benson@oddball.io>
  • Loading branch information
adamodd and ClayBenson94 authored Aug 7, 2024
1 parent 506f76c commit 09d08df
Show file tree
Hide file tree
Showing 15 changed files with 353 additions and 151 deletions.
105 changes: 105 additions & 0 deletions src/components/shared/AtoStatus/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import {
IconCheck,
IconCheckCircleOutline,
IconError,
IconErrorOutline,
IconHelp,
IconHelpOutline,
IconHighlightOff,
IconWarning
} from '@trussworks/react-uswds';
// eslint-disable-next-line import/no-unresolved
import { IconProps } from '@trussworks/react-uswds/lib/components/Icon/Icon';
import classnames from 'classnames';

import { ATO_STATUS_DUE_SOON_DAYS } from 'constants/systemProfile';
import { AtoStatus } from 'types/systemProfile';
import { formatDateUtc, parseAsUTC } from 'utils/date';

import Tag from '../Tag';

/**
* Get the ATO Status from a date property
*/
export function getAtoStatus(dt: string | null | undefined): AtoStatus {
// No ato if it doesn't exist or invalid empty string
if (typeof dt !== 'string' || dt === '') return 'No ATO';

const expiry = parseAsUTC(dt).toString();

const date = new Date().toISOString();

if (date >= expiry) return 'Expired';

const soon = parseAsUTC(expiry)
.minus({ days: ATO_STATUS_DUE_SOON_DAYS })
.toString();

if (date >= soon) return 'Due Soon';

return 'Active';
}

const atoStatusTagClassNames: Record<AtoStatus, string> = {
Active: 'text-white bg-success-dark',
'Due Soon': 'bg-warning',
Expired: 'text-white bg-error-dark',
'No ATO': 'bg-base-lighter'
};

const atoStatusTagIcon: Record<AtoStatus, React.ComponentType<IconProps>> = {
Active: IconCheck,
'Due Soon': IconWarning,
Expired: IconError,
'No ATO': IconHelp
};

export function AtoStatusTag({
status,
className
}: {
status: AtoStatus;
className?: string;
}) {
const Icon = atoStatusTagIcon[status];
return (
<Tag className={classnames(`${atoStatusTagClassNames[status]}`, className)}>
<Icon className="margin-right-1" />
{status}
</Tag>
);
}

const atoStatusIconClassNames: Record<AtoStatus, string> = {
Active: 'text-success',
'Due Soon': 'text-warning-dark',
Expired: 'text-error',
'No ATO': 'text-base-light'
};

const atoStatusIcon: Record<AtoStatus, React.ComponentType<IconProps>> = {
Active: IconCheckCircleOutline,
'Due Soon': IconErrorOutline,
Expired: IconHighlightOff,
'No ATO': IconHelpOutline
};

export function AtoStatusIconText({ dt }: { dt: string | null | undefined }) {
const status = getAtoStatus(dt);
const Icon = atoStatusIcon[status];
const { t } = useTranslation('systemProfile');
return (
<div className="display-flex flex-align-center">
<Icon
size={3}
className={`margin-right-1 ${atoStatusIconClassNames[status]}`}
/>
<span>
{t(`systemTable.atoStatusColumn.${status}`)}{' '}
{formatDateUtc(dt || null, 'MM/yyyy')}
</span>
</div>
);
}
44 changes: 0 additions & 44 deletions src/components/shared/AtoStatusTag/index.tsx

This file was deleted.

6 changes: 6 additions & 0 deletions src/i18n/en-US/systemProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,12 @@ const systemProfile = {
header: 'Don’t see the system you’re looking for?',
description:
'If you believe there’s an error in the table above, please refresh the page. You may also use the Systems section of EASi to view information about all CMS systems. <link1>Go to all CMS systems<iconForward /></link1>'
},
atoStatusColumn: {
Active: 'Expires',
'Due Soon': 'Expires',
Expired: 'Expired',
'No ATO': 'No ATO on file'
}
},
bookmark: {
Expand Down
1 change: 1 addition & 0 deletions src/queries/GetCedarSystemsQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default gql`
systemMaintainerOrg
systemMaintainerOrgComp
isBookmarked
atoExpirationDate
}
}
`;
1 change: 1 addition & 0 deletions src/queries/GetMyCedarSystemsQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default gql`
systemMaintainerOrg
systemMaintainerOrgComp
isBookmarked
atoExpirationDate
}
}
`;
1 change: 1 addition & 0 deletions src/queries/types/GetCedarSystems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface GetCedarSystems_cedarSystems {
systemMaintainerOrg: string | null;
systemMaintainerOrgComp: string | null;
isBookmarked: boolean;
atoExpirationDate: Time | null;
}

export interface GetCedarSystems {
Expand Down
1 change: 1 addition & 0 deletions src/queries/types/GetMyCedarSystems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface GetMyCedarSystems_myCedarSystems {
systemMaintainerOrg: string | null;
systemMaintainerOrgComp: string | null;
isBookmarked: boolean;
atoExpirationDate: Time | null;
}

export interface GetMyCedarSystems {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DateTime } from 'luxon';
// Used to parse out mintute, day, ,month, and years from ISOString
export const parseAsUTC = (date: string) => DateTime.fromISO(date).toUTC();

type DateFormat = 'MM/dd/yyyy' | 'MMMM d, yyyy';
type DateFormat = 'MM/dd/yyyy' | 'MMMM d, yyyy' | 'MM/yyyy';

/**
* Output local timezoned dates from iso string.
Expand Down
114 changes: 67 additions & 47 deletions src/views/SystemList/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React, { useEffect, useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { useHistory, useLocation } from 'react-router-dom';
import {
CellProps,
Column,
Row,
useFilters,
Expand All @@ -30,6 +31,7 @@ import classNames from 'classnames';
import UswdsReactLink from 'components/LinkWrapper';
import PageLoading from 'components/PageLoading';
import Alert from 'components/shared/Alert';
import { AtoStatusIconText } from 'components/shared/AtoStatus';
import GlobalClientFilter from 'components/TableFilter';
import TablePageSize from 'components/TablePageSize';
import TablePagination from 'components/TablePagination';
Expand Down Expand Up @@ -120,7 +122,7 @@ export const Table = ({
}
}, [systemTableType, systems, mySystems]);

const columns = useMemo<Column<CedarSystem>[]>(() => {
const columns: Column<CedarSystem>[] = useMemo(() => {
const isBookmarked = (cedarSystemId: string): boolean =>
!!systems.find(system => system.id === cedarSystemId)?.isBookmarked;

Expand All @@ -143,8 +145,10 @@ export const Table = ({
});
};

return [
{
const cols: Column<CedarSystem>[] = [];

if (!isMySystems) {
cols.push({
Header: <IconBookmark />,
accessor: 'id',
id: 'systemId',
Expand All @@ -166,23 +170,28 @@ export const Table = ({
/>
</Button>
)
},
{
Header: t<string>('systemTable.header.systemAcronym'),
accessor: 'acronym'
},
{
Header: t<string>('systemTable.header.systemName'),
accessor: 'name',
id: 'systemName',
Cell: ({ row }: { row: Row<CedarSystem> }) => {
const url = `/systems/${row.original.id}/${
systemTableType === 'my-systems' ? 'workspace' : 'home/top'
}`;
return <UswdsReactLink to={url}>{row.original.name}</UswdsReactLink>;
}
},
{
});
}

cols.push({
Header: t<string>('systemTable.header.systemAcronym'),
accessor: 'acronym'
});

cols.push({
Header: t<string>('systemTable.header.systemName'),
accessor: 'name',
id: 'systemName',
Cell: ({ row }: { row: Row<CedarSystem> }) => {
const url = `/systems/${row.original.id}/${
systemTableType === 'my-systems' ? 'workspace' : 'home/top'
}`;
return <UswdsReactLink to={url}>{row.original.name}</UswdsReactLink>;
}
});

if (!isMySystems) {
cols.push({
Header: t<string>('systemTable.header.systemOwner'),
accessor: 'businessOwnerOrg',
id: 'systemOwner',
Expand All @@ -193,33 +202,44 @@ export const Table = ({
)?.acronym || row.original.businessOwnerOrg}
</p>
)
}
/*
{
Header: t<string>('systemTable.header.systemStatus'),
accessor: 'status',
id: 'systemStatus',
disableGlobalFilter: true,
Cell: ({ row }: { row: Row<CedarSystem> }) => (
<div>
<SystemHealthIcon
status={mapCedarStatusToIcon(row.original.status)}
size="medium"
className="margin-right-1"
/>
<span>{row.original.status}</span>
</div>
)
}
*/
];
}, [t, systems, systemTableType, createMutate, deleteMutate]);

// Remove bookmark column if showing My systems table
if (isMySystems) {
columns.splice(0, 1);
columns.pop(); // remove component if isMySystems
}
});
}

cols.push({
Header: t<string>('systemTable.header.systemStatus'),
accessor: 'atoExpirationDate',
Cell: ({
value
}: CellProps<CedarSystem, CedarSystem['atoExpirationDate']>) => (
<AtoStatusIconText dt={value} />
),
sortType: (a, b) =>
(a.values.atoExpirationDate ?? '') > (b.values.atoExpirationDate ?? '')
? 1
: -1
});

/*
{
Header: t<string>('systemTable.header.systemStatus'),
accessor: 'status',
id: 'systemStatus',
disableGlobalFilter: true,
Cell: ({ row }: { row: Row<CedarSystem> }) => (
<div>
<SystemHealthIcon
status={mapCedarStatusToIcon(row.original.status)}
size="medium"
className="margin-right-1"
/>
<span>{row.original.status}</span>
</div>
)
}
*/

return cols;
}, [t, systems, systemTableType, createMutate, deleteMutate, isMySystems]);

const {
getTableProps,
Expand Down
Loading

0 comments on commit 09d08df

Please sign in to comment.