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

(feat) :Added empty state for "No search results" and "No provider avaailable" in Provider management ESM #453

Merged
merged 11 commits into from
Nov 14, 2024
23 changes: 23 additions & 0 deletions packages/esm-providers-app/src/table/empty-state.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import styles from './empty-state.scss';

interface EmptySearchProps {
title: string;
subTitle: string;
icon: React.ReactNode;
}

const EmptyProviderState: React.FC<EmptySearchProps> = ({ title, subTitle, icon }) => {
const { t } = useTranslation();

return (
<div className={styles.emptyStateContainer}>
<div>{icon}</div>
<p className={styles.title}>{title}</p>
<p className={styles.subTitle}>{subTitle}</p>
</div>
);
};

export default EmptyProviderState;
26 changes: 26 additions & 0 deletions packages/esm-providers-app/src/table/empty-state.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@use '@carbon/colors';
@use '@carbon/layout';
@use '@carbon/type';

.emptyStateContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 300px;
background-color: colors.$gray-10;
row-gap: layout.$spacing-02;

& form {
border: none;
}

.title {
@include type.type-style('heading-01');
color: colors.$cool-gray-70;
}
.subTitle {
@include type.type-style('body-compact-01');
color: colors.$cool-gray-70;
}
}
7 changes: 6 additions & 1 deletion packages/esm-providers-app/src/table/generic-data-table.scss
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@
width: 2rem;
padding-top: 3px;
border-bottom: 0.375rem solid;
// @include brand-03(border-bottom-color);
}
}
}
Expand Down Expand Up @@ -145,3 +144,9 @@
padding-left: 2rem !important;
}
}

svg.iconOverrides {
width: layout.$spacing-11;
height: layout.$spacing-11;
fill: var(--brand-03);
}
141 changes: 59 additions & 82 deletions packages/esm-providers-app/src/table/provider-data-table.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import ProviderDetails from './provider-details.component';
import { ConfigObject } from '../config-schema';
import dayjs from 'dayjs';
import CustomActionMenu from '../overflow/overflow-component';
import EmptyProviderState from './empty-state.component';
import { Report, SearchLocate } from '@carbon/react/icons';

