-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* workflow history filters * add missing files * fix lint * add filter helpers * fix lint warning * fix workflow history tests * update buttons sizes * fix filter icon size
- Loading branch information
1 parent
0666adb
commit a3d6ac4
Showing
32 changed files
with
1,048 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { useMemo, useCallback } from 'react'; | ||
|
||
import usePageQueryParams from '@/hooks/use-page-query-params/use-page-query-params'; | ||
import { | ||
type PageQueryParams, | ||
type PageQueryParamKeys, | ||
type PageQueryParamValues, | ||
} from '@/hooks/use-page-query-params/use-page-query-params.types'; | ||
|
||
import { type PageFilterConfig } from '../page-filters.types'; | ||
|
||
export default function usePageFilters<P extends PageQueryParams>({ | ||
pageFiltersConfig, | ||
pageQueryParamsConfig, | ||
}: { | ||
pageFiltersConfig: Array<PageFilterConfig<P, any>>; | ||
pageQueryParamsConfig: P; | ||
}) { | ||
const [queryParams, setQueryParams] = usePageQueryParams( | ||
pageQueryParamsConfig, | ||
{ pageRerender: false } | ||
); | ||
|
||
const activeFiltersCount = useMemo(() => { | ||
const configsByKey = Object.fromEntries( | ||
pageQueryParamsConfig.map((c) => [c.key, c]) | ||
); | ||
return pageFiltersConfig.filter((pageFilter) => | ||
Object.keys(pageFilter.getValue(queryParams)).every( | ||
(queryParamKey: PageQueryParamKeys<P>) => | ||
queryParams[queryParamKey] && | ||
queryParams[queryParamKey] !== | ||
configsByKey[queryParamKey].defaultValue | ||
) | ||
).length; | ||
}, [pageFiltersConfig, pageQueryParamsConfig, queryParams]); | ||
|
||
const resetAllFilters = useCallback(() => { | ||
const emptyQueryParamsObject = pageQueryParamsConfig.reduce( | ||
(acc, config) => ({ | ||
...acc, | ||
[config.key]: undefined, | ||
}), | ||
{} | ||
) as PageQueryParamValues<P>; | ||
|
||
setQueryParams( | ||
pageFiltersConfig.reduce((acc, pageFilter) => { | ||
return { | ||
...acc, | ||
...pageFilter.getValue(emptyQueryParamsObject), | ||
}; | ||
}, {}) | ||
); | ||
}, [pageFiltersConfig, pageQueryParamsConfig, setQueryParams]); | ||
|
||
return { resetAllFilters, activeFiltersCount, queryParams, setQueryParams }; | ||
} |
113 changes: 113 additions & 0 deletions
113
src/components/page-filters/page-filters-fields/__tests__/page-filters-fields.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import React from 'react'; | ||
|
||
import { render, screen, act, fireEvent } from '@/test-utils/rtl'; | ||
|
||
import { type PageQueryParamValues } from '@/hooks/use-page-query-params/use-page-query-params.types'; | ||
|
||
import { | ||
type mockPageQueryParamConfig, | ||
mockQueryParamsValues, | ||
} from '../../__fixtures__/page-filters.fixtures'; | ||
import { | ||
type PageFilterComponentProps, | ||
type PageFilterConfig, | ||
} from '../../page-filters.types'; | ||
import PageFiltersFields from '../page-filters-fields'; | ||
|
||
const MockFilterA = ({ | ||
value, | ||
setValue, | ||
}: PageFilterComponentProps<{ paramA: string }>) => { | ||
return ( | ||
<div> | ||
<div>Value 1: {value.paramA}</div> | ||
<div | ||
data-testid="change-filters" | ||
onClick={() => setValue({ paramA: 'valueA2' })} | ||
/> | ||
</div> | ||
); | ||
}; | ||
|
||
const MockFilterB = ({ | ||
value, | ||
setValue, | ||
}: PageFilterComponentProps<{ paramB: string }>) => { | ||
return ( | ||
<div> | ||
<div>Value 2: {value.paramB}</div> | ||
<div | ||
data-testid="change-filters" | ||
onClick={() => setValue({ paramB: 'valueB2' })} | ||
/> | ||
</div> | ||
); | ||
}; | ||
|
||
export const mockFiltersConfig: [ | ||
PageFilterConfig<typeof mockPageQueryParamConfig, { paramA: string }>, | ||
PageFilterConfig<typeof mockPageQueryParamConfig, { paramB: string }>, | ||
] = [ | ||
{ | ||
id: 'filterA', | ||
getValue: (v) => ({ paramA: v.paramA }), | ||
formatValue: (v) => v, | ||
component: MockFilterA, | ||
}, | ||
{ | ||
id: 'filterB', | ||
getValue: (v) => ({ paramB: v.paramB }), | ||
formatValue: (v) => v, | ||
component: MockFilterB, | ||
}, | ||
]; | ||
|
||
describe('PageFiltersFields', () => { | ||
it('should reset filters when clear filters button is pressed', async () => { | ||
const { mockedResetAllFilters } = setup({ | ||
valuesOverrides: { paramA: 'valueA2', paramB: 'valueB2' }, | ||
}); | ||
|
||
const clearFiltersButton = await screen.findByText('Clear filters'); | ||
|
||
act(() => { | ||
fireEvent.click(clearFiltersButton); | ||
}); | ||
|
||
expect(mockedResetAllFilters).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should call setQueryParams when filter setValue is called', async () => { | ||
const { mockedSetQueryParams } = setup({}); | ||
|
||
const filtersButtons = await screen.findAllByTestId('change-filters'); | ||
expect(filtersButtons).toHaveLength(2); | ||
|
||
act(() => { | ||
fireEvent.click(filtersButtons[0]); | ||
}); | ||
|
||
expect(mockedSetQueryParams).toHaveBeenCalledWith({ paramA: 'valueA2' }); | ||
}); | ||
}); | ||
|
||
function setup({ | ||
valuesOverrides, | ||
}: { | ||
valuesOverrides?: Partial< | ||
PageQueryParamValues<typeof mockPageQueryParamConfig> | ||
>; | ||
}) { | ||
const mockedResetAllFilters = jest.fn(); | ||
const mockedSetQueryParams = jest.fn(); | ||
|
||
render( | ||
<PageFiltersFields | ||
pageFiltersConfig={mockFiltersConfig} | ||
resetAllFilters={mockedResetAllFilters} | ||
setQueryParams={mockedSetQueryParams} | ||
queryParams={{ ...mockQueryParamsValues, ...valuesOverrides }} | ||
/> | ||
); | ||
return { mockedResetAllFilters, mockedSetQueryParams }; | ||
} |
40 changes: 40 additions & 0 deletions
40
src/components/page-filters/page-filters-fields/page-filters-fields.styles.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { styled as createStyled, type Theme } from 'baseui'; | ||
import type { ButtonOverrides } from 'baseui/button'; | ||
import { type StyleObject } from 'styletron-react'; | ||
|
||
export const styled = { | ||
SearchFiltersContainer: createStyled( | ||
'div', | ||
({ $theme }: { $theme: Theme }) => ({ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
flexWrap: 'wrap', | ||
gap: $theme.sizing.scale500, | ||
marginBottom: $theme.sizing.scale700, | ||
[$theme.mediaQuery.medium]: { | ||
flexDirection: 'row', | ||
}, | ||
}) | ||
), | ||
SearchFilterContainer: createStyled('div', { | ||
flexGrow: 2, | ||
flexBasis: 0, | ||
}), | ||
}; | ||
|
||
export const overrides = { | ||
clearFiltersButton: { | ||
Root: { | ||
style: ({ $theme }: { $theme: Theme }): StyleObject => ({ | ||
whiteSpace: 'nowrap', | ||
flexGrow: 2, | ||
height: $theme.sizing.scale950, | ||
[$theme.mediaQuery.medium]: { | ||
flexGrow: 0, | ||
alignSelf: 'flex-end', | ||
marginTop: $theme.sizing.scale700, | ||
}, | ||
}), | ||
}, | ||
} satisfies ButtonOverrides, | ||
}; |
Oops, something went wrong.