UNPKG

redux-devshare

Version:

[![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] [![Code Climate][climate-image]][climate-url] [![Code Coverage][coverage-i

417 lines (368 loc) 14.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.customToJS = exports.populatedDataToJS = exports.buildChildList = exports.orderedToJS = exports.dataToJS = exports.pathToJS = exports.toJS = exports.fixPath = exports.isEmpty = exports.isLoaded = undefined; var _defaultsDeep2 = require('lodash/defaultsDeep'); var _defaultsDeep3 = _interopRequireDefault(_defaultsDeep2); var _isString2 = require('lodash/isString'); var _isString3 = _interopRequireDefault(_isString2); var _reduce2 = require('lodash/reduce'); var _reduce3 = _interopRequireDefault(_reduce2); var _mapValues2 = require('lodash/mapValues'); var _mapValues3 = _interopRequireDefault(_mapValues2); var _drop2 = require('lodash/drop'); var _drop3 = _interopRequireDefault(_drop2); var _first2 = require('lodash/first'); var _first3 = _interopRequireDefault(_first2); var _some2 = require('lodash/some'); var _some3 = _interopRequireDefault(_some2); var _map2 = require('lodash/map'); var _map3 = _interopRequireDefault(_map2); var _size2 = require('lodash/size'); var _size3 = _interopRequireDefault(_size2); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _populate = require('./utils/populate'); var _constants = require('./constants'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /** * @description Detect whether items are loaded yet or not * @param {Object} item - Item to check loaded status of. A comma seperated list is also acceptable. * @return {Boolean} Whether or not item is loaded * @example * import React, { Component, PropTypes } from 'react' * import { connect } from 'react-redux' * import { firebaseConnect, isLoaded, dataToJS } from 'react-redux-firebase' * * @firebaseConnect(['/todos']) * @connect( * ({ firebase }) => ({ * todos: dataToJS(firebase, '/todos'), * }) * ) * class Todos extends Component { * static propTypes = { * todos: PropTypes.object * } * * render() { * const { todos } = this.props; * * // Show loading while todos are loading * if(!isLoaded(todos)) { * return <span>Loading...</span> * } * * return <ul>{todosList}</ul> * } * } */ var isLoaded = exports.isLoaded = function isLoaded() { if (!arguments || !arguments.length) { return true; } return (0, _map3.default)(arguments, function (a) { return a !== undefined; }).reduce(function (a, b) { return a && b; }); }; /** * @description Detect whether items are empty or not * @param {Object} item - Item to check loaded status of. A comma seperated list is also acceptable. * @return {Boolean} Whether or not item is empty * @example * import React, { Component, PropTypes } from 'react' * import { connect } from 'react-redux' * import { firebaseConnect, isEmpty, dataToJS } from 'react-redux-firebase' * * @firebaseConnect(['/todos']) * @connect( * ({ firebase }) => ({ * todos: dataToJS(firebase, '/todos'), * }) * ) * class Todos extends Component { * static propTypes = { * todos: PropTypes.object * } * * render() { * const { todos } = this.props; * * // Message for if todos are empty * if(isEmpty(todos)) { * return <span>No Todos Found</span> * } * * return <ul>{todosList}</ul> * } * } */ var isEmpty = exports.isEmpty = function isEmpty(data) { return !(data && (0, _size3.default)(data)); }; /** * @description Fix path by adding "/" to path if needed * @param {String} path - Path string to fix * @return {String} - Fixed path * @private */ var fixPath = exports.fixPath = function fixPath(path) { return (path.substring(0, 1) === '/' ? '' : '/') + path; }; /** * @description Convert Immutable Map to a Javascript object * @param {Object} data - Immutable Map to be converted to JS object (state.firebase) * @return {Object} data - Javascript version of Immutable Map * @return {Object} Data located at path within Immutable Map */ var toJS = exports.toJS = function toJS(data) { return data && data.toJS ? data.toJS() : data; }; /** * @description Convert parameter from Immutable Map to a Javascript object * @param {Map} firebase - Immutable Map to be converted to JS object (state.firebase) * @param {String} path - Path from state.firebase to convert to JS object * @param {Object|String|Boolean} notSetValue - Value to use if data is not available * @return {Object} Data located at path within Immutable Map * @example <caption>Basic</caption> * import { connect } from 'react-redux' * import { firebaseConnect, pathToJS } from 'react-redux-firebase' * * @firebaseConnect() * @connect(({ firebase }) => ({ * profile: pathToJS(firebase, 'profile'), * auth: pathToJS(firebase, 'auth') * }) * export default class MyComponent extends Component { * ... */ var pathToJS = exports.pathToJS = function pathToJS(data, path, notSetValue) { if (!data) { return notSetValue; } var pathArr = fixPath(path).split(/\//).slice(1); if (data.getIn) { // Handle meta params (stored by string key) if ((0, _some3.default)(_constants.metaParams, function (v) { return pathArr.indexOf(v) !== -1; })) { return toJS(data.getIn([(0, _first3.default)(pathArr), (0, _drop3.default)(pathArr).join(_constants.paramSplitChar)], notSetValue)); } return toJS(data.getIn(pathArr, notSetValue)); } return data; }; /** * @description Convert parameter under "data" path of Immutable Map to a Javascript object. * **NOTE:** Setting a default value will cause `isLoaded` to always return true * @param {Map} firebase - Immutable Map to be converted to JS object (state.firebase) * @param {String} path - Path of parameter to load * @param {Object|String|Boolean} notSetValue - Value to return if value is not * found in redux. This will cause `isLoaded` to always return true (since * value is set from the start). * @return {Object} Data located at path within Immutable Map * @example <caption>Basic</caption> * import { connect } from 'react-redux' * import { firebaseConnect, dataToJS } from 'react-redux-firebase' * * @firebaseConnect(['/todos']) * @connect(({ firebase }) => ({ * // this.props.todos loaded from state.firebase.data.todos * todos: dataToJS(firebase, 'todos') * }) * @example <caption>Default Value</caption> * import { connect } from 'react-redux' * import { firebaseConnect, dataToJS } from 'react-redux-firebase' * const defaultValue = { * 1: { * text: 'Example Todo' * } * } * @firebaseConnect(['/todos']) * @connect(({ firebase }) => ({ * // this.props.todos loaded from state.firebase.data.todos * todos: dataToJS(firebase, 'todos', defaultValue) * }) */ var dataToJS = exports.dataToJS = function dataToJS(data, path, notSetValue) { if (!data) { return notSetValue; } var pathArr = ('/data' + fixPath(path)).split(/\//).slice(1); if (data.getIn) { return toJS(data.getIn(pathArr, notSetValue)); } return data; }; /** * @description Convert parameter under "ordered" path of Immutable Map to a * Javascript array. This preserves order set by query. * @param {Map} firebase - Immutable Map to be converted to JS object (state.firebase) * @param {String} path - Path of parameter to load * @param {Object|String|Boolean} notSetValue - Value to return if value is not found * @return {Object} Data located at path within Immutable Map * @example <caption>Basic</caption> * import { connect } from 'react-redux' * import { firebaseConnect, orderedToJS } from 'react-redux-firebase' * * @firebaseConnect([ * { * path: 'todos', * queryParams: ['orderByChild=text'] // order alphabetically based on text * }, * ]) * @connect(({ firebase }) => ({ * // this.props.todos loaded from state.firebase.ordered.todos * todos: orderedToJS(firebase, 'todos') * }) */ var orderedToJS = exports.orderedToJS = function orderedToJS(data, path, notSetValue) { if (!data) { return notSetValue; } var pathArr = ('/ordered' + fixPath(path)).split(/\//).slice(1); if (data.getIn) { return toJS(data.getIn(pathArr, notSetValue)); } return data; }; /** * @private * @description Build child list based on populate * @param {Map} data - Immutable Map to be converted to JS object (state.firebase) * @param {Object} list - Path of parameter to load * @param {Object} populate - Object with population settings */ var buildChildList = exports.buildChildList = function buildChildList(data, list, p) { return (0, _mapValues3.default)(list, function (val, key) { var getKey = val; // Handle key: true lists if (val === true) { getKey = key; } var pathString = p.childParam ? p.root + '/' + getKey + '/' + p.childParam : p.root + '/' + getKey; // Set to child under key if populate child exists if (dataToJS(data, pathString)) { return p.keyProp ? _extends(_defineProperty({}, p.keyProp, getKey), dataToJS(data, pathString)) : dataToJS(data, pathString); } // Populate child does not exist return val === true ? val : getKey; }); }; /** * @description Convert parameter under "data" path of Immutable Map to a * Javascript object with parameters populated based on populates array * @param {Map} firebase - Immutable Map to be converted to JS object (state.firebase) * @param {String} path - Path of parameter to load * @param {Array} populates - Array of populate objects * @param {Object|String|Boolean} notSetValue - Value to return if value is not found * @return {Object} Data located at path within Immutable Map * @example <caption>Basic</caption> * import { connect } from 'react-redux' * import { firebaseConnect, helpers } from 'react-redux-firebase' * const { dataToJS } = helpers * const populates = [{ child: 'owner', root: 'users' }] * * const fbWrapped = firebaseConnect([ * { path: '/todos', populates } // load "todos" and matching "users" to redux * ])(App) * * export default connect(({ firebase }) => ({ * // this.props.todos loaded from state.firebase.data.todos * // each todo has child 'owner' populated from matching uid in 'users' root * // for loading un-populated todos use dataToJS(firebase, 'todos') * todos: populatedDataToJS(firebase, 'todos', populates), * }))(fbWrapped) */ var populatedDataToJS = exports.populatedDataToJS = function populatedDataToJS(data, path, populates, notSetValue) { if (!data) { return notSetValue; } // Handle undefined child if (!dataToJS(data, path, notSetValue)) { return dataToJS(data, path, notSetValue); } var populateObjs = (0, _populate.getPopulateObjs)(populates); // reduce array of populates to object of combined populated data return (0, _reduce3.default)((0, _map3.default)(populateObjs, function (p, obj) { // single item with iterable child if (dataToJS(data, path)[p.child]) { // populate child is key if ((0, _isString3.default)(dataToJS(data, path)[p.child])) { var key = dataToJS(data, path)[p.child]; var pathString = p.childParam ? p.root + '/' + key + '/' + p.childParam : p.root + '/' + key; if (dataToJS(data, pathString)) { return _defineProperty({}, p.child, p.keyProp ? _extends(_defineProperty({}, p.keyProp, key), dataToJS(data, pathString)) : dataToJS(data, pathString)); } // matching child does not exist return dataToJS(data, path); } return _defineProperty({}, p.child, buildChildList(data, dataToJS(data, path)[p.child], p)); } // list with child param in each item return (0, _mapValues3.default)(dataToJS(data, path), function (child, i) { // no matching child parameter if (!child || !child[p.child]) { return child; } // populate child is key if ((0, _isString3.default)(child[p.child])) { var _key = child[p.child]; var _pathString = p.childParam ? p.root + '/' + _key + '/' + p.childParam : p.root + '/' + _key; if (dataToJS(data, _pathString)) { return _defineProperty({}, p.child, p.keyProp ? _extends(_defineProperty({}, p.keyProp, _key), dataToJS(data, _pathString)) : dataToJS(data, _pathString)); } // matching child does not exist return child; } // populate child list return _defineProperty({}, p.child, buildChildList(data, child[p.child], p)); }); }), function (obj, v) { // combine data from all populates to one object var combined = (0, _defaultsDeep3.default)(obj, v); return (0, _defaultsDeep3.default)(combined, dataToJS(data, path)); }); }; /** * @description Load custom object from within store * @param {Map} firebase - Immutable Map to be converted to JS object (state.firebase) * @param {String} path - Path of parameter to load * @param {String} customPath - Part of store from which to load * @param {Object|String|Boolean} notSetValue - Value to return if value is not found * @return {Object} Data located at path within state * @example <caption>Basic</caption> * import { connect } from 'react-redux' * import { firebaseConnect, helpers } from 'react-redux-firebase' * const { customToJS } = helpers * * const fbWrapped = firebaseConnect(['/todos'])(App) * * export default connect(({ firebase }) => ({ * // this.props.todos loaded from state.firebase.data.todos * requesting: customToJS(firebase, 'todos', 'requesting') * }))(fbWrapped) */ var customToJS = exports.customToJS = function customToJS(data, path, custom, notSetValue) { if (!data) { return notSetValue; } var pathArr = ('/' + custom + fixPath(path)).split(/\//).slice(1); if (data.getIn) { return toJS(data.getIn(pathArr, notSetValue)); } return data; }; exports.default = { toJS: toJS, pathToJS: pathToJS, dataToJS: dataToJS, orderedToJS: orderedToJS, populatedDataToJS: populatedDataToJS, customToJS: customToJS, isLoaded: isLoaded, isEmpty: isEmpty };