Skip to content

Commit

Permalink
implement Client side server side filters and sort (#1457)
Browse files Browse the repository at this point in the history
* Update data fetcher hooks to support sort and filters

* Add hook to manage client side filters

* Add accountability filter to inventory view details

* Update react-utils data fetching hooks

* Add sort and filter for locations list view

* Update tests and fix lint isues in react-utils

* Refactor filter row for locations

* Fix lint issues

* Fix bug on inventory details status filter

* Fix test regressions
  • Loading branch information
peterMuriuki authored Aug 2, 2024
1 parent 544f1f8 commit 766912c
Show file tree
Hide file tree
Showing 23 changed files with 1,552 additions and 287 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
width: 45%;
min-width: 192px;
}

.filter-row {
margin-bottom: 16px;
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
/* eslint-disable @typescript-eslint/naming-convention */
import React, { ReactNode, useMemo } from 'react';
import { useSimpleTabularView, NoData, Column } from '@opensrp/react-utils';
import {
useSimpleTabularView,
NoData,
Column,
GetControlledSortProps,
SortParamState,
} from '@opensrp/react-utils';
import { RouteComponentProps } from 'react-router';
import { locationResourceType } from '../../constants';
import { BrokenPage, TableLayout, BodyLayout, SearchForm } from '@opensrp/react-utils';
import { Helmet } from 'react-helmet';
import { useMls } from '../../mls';
import { TFunction } from '@opensrp/i18n';
import { Row, Col } from 'antd';
import { useHistory } from 'react-router-dom';
import { BundleEntry } from '@smile-cdr/fhirts/dist/FHIR-R4/classes/bundleEntry';
import { getEntryFromBundle, getTableData } from './utils';
import './base.css';
import type { URLParams } from '@opensrp/server-service';
import { Dictionary } from '@onaio/utils';
import { LocationGridFilterRowRender } from './dataGridFilterRow';
import { SorterResult } from 'antd/es/table/interface';

interface RouteParams {
locationId: string | undefined;
Expand All @@ -20,7 +30,7 @@ interface RouteParams {
export interface Props {
fhirBaseURL: string;
extraParamFilters?: URLParams;
columns: Column<Dictionary>[];
getColumns: (t: TFunction, getColumnSortProps: GetControlledSortProps) => Column<Dictionary>[];
pageTitle: string;
addLocationBtnRender: () => ReactNode;
}
Expand All @@ -41,7 +51,7 @@ export type BaseAllLocationListFlatProps = Props & RouteComponentProps<RoutePara
* @returns {Function} returns paginated locations list display
*/
export const BaseAllLocationListFlat: React.FC<BaseAllLocationListFlatProps> = (props) => {
const { fhirBaseURL, extraParamFilters, addLocationBtnRender, columns, pageTitle } = props;
const { fhirBaseURL, extraParamFilters, addLocationBtnRender, getColumns, pageTitle } = props;
const { t } = useMls();
const history = useHistory();
const getSearchParams = getSearchParamsFactory(extraParamFilters ?? {});
Expand All @@ -50,6 +60,8 @@ export const BaseAllLocationListFlat: React.FC<BaseAllLocationListFlatProps> = (
queryValues: { data, isFetching, isLoading, error },
tablePaginationProps,
searchFormProps,
sortOptions: { updateSortParams, getControlledSortProps },
filterOptions: { updateFilterParams, currentFilters },
} = useSimpleTabularView<BundleEntry>(
fhirBaseURL,
locationResourceType,
Expand Down Expand Up @@ -80,10 +92,29 @@ export const BaseAllLocationListFlat: React.FC<BaseAllLocationListFlatProps> = (

const tableProps = {
datasource: tableData,
columns,
columns: getColumns(t, getControlledSortProps),
loading: isFetching || isLoading,
pagination: tablePaginationProps,
locale: getTableLocale(),
onChange: function (
_: unknown,
__: unknown,
sorter: SorterResult<Dictionary> | SorterResult<Dictionary>[]
) {
const sorterArray = Array.isArray(sorter) ? sorter : [sorter];
const sortMap = sorterArray.reduce((acc, sort) => {
const dataIndex = sort.column?.dataIndex as string | undefined;
if (!sort.order) {
acc[dataIndex as string] = undefined;
return acc;
}
if (dataIndex) {
acc[dataIndex as string] = { paramAccessor: dataIndex, order: sort.order };
}
return acc;
}, {} as SortParamState);
updateSortParams(sortMap);
},
};
const headerProps = {
pageHeaderProps: {
Expand All @@ -103,6 +134,11 @@ export const BaseAllLocationListFlat: React.FC<BaseAllLocationListFlatProps> = (
<SearchForm {...searchFormProps} />
{addLocationBtnRender()}
</div>
<LocationGridFilterRowRender
fhirBaseUrl={fhirBaseURL}
updateFilterParams={updateFilterParams}
currentFilters={currentFilters}
/>
<TableLayout {...tableProps} />
</Col>
</Row>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { MoreOutlined, PlusOutlined } from '@ant-design/icons';
import { BaseAllLocationListFlat, BaseAllLocationListFlatProps } from './base';
import { Dictionary } from '@onaio/utils';
import { EditLink } from '../EditLink';
import { TFunction } from '@opensrp/i18n';
import { GetControlledSortProps } from '@opensrp/react-utils';

export type AllLocationListFlatProps = Omit<
BaseAllLocationListFlatProps,
Expand Down Expand Up @@ -44,26 +46,24 @@ export const AllLocationListFlat: React.FC<AllLocationListFlatProps> = (props) =
];
};

const columns = [
const getColumns = (t: TFunction, getControlledSortProps: GetControlledSortProps) => [
{
title: t('Name'),
dataIndex: 'name' as const,
editable: true,
sorter: true,
...getControlledSortProps('name'),
},
{
title: t('Parent'),
dataIndex: 'parent' as const,
editable: true,
},
{
title: t('Physical Type'),
dataIndex: 'type' as const,
editable: true,
},
{
title: t('Status'),
dataIndex: 'status' as const,
editable: true,
},
{
title: t('Actions'),
Expand Down Expand Up @@ -107,7 +107,7 @@ export const AllLocationListFlat: React.FC<AllLocationListFlatProps> = (props) =
...props,
pageTitle: t('Locations'),
addLocationBtnRender,
columns,
getColumns,
};

return <BaseAllLocationListFlat {...baseProps} />;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { ILocation } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/ILocation';
import { Space, Select } from 'antd';
import React from 'react';
import { FilterParamState, PaginatedAsyncSelect } from '@opensrp/react-utils';
import { locationResourceType } from '@opensrp/fhir-helpers';
import { useMls } from '.././../mls';
import { Trans } from '@opensrp/i18n';

export interface LocationGridFilterRowRenderProps {
fhirBaseUrl: string;
updateFilterParams: (filter: FilterParamState) => void;
currentFilters: FilterParamState;
}

const partOfFilterDataIdx = 'partof';
const statusFilterDataIdx = 'status';

export const LocationGridFilterRowRender = (props: LocationGridFilterRowRenderProps) => {
const { t } = useMls();
const { fhirBaseUrl, updateFilterParams, currentFilters } = props;
return (
<div className="filter-row" data-testid="filter-row">
<Space>
<Trans t={t} i18nKey="parentLocationFilter">
<Space>
Parent Location:
<PaginatedAsyncSelect<ILocation>
allowClear={true}
showSearch={true}
resourceType={locationResourceType}
baseUrl={fhirBaseUrl}
transformOption={(resource) => {
return {
value: resource.id as string,
label: resource.name as string,
ref: resource,
};
}}
onChange={(value) => {
if (!value) {
updateFilterParams({ [partOfFilterDataIdx]: undefined });
} else {
updateFilterParams({
[partOfFilterDataIdx]: {
paramAccessor: 'partof',
rawValue: value,
paramValue: value,
},
});
}
}}
/>
</Space>
</Trans>
<Trans t={t} i18nKey="locationStatusFilter">
<Space>
Status:
<Select
id="location-status-filter"
value={currentFilters['status']?.rawValue ?? '*'}
style={{ width: 120 }}
onChange={(value: string) => {
if (value === '*') {
updateFilterParams({ [statusFilterDataIdx]: undefined });
return;
}
updateFilterParams({
[statusFilterDataIdx]: {
paramAccessor: 'status',
rawValue: value,
paramValue: value,
},
});
}}
options={[
{ value: 'active', label: t('Active') },
{ value: 'inactive', label: t('Inactive') },
{ value: '*', label: t('Show all') },
]}
/>
</Space>
</Trans>
</Space>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { BaseAllLocationListFlat, BaseAllLocationListFlatProps } from './base';
import { Dictionary } from '@onaio/utils';
import { eusmPhysicalLocationsFilterParams } from './utils';
import { URL_LOCATION_VIEW_DETAILS, URL_SERVICE_POINT_ADD_EDIT } from '../../constants';
import { TFunction } from '@opensrp/i18n';
import { GetControlledSortProps } from '@opensrp/react-utils';

export type EusmLocationListFlatProps = Omit<
BaseAllLocationListFlatProps,
Expand Down Expand Up @@ -38,26 +40,24 @@ export const EusmLocationListFlat: React.FC<EusmLocationListFlatProps> = (props)
];
};

const columns = [
const getColumns = (t: TFunction, getControlledSortProps: GetControlledSortProps) => [
{
title: t('Name'),
dataIndex: 'name' as const,
editable: true,
sorter: true,
...getControlledSortProps('name'),
},
{
title: t('Type'),
dataIndex: 'type' as const,
editable: true,
},
{
title: t('Status'),
dataIndex: 'status' as const,
editable: true,
},
{
title: t('Parent'),
dataIndex: 'parent' as const,
editable: true,
},
{
title: t('Actions'),
Expand Down Expand Up @@ -103,7 +103,7 @@ export const EusmLocationListFlat: React.FC<EusmLocationListFlatProps> = (props)
...props,
pageTitle: t('Service points'),
addLocationBtnRender,
columns,
getColumns,
extraParamFilters: eusmPhysicalLocationsFilterParams,
};

Expand Down
Loading

0 comments on commit 766912c

Please sign in to comment.