const ProviderListTable: React.FC<{ filter: (provider: any) => boolean }> = ({ filter }) => {
const { t } = useTranslation();
Expand All @@ -43,12 +45,8 @@ const ProviderListTable: React.FC<{ filter: (provider: any) => boolean }> = ({ f
const { pageSizes } = usePaginationInfo(pageSize, filteredProviders.length, currentPage, results?.length);

const headerData = [
{ header: t('serial', 'SNo'), key: 'serial' },
{ header: t('identifier', 'National ID'), key: 'identifier' },
{ header: t('name', 'Name'), key: 'name' },
{ header: t('license', 'License Number'), key: 'license' },
{ header: t('date', 'License expiry date'), key: 'date' },
{ header: t('status', 'Status'), key: 'status' },
{ header: t('action', 'Action'), key: 'action' },
];

Expand All @@ -63,41 +61,10 @@ const ProviderListTable: React.FC<{ filter: (provider: any) => boolean }> = ({ f

const rowData = results.map((provider, index) => {
const licenseAttr = provider.attributes.find((attr) => attr.attributeType.uuid === licenseNumberUuid);
const dateAttr = provider.attributes.find((attr) => attr.attributeType.uuid === licenseExpiryDateUuid);
const nationalId = provider.attributes.find((attr) => attr.attributeType.uuid === providerNationalIdUuid);

const licenseExpiryDate = dateAttr ? dayjs(dateAttr.value) : null;
const today = dayjs();
const daysUntilExpiry = licenseExpiryDate ? licenseExpiryDate.diff(today, 'day') : null;

let statusTag;

if (!licenseExpiryDate) {
statusTag = <Tag type="red">{t('missingExpiryDate', 'Missing expiry date')}</Tag>;
} else if (daysUntilExpiry < 0) {
statusTag = <Tag type="red">{t('licenseExpired', 'License has expired')}</Tag>;
} else if (daysUntilExpiry <= 3) {
statusTag = <Tag type="cyan">{t('licenseExpiringSoon', 'License is expiring soon')}</Tag>;
} else {
statusTag = <Tag type="green">{t('activeLicensed', 'Active License')}</Tag>;
}

return {
id: provider.uuid,
serial: (currentPage - 1) * pageSize + (index + 1),
identifier: nationalId ? (
maskNationalId(nationalId?.value)
) : (
<Tag type="red">{t('missingIDno', 'Missing National ID')}</Tag>
),
name: provider.person.display,
license: licenseAttr ? licenseAttr?.value : <Tag type="magenta">{t('unlicensed', 'Unlicensed')}</Tag>,
date: licenseExpiryDate ? (
licenseExpiryDate.format('YYYY-MM-DD')
) : (
<Tag type="magenta">{t('missingExpiryDate', 'Missing expiry date')}</Tag>
),
status: statusTag,
license: licenseAttr ? licenseAttr?.value : '--',
action: <CustomActionMenu provider={provider} />,
providerUuid: provider?.uuid,
};
Expand All @@ -124,55 +91,65 @@ const ProviderListTable: React.FC<{ filter: (provider: any) => boolean }> = ({ f
<Search
labelText=""
placeholder={t('searchProvider', 'Search for provider')}
onChange={(e) => setSearchQuery(e.target.value)} // Update search query
onChange={(e) => setSearchQuery(e.target.value)}
size={isDesktop(layout) ? 'sm' : 'lg'}
value={searchQuery}
/>
<DataTable isSortable rows={rowData} headers={headerData} size={responsiveSize} useZebraStyles>
{({
rows,
headers,
getExpandHeaderProps,
getTableProps,
getTableContainerProps,
getHeaderProps,
getRowProps,
}) => (
<TableContainer {...getTableContainerProps()}>
<Table className={styles.table} {...getTableProps()} aria-label="Provider list">
<TableHead>
<TableRow>
<TableExpandHeader enableToggle {...getExpandHeaderProps()} />
{headers.map((header, i) => (
<TableHeader key={i} {...getHeaderProps({ header })}>
{header.header}
</TableHeader>

{filteredProviders.length === 0 ? (
<EmptyProviderState
title={t('noProvidersAvailable', 'No providers available')}
subTitle={t('adjustFilterOrSwitch', 'Try adjusting your search or switch to a different category above.')}
icon={<Report className={styles.iconOverrides} />}
/>
) : (
<DataTable isSortable rows={rowData} headers={headerData} size={responsiveSize} useZebraStyles>
{({
rows,
headers,
getExpandHeaderProps,
getTableProps,
getTableContainerProps,
getHeaderProps,
getRowProps,
}) => (
<TableContainer {...getTableContainerProps()}>
<Table className={styles.table} {...getTableProps()} aria-label="Provider list">
<TableHead>
<TableRow>
<TableExpandHeader enableToggle {...getExpandHeaderProps()} />
{headers.map((header, i) => (
<TableHeader key={i} {...getHeaderProps({ header })}>
{header.header}
</TableHeader>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row, i) => (
<React.Fragment key={row.id}>
<TableExpandRow {...getRowProps({ row })}>
{row.cells.map((cell) => (
<TableCell key={cell.id}>{cell.value}</TableCell>
))}
</TableExpandRow>
{row && row.isExpanded ? (
<TableExpandedRow className={styles.expandedRow} colSpan={headers.length + 1}>
<div className={styles.container} key={i}>
<ProviderDetails providerUuid={row.id} />
</div>
</TableExpandedRow>
) : (
<TableExpandedRow className={styles.hiddenRow} colSpan={headers.length + 2} />
)}
</React.Fragment>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row, i) => (
<React.Fragment key={row.id}>
<TableExpandRow {...getRowProps({ row })}>
{row.cells.map((cell) => (
<TableCell key={cell.id}>{cell.value}</TableCell>
))}
</TableExpandRow>
{row && row.isExpanded ? (
<TableExpandedRow className={styles.expandedRow} colSpan={headers.length + 1}>
<div className={styles.container} key={i}>
<ProviderDetails providerUuid={row.id} />
</div>
</TableExpandedRow>
) : (
<TableExpandedRow className={styles.hiddenRow} colSpan={headers.length + 2} />
)}
</React.Fragment>
))}
</TableBody>
</Table>
</TableContainer>
)}
</DataTable>
</TableBody>
</Table>
</TableContainer>
)}
</DataTable>
)}
{paginated && (
<Pagination
forwardText={t('nextPage', 'Next page')}
Expand Down
2 changes: 2 additions & 0 deletions packages/esm-providers-app/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"action": "Action",
"activeLicensed": "Active License",
"actives": "Active",
"adjustFilterOrSwitch": "Try adjusting your search or switch to a different category above.",
"all": "All Providers",
"cancel": "Cancel",
"continue": "Continue to registration",
Expand Down Expand Up @@ -31,6 +32,7 @@
"nextPage": "Next page",
"noHealthWorkerFound": "No Health worker found",
"noHwrApi": "Health Care Worker Registry API credentials not configured,Kindly contact system admin. Do you want to continue to create an account",
"noProvidersAvailable": "No providers available",
"previousPage": "Previous page",
"profileOverview": "Profile overview",
"providerManagement": "Providers Management",
Expand Down
Loading