Skip to content

Commit

Permalink
Update Project Household Enrollments table with new designs (#989)
Browse files Browse the repository at this point in the history
* Update Project Enrollment tables

* fix a11y

* More accessibility fixes

* Simplify and resolve todos

* Add storybook story

* Remove errant comment

* Add comments

* Update api of TableRowActions

* Fix issue with fulColSpan

* Right-align table row actions

Co-authored-by: Gig <[email protected]>

* Remove comment

* Replace overrideTableBody with more understandable API

* Implement PR suggestion of moving table row to column def

* Cleanup and add comments

* Port over relevant changes from other PR

* Refactor to use renderCellContents

* Revert out-of-scope change

* Add todo

* Remove circular dependency

* Clean up

* Centralize action column base attrs

* PR feedback

* Fix typescript problems

* Implement Table Actions pattern and default columns (#998)

* Implement Table Actions pattern and default columns

* Add random comment

* Add storybook for table actions and fix cde story

* Implement PR suggestion of moving table row to column def

* add todo

* Finish refactor to use column def instead of getTableAction

* Fix bulk services loading

* Provide a visually hidden header when header isnt provided

* Keep existing behavior of individual/household assessment viewing

* Fix typescript

* Add accessible text for RelativeDateDisplay

* implement one possible approach for client ID typescript

* Remove unnecessary cast

---------

Co-authored-by: Gig Ashton <[email protected]>
  • Loading branch information
martha and gigxz authored Jan 6, 2025
1 parent 64aace0 commit 4bb7e11
Show file tree
Hide file tree
Showing 47 changed files with 1,687 additions and 1,068 deletions.
12 changes: 11 additions & 1 deletion .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import { MemoryRouter } from 'react-router-dom';
import theme from '../src/config/theme';
import '../src/index.css';
import {
AMERICAN_LAKE_HOUSE,
applicationUserMock,
fakeEnrollment,
RITA_ACKROYD,
} from '../src/test/__mocks__/requests';
import { RenderRouteWithOutletContext } from './components/RenderRouteWithOutletContext';
import { ProjectDashboardContext } from '../src/modules/projects/components/ProjectDashboard';

export const parameters = {
layout: 'padded',
Expand All @@ -40,7 +42,7 @@ export const decorators = [
// React Router decorator can optionally provide a dashboard context if `dashboardContext` is passed.
// Caller can optionally specify the client/enrollemnt mocks that should be used in the context by
// passing `client` or `enrollment` parameters.
const { dashboardContext, client, enrollment } = parameters;
const { dashboardContext, client, enrollment, project } = parameters;
switch (dashboardContext) {
case 'enrollment':
return (
Expand All @@ -64,6 +66,14 @@ export const decorators = [
{Story()}
</RenderRouteWithOutletContext>
);
case 'project':
return (
<RenderRouteWithOutletContext<ProjectDashboardContext>
context={{ project: project || AMERICAN_LAKE_HOUSE }}
>
{Story()}
</RenderRouteWithOutletContext>
);
default:
return <MemoryRouter>{Story()}</MemoryRouter>;
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/elements/CommonMenuButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@ import { To } from 'react-router-dom';

import RouterLink from './RouterLink';
import { MoreMenuIcon } from './SemanticIcons';
import { LocationState } from '@/routes/routeUtil';

export type CommonMenuItem = {
key: string;
title: ReactNode;
to?: To;
onClick?: VoidFunction;
title?: ReactNode;
divider?: boolean;
disabled?: boolean;
ariaLabel?: string;
linkState?: LocationState;
openInNew?: boolean;
};

Expand Down
63 changes: 63 additions & 0 deletions src/components/elements/DateWithRelativeTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
Box,
Tooltip,
TooltipProps,
Typography,
TypographyProps,
} from '@mui/material';
import { visuallyHidden } from '@mui/utils';
import { useMemo } from 'react';

import { getFormattedDates } from './RelativeDateDisplay';

export interface DateWithRelativeTooltipProps {
dateString: string;
preciseTime?: boolean;
TooltipProps?: Omit<TooltipProps, 'title' | 'children'>;
TypographyProps?: TypographyProps;
}

/**
* Date with relative date as tooltip
*/
const DateWithRelativeTooltip = ({
dateString,
preciseTime = false,
TooltipProps = {},
TypographyProps = {},
}: DateWithRelativeTooltipProps) => {
const [formattedDate, formattedDateRelative] = useMemo(
() => getFormattedDates(dateString, preciseTime),
[dateString, preciseTime]
);

if (!dateString || !formattedDate || !formattedDateRelative) return null;

return (
<Tooltip
title={
<Typography component='span' variant='inherit'>
{formattedDateRelative}
</Typography>
}
arrow
{...TooltipProps}
>
<Typography
component='span'
variant='inherit'
{...TypographyProps}
sx={{
cursor: 'pointer',
...TypographyProps.sx,
}}
>
{formattedDate}
{/* Include the tooltip text as visually hidden for accessibility */}
<Box sx={visuallyHidden}>, {formattedDateRelative}</Box>
</Typography>
</Tooltip>
);
};

export default DateWithRelativeTooltip;
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
import {
Box,
Tooltip,
TooltipProps,
Typography,
TypographyProps,
} from '@mui/material';
import { visuallyHidden } from '@mui/utils';
import { useMemo } from 'react';

import {
formatDateForDisplay,
formatDateTimeForDisplay,
formatRelativeDateTime,
parseHmisDateString,
} from '@/modules/hmis/hmisUtil';

export const getFormattedDates = (
dateString: string,
preciseTime: boolean = true
) => {
const date = parseHmisDateString(dateString);
if (!date) return [];
return [
preciseTime ? formatDateTimeForDisplay(date) : formatDateForDisplay(date),
formatRelativeDateTime(date),
];
};

export interface RelativeDateDisplayProps {
dateString: string;
prefixVerb?: string;
suffixText?: string;
tooltipSuffixText?: string;
TooltipProps?: Omit<TooltipProps, 'title' | 'children'>;
TypographyProps?: TypographyProps;
}
Expand All @@ -27,22 +43,22 @@ const RelativeDateDisplay = ({
dateString,
prefixVerb,
suffixText,
tooltipSuffixText,
TooltipProps = {},
TypographyProps = {},
}: RelativeDateDisplayProps) => {
const [formattedDate, formattedDateRelative] = useMemo(() => {
const date = parseHmisDateString(dateString);
if (!date) return [];
return [formatDateTimeForDisplay(date), formatRelativeDateTime(date)];
}, [dateString]);
const [formattedDate, formattedDateRelative] = useMemo(
() => getFormattedDates(dateString),
[dateString]
);

if (!dateString || !formattedDate || !formattedDateRelative) return null;

return (
<Tooltip
title={
<Typography component='span' variant='inherit'>
{formattedDate}
{formattedDate} {tooltipSuffixText}
</Typography>
}
arrow
Expand All @@ -57,7 +73,12 @@ const RelativeDateDisplay = ({
...TypographyProps.sx,
}}
>
{prefixVerb || null} {formattedDateRelative} {suffixText || null}
{/* Include the tooltip text as visually hidden for accessibility */}
{prefixVerb || null} {formattedDateRelative}{' '}
<Box sx={visuallyHidden}>
({formattedDate} {tooltipSuffixText})
</Box>{' '}
{suffixText || null}
</Typography>
</Tooltip>
);
Expand Down
39 changes: 36 additions & 3 deletions src/components/elements/table/GenericTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ import { Box, Paper } from '@mui/material';
import { Meta, StoryFn } from '@storybook/react';

import GenericTable, { Props as GenericTableProps } from './GenericTable';
import TableRowActions from '@/components/elements/table/TableRowActions';
import { BASE_ACTION_COLUMN_DEF } from '@/components/elements/table/tableRowActionUtil';
import { SsnDobShowContextProvider } from '@/modules/client/providers/ClientSsnDobVisibility';
import { getCustomDataElementColumns } from '@/modules/hmis/hmisUtil';
import {
clientBriefName,
getCustomDataElementColumns,
} from '@/modules/hmis/hmisUtil';
import { CLIENT_COLUMNS } from '@/modules/search/components/ClientSearch';
import { RITA_ACKROYD } from '@/test/__mocks__/requests';
import { ClientFieldsFragment, DisplayHook } from '@/types/gqlTypes';
Expand All @@ -30,7 +35,6 @@ const Template =
);

const clientColumns = [
CLIENT_COLUMNS.id,
CLIENT_COLUMNS.first,
CLIENT_COLUMNS.last,
CLIENT_COLUMNS.ssn,
Expand Down Expand Up @@ -136,8 +140,37 @@ const rowsWithCdes = [
WithCustomDataElements.args = {
rows: rowsWithCdes,
columns: [
CLIENT_COLUMNS.id,
CLIENT_COLUMNS.name,
...getCustomDataElementColumns<RowType>(rowsWithCdes),
],
};

export const WithTableRowActions = Template<RowType>().bind({});
WithTableRowActions.args = {
rows: fakeRows,
columns: [
CLIENT_COLUMNS.name,
{
...BASE_ACTION_COLUMN_DEF,
render: (record) => (
<TableRowActions
record={record}
recordName={clientBriefName(record)}
primaryActionConfig={{
title: 'Do something in-app',
key: 'onClick',
onClick: () =>
alert(`Hello, ${clientBriefName(record)} ${record.id}`),
}}
secondaryActionConfigs={[
{
title: 'Navigate to a link',
key: 'link',
to: 'https://storybook.js.org/docs', // just link somewhere random to show `to` prop working
},
]}
/>
),
},
],
};
Loading

0 comments on commit 4bb7e11

Please sign in to comment.