Last active
December 2, 2017 11:14
-
-
Save iamdanthedev/36c94276cbfa6247f111fbc0fcc68f37 to your computer and use it in GitHub Desktop.
Apollo data loading or error HOC
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
import * as React from 'react'; | |
import { Loading } from '@common/components/Loading/Loading'; | |
import { ErrorMessage } from '@common/components/ErrorMessage/ErrorMessage'; | |
import { IconSizeProp } from 'semantic-ui-react/src/elements/Icon/Icon'; | |
type Options<T = any> = { | |
loaderSize?: IconSizeProp, | |
errorExtraCheck?: (props: T) => string | null | undefined, | |
loadingExtraCheck?: (props: T) => boolean, | |
skipLoading?: boolean, // if we want to handle loading state in a wrapped component | |
skipError?: boolean, // same for error | |
}; | |
/** | |
* Check if apollo data is loading or has errored and shows appropriate | |
* component or the base component otherwise | |
*/ | |
export function dataLoadingOrError<T extends {}>(); | |
export function dataLoadingOrError<T extends {}>(prop: string | ((props: T) => string)); | |
export function dataLoadingOrError<T extends {}>(options: Options<T>); | |
export function dataLoadingOrError<T extends {}>(prop: string | ((props: T) => string), options: Options<T>); | |
export function dataLoadingOrError<T extends {}>() { | |
const arg0 = arguments[0]; // tslint:disable-line | |
const arg1 = arguments[1]; // tslint:disable-line | |
return function(BaseComponent) { | |
return function(props) { | |
// args | |
let dataPropName: string = 'data'; | |
let options: Options = {}; | |
if (typeof arg0 === 'string') { | |
dataPropName = arg0; | |
} | |
else if (typeof arg0 === 'function') { | |
dataPropName = arg0(props); | |
} | |
else if (typeof arg0 === 'object') { | |
options = Object.assign({}, arg0); | |
} | |
if (typeof arg1 === 'object') { | |
options = Object.assign({}, arg1); | |
} | |
if (!!!dataPropName) { | |
throw new Error('cannot get data prop name'); | |
} | |
// validate | |
const data = props[dataPropName]; | |
if (!data) { | |
console.warn(`data prop "${dataPropName}" not found in props`); | |
return <BaseComponent {...props} />; | |
} | |
// error checks | |
let error = false; | |
let errorMessage = ''; | |
if (data.error) { | |
error = true; | |
errorMessage = data.error.message; | |
} | |
else if (options.errorExtraCheck) { | |
const extraError = options.errorExtraCheck(props); | |
if (!!extraError) { | |
error = true; | |
errorMessage = extraError; | |
} | |
} | |
// loading checks | |
let loading = false; | |
if (data.loading) { | |
loading = true; | |
} | |
else if (options.loadingExtraCheck && options.loadingExtraCheck(props)) { | |
loading = true; | |
} | |
// render | |
if (loading && !options.skipLoading) { | |
return <Loading size={options.loaderSize} />; | |
} | |
else if (error && !options.skipError) { | |
return <ErrorMessage message={errorMessage} />; | |
} | |
else { | |
return <BaseComponent {...props} />; | |
} | |
}; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment