UNPKG

@applicaster/zapp-react-native-utils

Version:

Applicaster Zapp React Native utilities package

508 lines (351 loc) • 17.5 kB
# @applicaster/zapp-react-native-utils [![CircleCI](https://github.com/applicaster/QuickBrick/tree/main.svg?style=shield&circle-token=07da67c776e760b087a4cc707712cd9a9c04d1af)](https://github.com/applicaster/QuickBrick/tree/main) ![npm version](https://badge.fury.io/js/%40applicaster%2Fzapp-react-native-utils.svg) ![logo](../../logo.png) This package contains js utilities for the Quick Brick App ## Contributing - Follow the steps in the [main README](../../README.md) to set up the Zapp-React-Native repo, and run the app. - add your folder or file - import it with ```javascript import { utility } from "@applicaster/zapp-react-native-utils/utility"; ``` ## API ### reactUtils `@applicaster/zapp-react-native-utils/reactUtils` #### attachLifeCycleMethods = (lifecycleMethods: { [name]: method }) => (Component<ReactComponent>) => <ReactComponent> adds lifecycle methods to any React component (stateless or class). The appropriate method will be used depending on the type of the component. If the component is stateless, it will wrap it in a class before it adds the method to the Component's prototype. Supports all React lifecycle methods except `constructor` and `static getDerivedStateFromProps` ```javascript import { attachLifeCycleMethods } from "@applicaster/zapp-react-native-utils/reactUtils"; const MyComponent = (props) => ( <View> <Text>I'm component</Text> </View> ); const lifeCycleDecorator = attachLifeCycleMethods({ componentDidMount() { console.log("I'm mounted"); }, componentWillUpdate(nextProps, nextState) { console.log("component will change", nextProps, nextState); }, }); export const ComponentWithLifeCycleMethods = lifeCycleDecorator(MyComponent); ``` ### stringUtils `@applicaster/zapp-react-native/stringUtils` - `capitalize: (input: string) => string`: sets the first letter of the input string as uppercase - `toPascalCase: (input: string) => string`: transforms a `snake_case` input string to `PascalCase` `@applicaster/zapp-react-native/objectUtils` All following functions are curried and can be either called by `f(a, b)` or `f(a)(b)`. They work like all curried Ramda functions - `filterObj: (predicate: any => boolean) => (object: any) => object: any` uses the predicate function to filter an object values. - `mapKeys: (mapper: string => string) => (object: any) => (object: any)` maps over an object's keys and applies the mapper function to these keys. Curried function ### stylesUtils `@applicaster/zapp-react-native/stylesUtils` - `fixColorHexCode: string => string`: transforms a `AARRGGBB` hex code into a `RRGGBBAA` hex code - this is required because React Native uses `RRGGBBAA` colors, but Zapp Api provides `AARRGGBB` ### pluginUtils `@applicaster/zapp-react-native/pluginUtils` - `findPluginByIdentifier: (identifier: string, plugins: {[string]: Plugin}) => Plugin`: find a plugin for a given identifier,in the provided map of available plugins. Returns the entire plugin. - `findPluginByType: (type: string, plugins: {[string]: Plugin}) => Plugin`: find a plugin for a given type, in the provided map of available plugins. Returns the callable plugin module. - `getNavigationPlugin: (type: string, plugins: {[string]: Plugin}, defaultComponents: ?{[string]: Plugin}`: resolves the navigation plugin to use for a given type, from a provided map of available plugins. If provided, will fallback to one of the defaultComponent. ### navigationUtils `@applicaster/zapp-react-native/navigationUtils` - `getNavigationType: (category: "nav_bar" | "menu", navigations: [Navigations]) => string`: retrieves the type of navigation for a given category (either nav_bar or menu), from the navigation data in the layout.json - `getPathAttributes: (pathname: string) => [{ screenType: string, screenId: string }]`: transforms a given route into a map of attributes for that specific route. `/foo/bar/baz/qux` becomes : ```javascript [ { screenType: "foo", screenId: "bar" }, { screenType: "baz", screenId: "qux" }, ]; ``` - `getItemType: (item: any, layoutVersion: 'v1' | 'v2' ) => string`: gets the type of a given item in a feed. - `getItemTargetId: (item: any) => string`: gets the target screen id for a given item in a feed. ### reactHooks `@applicaster/zapp-react-native/reactHooks` **navigation hooks** `@applicaster/zapp-react-native/reactHooks/navigation` `useNavigation: (void) => NavigationContext` - Hook returns navigation context (See navigation documentation at quick-brick-core) ```javascript const navigation = useNavigation(); ``` `useBackHandler: (callback: () => any) => void` - Adds hardware back button listener to your component. ```javascript useBackHandler(() => { console.log("HArdware back button clicked"); }); ``` **layout hooks** `@applicaster/zapp-react-native/reactHooks/layout` - `useDimensions: (context : 'screen'|'window' = 'window', {fullDimensions: bool = false, round: bool = false, excludeStatusBar: bool = false }) => { width: number, height: number, scale: number, fontScale, number } | { width: number, height: number }` - Hook will be called on initial component mount, will measure the Dimensions and return the result. One every screen or window size change the hook will update it's dimensions. ```javascript const dimensions = useDimensions("window", { fullDimensions: true }); ``` - `usePrevious: (value : any) => any` - Hook will return previous value that was passed to it. Usefull if you want to replicated behavior of `componentDidUpdate(prevState)` **Device hooks** `@applicaster/zapp-react-native/reactHooks/device` - `useIsTablet: () =>boolean` - Checks if device is a tablet ```javascript const isTablet = useIsTablet(); ``` - `useOrientation: () => 'landscape' | 'portrait'` - Checks device orientation ```javascript const orientation = useOrientation(); ``` **utility hooks** `@applicaster/zapp-react-native/reactHooks/utils` ```javascript const previousVideo = usePrevious(video); useEffect(() => { if (previousVideo === video) { // do something } }); ``` **app hooks** `@applicaster/zapp-react-native/reactHooks/app` - `useAppState: (returnIsActive?: boolean) => boolean | AppStateStatus` - Hook returns current appState, or if parameter set to true, boolean value for appState === "active" ```javascript const appState = useAppState(); const isActive = useAppState(true); ``` **screen hooks** `@applicaster/zapp-react-native/reactHooks/screen` - `useCurrentScreenData: () => ZappRiver` - Hook returns river data for the current path ```javascript const river = useCurrentScreenData(); ``` `@applicaster/zapp-react-native/reactHooks/screen` - `useScreenData: (screenId) => ZappRiver` - Hook returns river data for the passed screen id ```javascript const river = useScreenData("screen-id"); ``` **flatList hooks** `@applicaster/zapp-react-native/reactHooks/flatList` - `useSequentialRenderItem: (data : array) => {renderItem: (_renderItem, renderArgs) => Component, allLoaded: boolean}` - Hook used for adding sequential loading functionality for mapper functions like map or flatList renderItem. renderItem - wrapper for renderItem function, inflating it with extra function `onLoadFinished` that needs to be called when component is ready to be displayed. renderItem wraps the resolution of the `_renderItem`, in View with the display style set to "none" or "flex"; allLoaded - returns true when `onLoadFinished` was called for all items. FlatList ```javascript const data = [{ id: 1 }]; const { allLoaded, renderItem } = useSequentialRenderItem(data); const _renderItem = ({ item, index, onLoadFinished }) => { onLoadFinished(); return <Component />; }; return <FlatList data={data} renderItem={renderItem(_renderItem)} />; ``` Map ```javascript const data = [{ id: 1 }]; const { allLoaded, renderItem } = useSequentialRenderItem(data); const _renderItem = ({ item, index, onLoadFinished }) => { onLoadFinished(); return <Component />; }; return data.map((item, index) => renderItem(_renderItem, { item, index })); ``` **connection hooks** `@applicaster/zapp-react-native/reactHooks/connection` - `useConnectionInfo: (justOnlineStatus : boolean) => boolean | connectionInfo(NetInfo RN Module )` - Hook will return NetInfo state or boolean for isConnected. Updated on every change in network connection type ```javascript const connectionType = useConnectionInfo(); // connectionType = { type: 'wifi', effectiveType: 'unknown' } ``` ```javascript const connectionType = useConnectionInfo(true); // connectionType = true ``` **feed hooks** `@applicaster/zapp-react-native/reactHooks` - `useFeedRefresh: ({ reloadData: function, component: { id: boolean | string, rules: {enable_data_refreshing: boolean, refreshing_interval: number} } }) => void` - Hook will call `reloadData` function, in the specified intervals if `enable_data_refreshing` is set to true; ```javascript useFeedRefresh({ reloadData, component }); ``` - `useFeedLoader: ({ feedUrl: string, pipesOptions?: { clearCache?: boolean, loadLocalFavourites?: boolean, silentRefresh?: boolean} }) => ({data: ?ApplicasterFeed, loading: boolean, url: string, error: Error,reloadData: (silentRefresh?: boolean) => void, loadNext: () => void})` - Hook will load data to the redux store and return a feed for the provided DSP URL. If the data for the provided url was already loaded, it will return that value ```javascript const { data, loading, url, reloadData, loadNext } = useFeedLoader({ feedUrl: "applicaster://fetchData?type=url&url=applicaster.com", }); reloadData(); // Reloads data using feedUrl provided to useFeedLoader loadNext(); // Loads next data, using `next` key from the feed returned by feedUrl request ``` **resolver hooks** - `useComponentResolver` hook used to resolve a selected component from the list of plugins and apply decorators on it (optional). Call signature ```typescript type Decorator = (comp: React.Component<any>) => React.Component<any>; type Props = { componentType: string; decorators?: Decorator | Array<Decorator>; }; type Watchers = Array<any>; useComponentResolver({ componentType, decorators }, watchers); ``` - **componentType**: plugin identifier of your component - **decorators**(_optional_): decorator/list of decorators used to decorate your component - **watchers**(_optional_): list of dependencies to be passed to useMemo hook that wraps componentResolver internally. Useful when component resolution is dependant on external variables. For example, one of the decorators uses external variable that is likely to change. Example: ```javascript const viewWrapperDecorator = (Component) => (props) => <View>{props.children}</View>; const Container = (props) => { const Component = useComponentResolver( { componentType: "horizontal_list_qb", decorators: viewWrapperDecorator, }, [props.reCreateComponentOnThisPropChange] ); return <Component />; }; ``` &nbsp; - `useCellResolver` Creates cell component, based on passed configuration. Warning: resolution of this hook is memoized outside of RN lifecycle so once cell component is created it will won't be re-calculated, unless `component.id` changes. Call signature: ```typescript type ZappComponent = { id: string; styles: { cell_plugin_configuration_id: string; }; }; useCellResolver({ component: ZappComponent }); ``` - **component**: Zapp component object Example: ```javascript const component = { id: "123", styles: { cell_plugin_configuration_id: "ahs733-fnk3f-fsnb21-fbsk235", }, }; const Cell = useCellResolver({ component }); ``` &nbsp; ### appUtils - orientationHelper `@applicaster/zapp-react-native/appUtils/orientationHelper` ```javascript const ORIENTATIONS = { portrait: 1, landscapeRight: 2, landscapeLeft: 4, landscapeSensor: 6, allButUpsideDown: 7, portraitUpsideDown: 8, all: 15, }; ``` `allowedOrientationsForScreen: (ORIENTATIONS) => void` - Sets allowed orientations for the current screen `addOrientationChangeListener: (callback: ({toOrientation: ORIENTATIONS, fromOrientation: ORIENTATIONS)) => listenerInstance` - Adds orientation change listener that will call the callback on every allowed orientation change (set with allowedOrientationsForScreen). `removeOrientationChangeListener: (listenerInstance) => void` - Removes passed listener Example of how to use orientation handler inside React useEffect hook: ```javascript useEffect(() => { allowedOrientationsForScreen(ORIENTATIONS.allButUpsideDown); const listener = addOrientationChangeListener( ({ toOrientation, fromOrientation }) => { // Do something } ); return () => { removeOrientationChangeListener(listener); }; }, []); ``` ### testUtils `@applicaster/zapp-react-native-utils/testUtils` - `testIDEquals: (testId: any) => boolean | { width: number, height: number }` - Function to be used in tandem with enzyme findWhere ```javascript wrapper.findWhere(testIDEquals("text")); ``` ### appUtils - contextKeysManager `@applicaster/zapp-react-native-utils/appUtils/contextKeyManager` **- getKey()** fetch value by key from storages(session, local or secure). In case failed to fetch returns null. Key can be: - object => { key: 'some_key', namespace: 'namespace'} - string with namespace => "some_namespace.some_key" - string without namespace => "some_key" in this case we use default namespace="applicaster.v2" Example: ```typescript import { ContextKeysManager } from "@applicaster/zapp-react-native-utils/appUtils/contextKeyManager"; const key = { key: "some_key", namespace: "namespace" }; const value = await ContextKeysManager.instance.getKey(key); ``` **- getKeys()** fetch values by keys from storages(session, local or secure). It return structure Map with key=>value. If failed get some value it returns null for it. Example: ```typescript import { ContextKeysManager } from "@applicaster/zapp-react-native-utils/appUtils/contextKeyManager"; const keys = ["key1", "key2", "key3"]; const values: Map<KeyName, ValueOrNothing> = await ContextKeysManager.instance.getKeys(keys); // Map([[key1, value1], [key2, null], [key3, value3]]) ``` **- setKey()** save value by key to one specific storage(session, local or secure). For success save returns <true>. For failed returns <false>. Input: object of that shape => { key, value, storageLevel } - key: string | { key: 'some_key', namespace: 'namespace' }, - value: string | number | boolean | Array<any> | Object;, - storageLevel?: StorageLevel.default | StorageLevel.persisted | StorageLevel.secure When storageLevel is omitted we use StorageLevel.default. Example: ```typescript import { ContextKeysManager, StorageLevel, } from "@applicaster/zapp-react-native-utils/appUtils/contextKeyManager"; const key = { key: "some_key", namespace: "namespace" }; const value = "value"; const storageLevel = StorageLevel.persisted; const resultOfSave: boolean = await ContextKeysManager.instance.setKey( key, value, storageLevel ); ``` **- setKeys()** Save array of values by keys to one specific storage(session, local or secure). For each key can be chosen specific storage. It return structure Map with key => result_of_saving. Result of saving can be <true> in success saving, otherwise <false>. Inputs - array of objects such shape as { key, value, storageLevel } - key: string | { key: 'some_key', namespace: 'namespace' }, - value: string | number | boolean | Array<any> | Object;, - storageLevel?: StorageLevel.default | StorageLevel.persisted | StorageLevel.secure When storageLevel is omitted we use StorageLevel.default. Example: ```typescript import { ContextKeysManager } from "@applicaster/zapp-react-native-utils/appUtils/contextKeyManager"; const key = { key: "some_key", namespace: "namespace" }; const value = "value"; const storageLevel = StorageLevel.persisted; const keys = [{ key, value, storageLevel }]; const resultsOfSave: Map<KeyName, boolean> = await ContextKeysManager.instance.setKeys(keys); // Map([[key1, true], [key2, false], [key3, true]]) ``` **- removeKey()** drop value by key in all storages(session, local and secure). If removing was succeed -> return <true>, otherwise <false>. Key can be: - object => { key: 'some_key', namespace: 'namespace'} - string with namespace => "some_namespace.some_key" - string without namespace => "some_key" in this case we use default namespace="applicaster.v2" Example: ```typescript import { ContextKeysManager } from "@applicaster/zapp-react-native-utils/appUtils/contextKeyManager"; const key = { key: "some_key", namespace: "namespace" }; const resultOfRemoving: boolean = await ContextKeysManager.instance.removeKey( key ); ``` **- removeKeys()** drop values by keys in all storages(session, local and secure). It return structure Map with key => result_of_removing. Result of removing can be <true> in success removing, otherwise <false>. Key can be: - object => { key: 'some_key', namespace: 'namespace'} - string with namespace => "some_namespace.some_key" - string without namespace => "some_key" in this case we use default namespace="applicaster.v2" Example: ```typescript import { ContextKeysManager } from "@applicaster/zapp-react-native-utils/appUtils/contextKeyManager"; const key = { key: "some_key", namespace: "namespace" }; const keys = [key]; const resultsOfRemoving: Map<KeyName, boolean> = await ContextKeysManager.instance.removeKeys(keys); // Map([[key1, true], [key2, false], [key3, true]]) ```