Skip to content

Commit

Permalink
feat: enable global filter to filter communities
Browse files Browse the repository at this point in the history
  • Loading branch information
RRanath authored and ccbc-service-account committed Nov 25, 2024
1 parent 40ee00d commit ea051c8
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 5 deletions.
36 changes: 34 additions & 2 deletions app/components/AnalystDashboard/AllDashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-shadow */
/* eslint-disable react/jsx-pascal-case */
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { graphql, useFragment } from 'react-relay';
import styled from 'styled-components';
import cookie from 'js-cookie';
Expand All @@ -18,6 +18,7 @@ import {
MRT_ToggleDensePaddingButton,
MRT_ToggleFullScreenButton,
MRT_ShowHideColumnsButton,
MRT_FilterFns,
} from 'material-react-table';

import RowCount from 'components/Table/RowCount';
Expand Down Expand Up @@ -302,6 +303,10 @@ const AllDashboardTable: React.FC<Props> = ({ query }) => {
const [showColumnFilters, setShowColumnFilters] = useState(false);

const [sorting, setSorting] = useState<MRT_SortingState>([]);
const [expanded, setExpanded] = useState({});
const [globalFilter, setGlobalFilter] = useState(null);

const expandedRowsRef = useRef({});

const [columnSizing, setColumnSizing] = useState<MRT_ColumnSizingState>({
'mrt-row-expand': 40,
Expand Down Expand Up @@ -442,6 +447,11 @@ const AllDashboardTable: React.FC<Props> = ({ query }) => {
}
}, [visibilityPreference]);

useEffect(() => {
setExpanded(globalFilter ? expandedRowsRef.current : {});
expandedRowsRef.current = {};
}, [globalFilter]);

const state = {
showGlobalFilter: true,
columnFilters,
Expand All @@ -450,6 +460,20 @@ const AllDashboardTable: React.FC<Props> = ({ query }) => {
showColumnFilters,
sorting,
columnSizing,
expanded,
globalFilter,
};

const customGlobalFilter = (row, id, filterValue, filterMeta) => {
const defaultMatch = MRT_FilterFns.fuzzy(row, id, filterValue, filterMeta);
const communitiesString = row.original.communities
?.map((item) => item.geoName)
.join(',')
?.toLowerCase();
const detailsMatch = communitiesString?.includes(filterValue.toLowerCase());
expandedRowsRef.current[row.id] = detailsMatch;

return defaultMatch || detailsMatch;
};

const getCommunities = (application) => {
Expand Down Expand Up @@ -689,8 +713,16 @@ const AllDashboardTable: React.FC<Props> = ({ query }) => {
filterFns: {
filterNumber,
statusFilter,
customGlobalFilter,
},
renderDetailPanel: ({ row }) => (
<AllDashboardDetailPanel row={row} filterValue={globalFilter} />
),
globalFilterFn: 'customGlobalFilter',
onGlobalFilterChange: setGlobalFilter,
onExpandedChange: (expanded) => {
setExpanded(expanded);
},
renderDetailPanel: ({ row }) => <AllDashboardDetailPanel row={row} />,
renderToolbarInternalActions: ({ table }) => (
<Box>
<IconButton size="small">
Expand Down
37 changes: 35 additions & 2 deletions app/components/AnalystDashboard/AllDashboardDetailPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import styled from 'styled-components';

interface Props {
row: any;
filterValue: string;
}

const StyledMapLink = styled.a`
Expand All @@ -17,7 +18,36 @@ const StyledSpan = styled.span`
display: block;
`;

const AllDashboardDetailPanel: React.FC<Props> = ({ row }) => {
const StyledHighlightSpan = styled.span`
background-color: ${(props) => props.theme.color.primaryYellow};
`;

const HighlightFilterMatch = ({ text, filterValue }) => {
if (!filterValue) return text;

const normalizedFilterValue = filterValue.replace(/\s+/g, '').toLowerCase();
const normalizedText = text.replace(/\s+/g, '').toLowerCase();

const matchIndex = normalizedText.indexOf(normalizedFilterValue);

if (matchIndex === -1) {
return text;
}

const beforeMatch = text.slice(0, matchIndex);
const match = text.slice(matchIndex, matchIndex + filterValue.length);
const afterMatch = text.slice(matchIndex + filterValue.length);

return (
<>
{beforeMatch}
<StyledHighlightSpan>{match}</StyledHighlightSpan>
{afterMatch}
</>
);
};

const AllDashboardDetailPanel: React.FC<Props> = ({ row, filterValue }) => {
const communities = (row.original.communities as any[]) || [];
return (
<>
Expand All @@ -30,7 +60,10 @@ const AllDashboardDetailPanel: React.FC<Props> = ({ row }) => {
target="_blank"
rel="noopener noreferrer"
>
{item.geoName}
<HighlightFilterMatch
text={item.geoName}
filterValue={filterValue}
/>
</StyledMapLink>
{index < communities.length - 1 && ', '}
</>
Expand Down
9 changes: 8 additions & 1 deletion app/components/Table/ClearFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const ClearFilters: React.FC<Props> = ({
const clearFilters = () => {
table.resetColumnFilters();
table.setColumnFilters(defaultFilters);
table.setGlobalFilter('');
};

const isTableFiltersPresent =
Expand All @@ -29,9 +30,15 @@ const ClearFilters: React.FC<Props> = ({
filters.filter((f) => f.id === 'program' && (f.value as any[]).length < 3)
.length > 0;

const isGlobalFilterPresent = table.getState().globalFilter !== '';

return (
<Button
disabled={!isTableFiltersPresent && !isExternalFiltersPresent}
disabled={
!isTableFiltersPresent &&
!isExternalFiltersPresent &&
!isGlobalFilterPresent
}
variant="text"
onClick={clearFilters}
data-testid="clear-filter-button"
Expand Down
56 changes: 56 additions & 0 deletions app/tests/pages/analyst/dashboard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,62 @@ describe('The index page', () => {
});
});

it('global filter correctly filters communities and expand the row with match highlighting', async () => {
jest
.spyOn(moduleApi, 'useFeature')
.mockReturnValue(mockShowCbcProjects(true));

pageTestingHelper.loadQuery();
pageTestingHelper.renderPage();

expect(screen.getByText('CCBC-010001')).toBeInTheDocument();
expect(screen.getByText('CCBC-010002')).toBeInTheDocument();

const globalSearch = screen.getByPlaceholderText('Search');
expect(globalSearch).toBeInTheDocument();

fireEvent.change(globalSearch, {
target: { value: 'Bear Lake' },
});

await waitFor(() => {
expect(screen.queryByText('CCBC-010001')).not.toBeInTheDocument();
expect(screen.getByText('CCBC-010002')).toBeInTheDocument();

expect(screen.getByText('Bear Lake')).toHaveStyle(
'background-color: #FCBA19'
);
});
});

it('clear filters correctly clears global filter and restore data', async () => {
jest
.spyOn(moduleApi, 'useFeature')
.mockReturnValue(mockShowCbcProjects(true));

pageTestingHelper.loadQuery();
pageTestingHelper.renderPage();

expect(screen.getByText('5555')).toBeInTheDocument();
const globalSearch = screen.getByPlaceholderText('Search');
expect(globalSearch).toBeInTheDocument();

fireEvent.change(globalSearch, {
target: { value: 'Bear Lake' },
});

await waitFor(() => {
expect(screen.queryByText('CCBC-010001')).not.toBeInTheDocument();
});

const clearFiltersBtn = screen.getByText('Clear Filtering');
await act(async () => {
fireEvent.click(clearFiltersBtn);
});

expect(screen.queryByText('CCBC-010001')).toBeInTheDocument();
});

it('cbc statuses are duplicated for both analyst and external statuses', async () => {
jest
.spyOn(moduleApi, 'useFeature')
Expand Down

0 comments on commit ea051c8

Please sign in to comment.