import { useContext , useMemo } from 'react' ; import { Dispatch } from 'redux' ; import { useDispatch , useSelector , useStore } from 'react-redux' ; import DataProviderContext from './DataProviderContext' ; import defaultDataProvider from './defaultDataProvider' ; import { ReduxState , DataProvider , DataProviderProxy } from '../types' ; import useLogoutIfAccessDenied from '../auth/useLogoutIfAccessDenied' ; import { getDataProviderCallArguments } from './getDataProviderCallArguments' ; import { doQuery , stackCall , stackOptimisticCall , getRemainingStackedCalls , } from './performQuery' ; return example example example const useDataProvider = < TDataProvider extends DataProvider = DataProvider , TDataProviderProxy extends DataProviderProxy < TDataProvider > = DataProviderProxy < TDataProvider > > ( ) : TDataProviderProxy => { const dispatch = useDispatch ( ) as Dispatch ; const dataProvider = ( ( useContext ( DataProviderContext ) || defaultDataProvider ) as unknown ) as TDataProvider ; const isOptimistic = useSelector ( ( state ) => state . admin . ui . optimistic ) ; const store = useStore < ReduxState > ( ) ; const logoutIfAccessDenied = useLogoutIfAccessDenied ( ) ; const dataProviderProxy = useMemo ( ( ) => { return new Proxy ( dataProvider , { get : ( target , name ) => { if ( typeof name === 'symbol' || name === 'then' ) { return ; } return ( ... args ) => { const { resource , payload , allArguments , options , } = getDataProviderCallArguments ( args ) ; const type = name . toString ( ) ; const { action = 'CUSTOM_FETCH' , undoable = false , onSuccess = undefined , onFailure = undefined , mutationMode = undoable ? 'undoable' : 'pessimistic' , enabled = true , ... rest } = options || { } ; if ( typeof dataProvider [ type ] !== 'function' ) { throw new Error ( `Unknown dataProvider function: ${ type }` ) ; } if ( onSuccess && typeof onSuccess !== 'function' ) { throw new Error ( 'The onSuccess option must be a function' ) ; } if ( onFailure && typeof onFailure !== 'function' ) { throw new Error ( 'The onFailure option must be a function' ) ; } if ( mutationMode === 'undoable' && ! onSuccess ) { throw new Error ( 'You must pass an onSuccess callback calling notify() to use the undoable mode' ) ; } if ( typeof enabled !== 'boolean' ) { throw new Error ( 'The enabled option must be a boolean' ) ; } if ( enabled === false ) { return Promise . resolve ( { } ) ; } const params = { resource , type , payload , action , onFailure , onSuccess , rest , mutationMode , dataProvider , store , dispatch , logoutIfAccessDenied , allArguments , } ; if ( isOptimistic ) { if ( mutationMode === 'undoable' || mutationMode === 'optimistic' ) { stackOptimisticCall ( params ) ; } else { stackCall ( params ) ; } return waitFor ( ( ) => getRemainingStackedCalls ( ) === 0 ) ; } else { return doQuery ( params ) ; } } ; } , } ) ; } , [ dataProvider , dispatch , isOptimistic , logoutIfAccessDenied , store ] ) ; return ( dataProviderProxy as unknown ) as TDataProviderProxy ; } ; const later = ( delay = 100 ) : Promise < void > => new Promise ( function ( resolve ) { setTimeout ( resolve , delay ) ; } ) ; const waitFor = ( condition ) : Promise < void > => new Promise ( resolve => condition ( ) ? resolve ( ) : later ( ) . then ( ( ) => waitFor ( condition ) . then ( ( ) => resolve ( ) ) ) ) ; export default useDataProvider ;