import { useCallback , useEffect , useRef } from 'react' ; import get from 'lodash/get' ; import isEqual from 'lodash/isEqual' ; import { indexById , removeEmpty , useSafeSetState } from '../util' ; import { FilterPayload , Identifier , Record , RecordMap , SortPayload , } from '../types' ; import usePaginationState from './usePaginationState' ; import useSortState from './useSortState' ; import useSelectionState from './useSelectionState' ; import { ListControllerProps } from '.' ; example param { UseListOptions } props param { Record [ ] } props . data param { Identifier [ ] } props . ids param { Boolean } props . loaded param { Boolean } props . loading param { Error | String } props . error param { Object } props . filter param { Number } props . page param { Number } props . perPage param { SortPayload } props . sort export const useList = ( props ) : UseListValue => { const { data , error , filter = defaultFilter , ids , loaded , loading , page : initialPage = 1 , perPage : initialPerPage = 1000 , sort : initialSort = defaultSort , } = props ; const [ finalItems , setFinalItems ] = useSafeSetState < { data : RecordMap ; ids : Identifier [ ] ; total : number ; } > ( ( ) => ( { data : Array . isArray ( data ) ? indexById ( data ) : { } , ids : Array . isArray ( ids ) ? ids : [ ] , total : Array . isArray ( ids ) ? ids . length : 0 , } ) ) ; const { page , setPage , perPage , setPerPage } = usePaginationState ( { page : initialPage , perPage : initialPerPage , } ) ; const { sort , setSort : setSortObject } = useSortState ( initialSort ) ; const setSort = useCallback ( ( field , order = 'ASC' ) => { setSortObject ( { field , order } ) ; setPage ( 1 ) ; } , [ setPage , setSortObject ] ) ; const { selectedIds , onSelect , onToggleItem , onUnselectItems , } = useSelectionState ( ) ; const filterRef = useRef ( filter ) ; const [ displayedFilters , setDisplayedFilters ] = useSafeSetState < { [ key ] : boolean ; } > ( { } ) ; const [ filterValues , setFilterValues ] = useSafeSetState < { [ key ] : any ; } > ( filter ) ; const hideFilter = useCallback ( ( filterName ) => { setDisplayedFilters ( previousState => { const { [ filterName ] : _ , ... newState } = previousState ; return newState ; } ) ; setFilterValues ( previousState => { const { [ filterName ] : _ , ... newState } = previousState ; return newState ; } ) ; } , [ setDisplayedFilters , setFilterValues ] ) ; const showFilter = useCallback ( ( filterName , defaultValue ) => { setDisplayedFilters ( previousState => ( { ... previousState , [ filterName ] : true , } ) ) ; setFilterValues ( previousState => removeEmpty ( { ... previousState , [ filterName ] : defaultValue , } ) ) ; } , [ setDisplayedFilters , setFilterValues ] ) ; const setFilters = useCallback ( ( filters , displayedFilters ) => { setFilterValues ( removeEmpty ( filters ) ) ; if ( displayedFilters ) { setDisplayedFilters ( displayedFilters ) ; } setPage ( 1 ) ; } , [ setDisplayedFilters , setFilterValues , setPage ] ) ; useEffect ( ( ) => { if ( ! isEqual ( filter , filterRef . current ) ) { filterRef . current = filter ; setFilterValues ( filter ) ; } } ) ; useEffect ( ( ) => { if ( ! loaded ) return ; let tempData = data . filter ( record => Object . entries ( filterValues ) . every ( ( [ filterName , filterValue ] ) => { const recordValue = get ( record , filterName ) ; const result = Array . isArray ( recordValue ) ? Array . isArray ( filterValue ) ? recordValue . some ( item => filterValue . includes ( item ) ) : recordValue . includes ( filterValue ) : Array . isArray ( filterValue ) ? filterValue . includes ( recordValue ) : filterValue == recordValue ; return result ; } ) ) ; const filteredLength = tempData . length ; if ( sort . field ) { tempData = tempData . sort ( ( a , b ) => { if ( get ( a , sort . field ) > get ( b , sort . field ) ) { return sort . order === 'ASC' ? 1 : - 1 ; } if ( get ( a , sort . field ) < get ( b , sort . field ) ) { return sort . order === 'ASC' ? - 1 : 1 ; } return 0 ; } ) ; } tempData = tempData . slice ( ( page - 1 ) * perPage , page * perPage ) ; const finalData = indexById ( tempData ) ; const finalIds = tempData . filter ( data => typeof data !== 'undefined' ) . map ( data => data . id ) ; setFinalItems ( { data : finalData , ids : finalIds , total : filteredLength , } ) ; } , [ data , filterValues , loaded , page , perPage , setFinalItems , sort . field , sort . order , ] ) ; return { currentSort : sort , data : finalItems . data , error , displayedFilters , filterValues , hideFilter , ids : finalItems . ids , loaded , loading , onSelect , onToggleItem , onUnselectItems , page , perPage , selectedIds , setFilters , setPage , setPerPage , setSort , showFilter , total : finalItems . total , } ; } ; export interface UseListOptions < RecordType extends Record = Record > { data ? : RecordType [ ] ; ids ? : Identifier [ ] ; error ? : any ; filter ? : FilterPayload ; loading : boolean ; loaded : boolean ; page ? : number ; perPage ? : number ; sort ? : SortPayload ; } export type UseListValue = Omit < ListControllerProps , 'resource' | 'basePath' | 'refetch' > ; const defaultFilter = { } ; const defaultSort = { field : null , order : null } ;