Skip to content

Commit 0a0c41a

Browse files
committed
Init
1 parent 995b46b commit 0a0c41a

File tree

3 files changed

+158
-2
lines changed

3 files changed

+158
-2
lines changed

packages/module/patternfly-docs/generated/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ module.exports = {
2525
'/extensions/data-view/functionality/react': {
2626
id: "Functionality",
2727
title: "Functionality",
28-
toc: [[{"text":"Toolbar usage"},{"text":"Pagination state"},{"text":"Pagination example"},{"text":"Toolbar usage","id":"toolbar-usage-0"},{"text":"Selection state"},{"text":"Selection example"}]],
29-
examples: ["Pagination example","Selection example"],
28+
toc: [[{"text":"Toolbar usage"},{"text":"Pagination state"},{"text":"Pagination example"},{"text":"Toolbar usage","id":"toolbar-usage-0"},{"text":"Selection state"},{"text":"Selection example"},{"text":"Toolbar usage","id":"toolbar-usage-1"},{"text":"Filters state"},{"text":"Filtering example"}]],
29+
examples: ["Pagination example","Selection example","Filtering example"],
3030
section: "extensions",
3131
subsection: "Data view",
3232
source: "react",
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import '@testing-library/jest-dom';
2+
import { renderHook, act } from '@testing-library/react';
3+
import { useDataViewFilters, UseDataViewFiltersProps } from './filters';
4+
5+
describe('useDataViewSort', () => {
6+
const initialFilters = { search: 'test', tags: [ 'tag1', 'tag2' ] };
7+
8+
it('should initialize with provided initial filters', () => {
9+
const { result } = renderHook(() => useDataViewFilters({ initialFilters }));
10+
expect(result.current.filters).toEqual(initialFilters);
11+
});
12+
13+
it('should initialize with empty filters if no initialFilters provided', () => {
14+
const { result } = renderHook(() => useDataViewFilters({}));
15+
expect(result.current.filters).toEqual({});
16+
});
17+
18+
it('should set filters correctly', () => {
19+
const { result } = renderHook(() => useDataViewFilters({ initialFilters }));
20+
const newFilters = { search: 'new search' };
21+
act(() => result.current.onSetFilters(newFilters));
22+
23+
expect(result.current.filters).toEqual({ ...initialFilters, ...newFilters });
24+
});
25+
26+
it('should delete specific filters without removing keys', () => {
27+
const { result } = renderHook(() => useDataViewFilters({ initialFilters }));
28+
const filtersToDelete = { search: 'test' };
29+
act(() => result.current.onDeleteFilters(filtersToDelete));
30+
31+
expect(result.current.filters).toEqual({ search: '', tags: [ 'tag1', 'tag2' ] });
32+
});
33+
34+
it('should clear all filters', () => {
35+
const { result } = renderHook(() => useDataViewFilters({ initialFilters }));
36+
act(() => result.current.clearAllFilters());
37+
38+
expect(result.current.filters).toEqual({ search: '', tags: [] });
39+
});
40+
41+
it('should sync with URL search params if isUrlSyncEnabled', () => {
42+
const searchParams = new URLSearchParams();
43+
const setSearchParams = jest.fn();
44+
const props: UseDataViewFiltersProps<typeof initialFilters> = {
45+
initialFilters,
46+
searchParams,
47+
setSearchParams,
48+
};
49+
50+
const { result } = renderHook(() => useDataViewFilters(props));
51+
act(() => result.current.onSetFilters({ search: 'new search' }));
52+
53+
expect(setSearchParams).toHaveBeenCalled();
54+
});
55+
56+
it('should reset filters to default values when clearAllFilters is called', () => {
57+
const { result } = renderHook(() => useDataViewFilters({ initialFilters }));
58+
act(() => result.current.clearAllFilters());
59+
60+
expect(result.current.filters).toEqual({ search: '', tags: [] });
61+
});
62+
});

packages/module/src/Hooks/sort.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { useState, useCallback, useEffect, useMemo } from "react";
2+
3+
export interface UseDataViewSortProps<T extends object> {
4+
/** Initial sorting object */
5+
initialSort?: T;
6+
/** Current search parameters as a string */
7+
searchParams?: URLSearchParams;
8+
/** Function to set search parameters */
9+
setSearchParams?: (params: URLSearchParams) => void;
10+
};
11+
12+
export const useDataViewSort = <T extends object>({
13+
initialSort = {} as T,
14+
searchParams,
15+
setSearchParams,
16+
}: UseDataViewSortProps<T>) => {
17+
const isUrlSyncEnabled = useMemo(() => searchParams && !!setSearchParams, [ searchParams, setSearchParams ]);
18+
19+
const getInitialSort = useCallback((): T => isUrlSyncEnabled ? Object.keys(initialSort).reduce((loadedSort, key) => {
20+
const urlValue = searchParams?.get(key);
21+
loadedSort[key as keyof T] = urlValue
22+
? (urlValue as T[keyof T] | T[keyof T])
23+
: loadedSort[key as keyof T];
24+
return loadedSort;
25+
// eslint-disable-next-line react-hooks/exhaustive-deps
26+
}, { ...loadedSort }) : loadedSort, [ isUrlSyncEnabled, JSON.stringify(loadedSort), searchParams?.toString() ]);
27+
28+
const [ sortConfig, setSortConfig ] = useState<T>(getInitialSort());
29+
30+
const updateSearchParams = useCallback(
31+
(newFilters: T) => {
32+
if (isUrlSyncEnabled) {
33+
const params = new URLSearchParams(searchParams);
34+
Object.entries(newFilters).forEach(([ key, value ]) => {
35+
if (value) {
36+
params.set(key, Array.isArray(value) ? value.join(',') : value);
37+
} else {
38+
params.delete(key);
39+
}
40+
});
41+
setSearchParams?.(params);
42+
}
43+
},
44+
[ isUrlSyncEnabled, searchParams, setSearchParams ]
45+
);
46+
47+
useEffect(() => {
48+
isUrlSyncEnabled && setSortConfig(getInitialSort())
49+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
50+
51+
const onSetSort = useCallback(
52+
(newFilters: Partial<T>) => {
53+
setSortConfig(prevFilters => {
54+
const updatedFilters = { ...prevFilters, ...newFilters };
55+
isUrlSyncEnabled && updateSearchParams(updatedFilters);
56+
return updatedFilters;
57+
});
58+
},
59+
[ isUrlSyncEnabled, updateSearchParams ]
60+
);
61+
62+
// helper function to reset filters
63+
const resetSortValues = useCallback((filters: Partial<T>): Partial<T> => Object.entries(filters).reduce((acc, [ key, value ]) => {
64+
if (Array.isArray(value)) {
65+
acc[key as keyof T] = [] as T[keyof T];
66+
} else {
67+
acc[key as keyof T] = '' as T[keyof T];
68+
}
69+
return acc;
70+
}, {} as Partial<T>), []);
71+
72+
// const onDeleteFilters = useCallback(
73+
// (filtersToDelete: Partial<T>) => {
74+
// setSortConfig(prevFilters => {
75+
// const updatedFilters = { ...prevFilters,...resetFilterValues(filtersToDelete) };
76+
// isUrlSyncEnabled && updateSearchParams(updatedFilters);
77+
// return updatedFilters;
78+
// });
79+
// },
80+
// [ isUrlSyncEnabled, updateSearchParams, resetFilterValues ]
81+
// );
82+
83+
// const clearAllFilters = useCallback(() => {
84+
// const clearedFilters = resetFilterValues(filters) as T;
85+
86+
// setFilters(clearedFilters);
87+
// isUrlSyncEnabled && updateSearchParams(clearedFilters);
88+
// }, [ filters, isUrlSyncEnabled, updateSearchParams, resetFilterValues ]);
89+
90+
return {
91+
sortConfig,
92+
onSetSort
93+
};
94+
};

0 commit comments

Comments
 (0)