diff --git a/README.md b/README.md index f3e74e6..4685ad2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Firekit +# fireform [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] [![License][license-image]][license-url] @@ -7,400 +7,15 @@ This project was bootstrapped with [nwb](https://github.com/insin/nwb) -Firekit was created to help working with Firebase in React Projects that use Redux as state storage. - -You can find a full functional **DEMO** project (React Most Wanted) with source code [here](https://www.react-most-wanted.com/). -You can also find more about the concepts used in this library [here](https://codeburst.io/firekit-concepts-to-sync-firebase-and-redux-606a1e3e50d6) - ## Table of Contents -- [Features](#features) -- [Configuration](#configuration) -- [Usage](#usage) - - [Accessing firebaseApp](#accessing-firebaseapp) - - [Connection](#connection) - - [Lists and Queries](#lists-and-queires) - - [Paths](#paths) - - [FireForm](#fireform) - - [Messaging](#messaging) +- [FireForm](#fireform) - [TO DO](#to-do) - [License](#license) -## Features - -Firekit allows you to watch firebase data and sync it to your redux store with a minimum of code to write. It uses a `Provider` to server the `firebaseApp` to all Components that need it. - -Some features that are unique to this firebase toolkit are: -* **persistant watchers** - the watchers are persistant and are not linked to components. You deside when to watch a value in your firebase database and when to unwatch (turn off listeners) it. - -* **your create firebaseApp** - you initialise the firebaseApp how you want and add it as prop to the firekit `FirebaseProvider` and all your components have access to the firebaseApp - -* **easy persistance** - firekit saves in your store only simple json data so that persistance is no nightmare any more! - -* **normalised redux store** - the firekit reducers are structured with normalisation in mind - -* **native firebase** - you can use firebases native sdk for the web. Firekit is just listening on changes. Every change on the data you can make as it is described in the official firebase documentation - -* **realtime forms** - firekit has a special Warapper for `redux-forms` witch allows to sync them with the realtime database very simple and plus it is automaticaly synced on field changes in real time if they ocure while your are in the Form - -Features like populating values in the database are omited with purpose. The [Firebase Cloud Functions](https://firebase.google.com/docs/functions/) are the place where you should populate data that must be saved in multiple places. - - -## Configuration - -We will use code snipets from the demo project to explan how to configure firekit. There are two main steps for the configuration: -* prepare the `FirebaseProvider` -* add the firekit reducers to your redux reducer - -To initialize the `FirebaseReducer` we need to initialize our firebase app as it is described in the official firebase documentation. -When we have the `firebaseApp` we just add it as paramater to our Provider. - -```js -import React from 'react'; -import ReactDOM from 'react-dom'; -import { Provider } from 'react-redux'; -import { FirebaseProvider } from 'firekit'; // Import the FirebaseProvider from firekit -import configureStore from './store'; -import { Root } from './containers/Root'; -import { addLocalizationData } from './locales'; -import injectTapEventPlugin from 'react-tap-event-plugin'; -import registerServiceWorker from './registerServiceWorker'; -import firebase from 'firebase'; - -const store = configureStore(); -addLocalizationData(); - -//Get the configs of your firerbase project -const firebaseConf={ - apiKey: "AIzaSyBQAmNJ2DbRyw8PqdmNWlePYtMP0hUcjpY", - authDomain: "react-most-wanted-3b1b2.firebaseapp.com", - databaseURL: "https://react-most-wanted-3b1b2.firebaseio.com", - projectId: "react-most-wanted-3b1b2", - storageBucket: "react-most-wanted-3b1b2.appspot.com", - messagingSenderId: "258373383650" -} - -//Initialise your firebase app -const firebaseApp = firebase.initializeApp(firebaseConf); - -//The part above can be done in a seperate file so it can be acessed from everiwhere in your application -//It is moved here in this snipped for simplicity purpose - -//Now in your root part of your application add the FirebaseProvider as you have done with the redux Provoder -//Take care that the FirebaseProvider comes after the redux Provider to have access to the redux store -ReactDOM.render( - - - - - - , document.getElementById('root') -); - -registerServiceWorker(); - -``` - -Take care that adding the `FirebaseProvider` happens in a root part of your application and after the redux Provider. -Taht would be the first part. In the second one we just add the firekit reducers to our redux reduxer. - -```js -import { responsiveStateReducer } from 'redux-responsive'; -import { combineReducers } from 'redux'; -import { responsiveDrawer } from 'material-ui-responsive-drawer'; -import { reducer as formReducer } from 'redux-form' -import auth from './auth/reducer'; -import dialogs from './dialogs/reducer'; -import messaging from './messaging/reducer'; -import locale from './locale/reducer'; -import theme from './theme/reducer'; -import firekitReducers from 'firekit'; //Import the firekitReducers - - -console.log(firekitReducers); - -const reducers = combineReducers({ - browser: responsiveStateReducer, - responsiveDrawer, - form: formReducer, - auth, - dialogs, - messaging, - locale, - theme, - ...firekitReducers //Spread the firekit reducers -}) - -export default reducers; - -``` -To add all firekit reducers to your redux store just spread the firekitReducers object into your `comineReducers` object. - -**WARNING:** if you are using persistance take care that the reducer `initialization` is not persisted! He saves the watchers. If he would be persisted the watcher would not initialize again after a page reload. If you are using `redux-persist` just add him to the black list. - -```js - persistStore(store, {blacklist:['auth', 'form', 'connection', 'initialization'] }, ()=>{}); //Add initialization to persistance blacklist if you use persistance -``` - -**INFO:** the reducers are not customasable. In future we could add customatisation for this so they could have any name you want. - -## Usage - -Let us now do something with our firekit :smile: -To use `firekit` in a component we need to tell the component to get all `firekit` props from the context. -We use for that a simple call `withFirebase`. It is very similar to the `react-router` call `withRouter`. The usage is exactly the same. - -Let us take a look on a simple component. - -```js - -import React, { Component } from 'react'; -import {injectIntl, intlShape} from 'react-intl'; -import { Activity } from '../../containers/Activity'; -import { withFirebase } from 'firekit'; - -class MyComponent extends Component { - - componentDidMount(){ - const { watchList }= this.props; - watchList('companies'); //Here we started watching a list - - } - - render() { - const { intl }= this.props; - - return ( - - - ); - } - -} - -MyComponent.propTypes = { - intl: intlShape.isRequired, -}; - - -export default injectIntl(withFirebase(MyComponent)); //Here using 'withFirebase()' we added all we need to our component - -``` -As you can see calling `withFirebase(Component)` adds to our Component all props we need to work with firekit. `watchList` is one of more API calls we can make. More about every one is writen below in the [API](#api) section. - -Now that we know how to add the `firekit` props to our Compont lets take a look what we can do with it. - -### Accessing firebaseApp - -The `FirebaseProvider` provides the `firebaseApp` trought the rect context and `withFirebase` allows us to get it easely as Component property. We can then do with the `firebaseApp` whatever we want: create, update, delete data in the realtime databae, work with the auth or with the storage. You have all your freedom with firebase cause `firebaseApp` is the same one you initialised and put into the `FirebaseProvider`. - - -```js - -import React, { Component } from 'react'; -import {injectIntl, intlShape} from 'react-intl'; -import { Activity } from '../../containers/Activity'; -import { withFirebase } from 'firekit'; - -class MyComponent extends Component { - - componentDidMount(){ - const { firebaseApp }= this.props; - firebaseApp.database().ref('some_value').update(55); //Here we just changed a value in our database - } - - render() { - const { intl }= this.props; - - return ( - - - ); - } - -} - -MyComponent.propTypes = { - intl: intlShape.isRequired, -}; - - -export default injectIntl(withFirebase(MyComponent)); //Here using 'withFirebase()' we added all we need to our component - -``` - -### Connection - -Firebase has integrated a listener to observe the connection state to your firebase app. - - -```js -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { withFirebase } from 'firekit'; - -class MyComponent extends Component { - - componentDidMount(){ - const { initConnection }= this.props; - initConnection(); //Here we started watching the connection state - } - - componentWillUnmount() { - const { unsubscribeConnection, }= this.props; - unsubscribeConnection(); // Here we unsunscribe the listening to the connection state - } - - render() { - const { isConnected }= this.props; - - return ( -
Connection state:{isConnected}
- ); - } - -} - -const mapStateToProps = (state) => { - const { connection} = state; - - return { - isConnected: connection?connection.isConnected:false, // Here we get the connection state from the redux store - }; -}; - -export default connect( - mapStateToProps -)(withFirebase(MyComponent)); -``` - -### Lists and Queries - -We can easely observe lists in the realtime database using the `watchList` and `unwatchList` API calls. The same calls are used to observe Firebase queries. `watchList` and `unwatchList` can recieve as parameter a string to a database path or a Firebase reference to that path. If you have a simple reference to a path using just the string of the path is the right choice. But if you have a Firebase query reference you can send that reference with all its query calls as parameter. - -**IMPORTAND:**: the list will be a Array contained of objects witch have the props `key` and `val` where the `key` is the child key in the list and `val` the value of the child. This is similar to the snapshot you get from a Firebase list `on` event. - -```js -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { withFirebase } from 'firekit'; -import _ from 'lodash'; - -class MyComponent extends Component { - - componentDidMount(){ - const { watchList, firebaseApp }= this.props; - - watchList('users'); //Here we started watching the users list - - //Here we watch a simple firebase query - let tasksRef= firebaseApp.database().ref('tasks').limitToFirst(10); - watchList(tasksRef); - - //Here we watch a list and save the data on a specific location in our redux store - watchList('public_tasks', 'tasks'); - - } - - componentWillUnmount() { - const { unwatchList, }= this.props; - unwatchList('users'); // We can unwatch the list on unmounting the Component - unwatchList('tasks'); // To unwatch a query qe can use just the ref path string - unwatchList('public_tasks'); // To unwatch a watcher that is stored in a specific location we call the unwatchList with the path - } - - rednerList = () => { - const {users} =this.props; - - if(users===undefined){ - return
- } - - return _.map(users, (user, i) => { - return
- {user.val.displayName} -
- }); - } - - render() { - const { isConnected }= this.props; - - return ( -
- {this.rednerList()} -
- ); - } - -} - -const mapStateToProps = (state) => { - const { lists } = state; - return { - users: lists.users, - tasks: lists.tasks, //the data from 'public_tasks' path - }; -}; - -export default connect( - mapStateToProps -)(withFirebase(MyComponent)); -``` - -Here we unwatched the list on `componentWillUnmount`. We could also leave this away and the list will change in realtime in the background and it will not load all data on revisiting the Component again. - -If you are using persistand watcher you would have to unwatch them in some point of your application or on application exit. -Because of that there are special calls that allow us to unwatch all persistand watcher in a single call. That could be calles in the root component of your application like this: - -```js - -//... other code of your root Component - - componentWillUnmount() { - const { unsubscribeConnection, unwatchAllLists, unwatchAllPaths }= this.props; - unsubscribeConnection(); - unwatchAllLists(); - unwatchAllPaths(); - } - -//... other code of your root Component - -``` - -**INFO:** You can call the `watchList` and `watchPath` as often you want. The library caches initialized lists and paths to the `initialization` state so it knows if you are trying to initialize a list or path that is already initialized and is already observed and in that case the library just doesn't do anything. So if you call `watchList('users')` in multiple places in your application you don't have to care about if it is already initialized or not and can be shure that if it is you just have your data in the redux store ready to use. - -As you noticed we here unwatch not only the lists but also the connection and the paths watcher. - -### Paths - -The paths watcher exactly like the lists watcher with `watchPath` and `unwatchPath`. - -```js -//... - componentDidMount(){ - const { watchPath }= this.props; - watchPath('users_count'); //Here we started watching the path - } - - componentWillUnmount() { - const { unwatchPath, destroyPath }= this.props; - unwatchPath('users'); // We can unwatch the path on unmounting the Component - destroyPath('users'); // We can destory the path. This will remove the path data from redux. - - //INFO: calling destroy will automaticaly unwatch the path or list - } - -//... -``` - -Here we also unwatch the path on `componentWillUnmount` but we could also leave the watcher persistand and unwatch it on application closing. This is useful if you need to load user data or user permissions from the database and you want that the permission changes take effect in realtime to the user. - ### FireForm -`FirForm` is a special component created for usage with `redux-form`. It takes a `path` and an `uid` paramater to know where to get its data. The `name` propertie is the name of the `redux-form` Form name. All other properties are optional and wil be described in further documentation. It is importand to know that `FireForm` can only be used in Components that have the `withFirebase` called to access the `firebaseApp`. +`FireForm` is a special component created for usage with `redux-form`. It takes a `path` and an `uid` paramater to know where to get its data. The `name` propertie is the name of the `redux-form` Form name. All other properties are optional and wil be described in further documentation. It is importand to know that `FireForm` can only be used in Components that have the `withFirebase` called to access the `firebaseApp`. Inside the `FireForm` we put as child our Form with the fields we want and the macig hapens :smile: @@ -413,6 +28,7 @@ And comes the cool thing. If you are in the Form working on fields and someone e //... {history.push('/companies');}} @@ -426,42 +42,23 @@ And comes the cool thing. If you are in the Form working on fields and someone e ``` -### Messaging - -Firebase offers a simple API for managing push notification messages. Firekit provides a simple API call `initMessaging` that manages all messaging events for you and syncs them to your redux store. The API call can recieve a function paramater you can use to hanlde new messages. That parameter is optional. Firekit stores the messaging token, permission and new messages to your store automaticaly. In future there will be added APIs to clear single and all messages. - -```js -//... - componentDidMount(){ - const { initMessaging }= this.props; - initMessaging((payload)=>{console.log(payload)}); //Here we initialise the Firbease messaging and log new messages to the console - } - -//... -``` ## TO DO -- [X] compine all reducer to one import -- [X] integrate firebase messaging -- [X] integrate firebase auth watcher -- [X] integrate firebase queries watcher -- [X] implement alias names (custom destination locations) for path and list watchers -- [ ] integrate selectors for lists -- [ ] integrate error hanling -- [ ] integrate loading indicators in redux state +- [X] integrate realtime fnctionality + ## License MIT @TarikHuber -[travis-image]: https://travis-ci.org/TarikHuber/firekit.svg?branch=master -[travis-url]: https://travis-ci.org/TarikHuber/firekit -[daviddm-image]: https://img.shields.io/david/TarikHuber/firekit.svg?style=flat-square -[daviddm-url]: https://david-dm.org/TarikHuber/firekit -[coverage-image]: https://img.shields.io/codecov/c/github/TarikHuber/firekit.svg?style=flat-square -[coverage-url]: https://codecov.io/gh/TarikHuber/firekit +[travis-image]: https://travis-ci.org/TarikHuber/fireform.svg?branch=master +[travis-url]: https://travis-ci.org/TarikHuber/fireform +[daviddm-image]: https://img.shields.io/david/TarikHuber/fireform.svg?style=flat-square +[daviddm-url]: https://david-dm.org/TarikHuber/fireform +[coverage-image]: https://img.shields.io/codecov/c/github/TarikHuber/fireform.svg?style=flat-square +[coverage-url]: https://codecov.io/gh/TarikHuber/fireform [license-image]: https://img.shields.io/npm/l/express.svg -[license-url]: https://github.com/TarikHuber/firekit/master/LICENSE +[license-url]: https://github.com/TarikHuber/fireform/master/LICENSE [code-style-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square [code-style-url]: http://standardjs.com/ diff --git a/demo/src/components/Drawer/DrawerContent.js b/demo/src/components/Drawer/DrawerContent.js index 10bf58b..05d01fe 100644 --- a/demo/src/components/Drawer/DrawerContent.js +++ b/demo/src/components/Drawer/DrawerContent.js @@ -8,7 +8,7 @@ import allLocales from '../../locales'; import firebase from 'firebase'; import { injectIntl } from 'react-intl'; import { withRouter } from 'react-router-dom'; -import { withFirebase } from '../../../../src'; +import { withFirebase } from 'firekit' const DrawerContent = (props, context) => { diff --git a/demo/src/components/Drawer/DrawerHeader.js b/demo/src/components/Drawer/DrawerHeader.js index 855bf88..28605b2 100644 --- a/demo/src/components/Drawer/DrawerHeader.js +++ b/demo/src/components/Drawer/DrawerHeader.js @@ -9,7 +9,7 @@ import {RMWIcon} from '../Icons'; import {injectIntl} from 'react-intl'; import muiThemeable from 'material-ui/styles/muiThemeable'; import CircularProgress from 'material-ui/CircularProgress'; -import { withFirebase } from '../../../../src'; +import { withFirebase } from 'firekit' const DrawerHeader = ({muiTheme, intl, auth, setAuthMenuOpen, fetchUser, dialogs, setDialogIsOpen, firebaseApp}) => { const styles={ diff --git a/demo/src/containers/About/About.js b/demo/src/containers/About/About.js index 5443afd..1c4a60b 100644 --- a/demo/src/containers/About/About.js +++ b/demo/src/containers/About/About.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import {injectIntl, intlShape} from 'react-intl'; import { Activity } from '../../containers/Activity'; -import { withFirebase } from '../../../../src'; +import { withFirebase } from 'firekit' class About extends Component { diff --git a/demo/src/containers/Companies/Companie.js b/demo/src/containers/Companies/Companie.js index 36f197a..0f618b1 100644 --- a/demo/src/containers/Companies/Companie.js +++ b/demo/src/containers/Companies/Companie.js @@ -9,7 +9,8 @@ import firebase from 'firebase'; import FontIcon from 'material-ui/FontIcon'; import FlatButton from 'material-ui/FlatButton'; import Dialog from 'material-ui/Dialog'; -import { withFirebase, FireForm } from '../../../../src'; +import { withFirebase } from 'firekit'; +import FireForm from '../../../../src'; const path='/companies/'; @@ -56,7 +57,7 @@ class Companie extends Component { render() { - const {history, intl, setDialogIsOpen, dialogs, match}=this.props; + const {history, intl, setDialogIsOpen, dialogs, match, firebaseApp}=this.props; const actions = [ {history.push('/companies');}} diff --git a/demo/src/containers/Companies/Companies.js b/demo/src/containers/Companies/Companies.js index 7ff203a..5028b90 100644 --- a/demo/src/containers/Companies/Companies.js +++ b/demo/src/containers/Companies/Companies.js @@ -11,7 +11,7 @@ import FontIcon from 'material-ui/FontIcon'; import FloatingActionButton from 'material-ui/FloatingActionButton'; import {withRouter} from 'react-router-dom'; import Avatar from 'material-ui/Avatar'; -import { withFirebase } from '../../../../src'; +import { withFirebase } from 'firekit' class Vehicles extends Component { diff --git a/demo/src/containers/MyAccount/Form.js b/demo/src/containers/MyAccount/Form.js index 612f636..2ee257e 100644 --- a/demo/src/containers/MyAccount/Form.js +++ b/demo/src/containers/MyAccount/Form.js @@ -11,7 +11,7 @@ import { setDialogIsOpen } from '../../store/dialogs/actions'; import { ImageCropDialog } from '../../containers/ImageCropDialog'; import IconButton from 'material-ui/IconButton'; import { withRouter } from 'react-router-dom'; -import { withFirebase } from '../../../../src'; +import { withFirebase } from 'firekit' import {GoogleIcon, FacebookIcon, GitHubIcon, TwitterIcon} from '../../components/Icons'; import muiThemeable from 'material-ui/styles/muiThemeable'; import config from '../../config'; diff --git a/demo/src/containers/MyAccount/MyAccount.js b/demo/src/containers/MyAccount/MyAccount.js index dc45965..e10e687 100644 --- a/demo/src/containers/MyAccount/MyAccount.js +++ b/demo/src/containers/MyAccount/MyAccount.js @@ -10,7 +10,8 @@ import FlatButton from 'material-ui/FlatButton'; import Dialog from 'material-ui/Dialog'; import firebase from 'firebase'; import {formValueSelector } from 'redux-form'; -import { withFirebase, FireForm } from '../../../../src'; +import { withFirebase } from 'firekit'; +import FireForm from '../../../../src'; const path='/users/'; diff --git a/demo/src/containers/Root/Root.js b/demo/src/containers/Root/Root.js index cfb0c7f..d459277 100644 --- a/demo/src/containers/Root/Root.js +++ b/demo/src/containers/Root/Root.js @@ -8,7 +8,7 @@ import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; import { IntlProvider } from 'react-intl' import { Routes } from '../../components/Routes'; import firebase from 'firebase'; -import { withFirebase } from '../../../../src'; +import { withFirebase } from 'firekit' class Root extends Component { diff --git a/demo/src/containers/SignIn/SignIn.js b/demo/src/containers/SignIn/SignIn.js index b7d1e2a..b1df043 100644 --- a/demo/src/containers/SignIn/SignIn.js +++ b/demo/src/containers/SignIn/SignIn.js @@ -8,7 +8,7 @@ import firebaseui from 'firebaseui'; import {firebaseAuth} from '../../firebase'; import config from '../../config'; import { withRouter } from 'react-router-dom'; -import { withFirebase } from '../../../../src'; +import { withFirebase } from 'firekit' var authUi = new firebaseui.auth.AuthUI(firebaseAuth); diff --git a/demo/src/containers/Tasks/Task.js b/demo/src/containers/Tasks/Task.js index 2027bcb..b524f94 100644 --- a/demo/src/containers/Tasks/Task.js +++ b/demo/src/containers/Tasks/Task.js @@ -10,7 +10,8 @@ import firebase from 'firebase'; import FontIcon from 'material-ui/FontIcon'; import FlatButton from 'material-ui/FlatButton'; import Dialog from 'material-ui/Dialog'; -import { withFirebase, FireForm } from '../../../../src'; +import { withFirebase } from 'firekit'; +import FireForm from '../../../../src'; const path='/public_tasks/'; diff --git a/demo/src/containers/Tasks/Tasks.js b/demo/src/containers/Tasks/Tasks.js index 88f3646..ac1660f 100644 --- a/demo/src/containers/Tasks/Tasks.js +++ b/demo/src/containers/Tasks/Tasks.js @@ -19,7 +19,7 @@ import {BottomNavigation} from 'material-ui/BottomNavigation'; import {withRouter} from 'react-router-dom'; import FlatButton from 'material-ui/FlatButton'; import Dialog from 'material-ui/Dialog'; -import { withFirebase } from '../../../../src'; +import { withFirebase } from 'firekit' class Tasks extends Component { diff --git a/demo/src/containers/Users/Users.js b/demo/src/containers/Users/Users.js index d3330c5..00c1520 100644 --- a/demo/src/containers/Users/Users.js +++ b/demo/src/containers/Users/Users.js @@ -10,7 +10,7 @@ import Avatar from 'material-ui/Avatar'; import FontIcon from 'material-ui/FontIcon'; import {GoogleIcon, FacebookIcon, GitHubIcon, TwitterIcon} from '../../components/Icons'; import IconButton from 'material-ui/IconButton'; -import { withFirebase } from '../../../../src'; +import { withFirebase } from 'firekit' import ReactList from 'react-list'; class Users extends Component { diff --git a/demo/src/index.js b/demo/src/index.js index f41a7ff..d548186 100644 --- a/demo/src/index.js +++ b/demo/src/index.js @@ -1,7 +1,7 @@ import React, {Component} from 'react' import {render} from 'react-dom' import { Provider } from 'react-redux'; -import { FirebaseProvider } from '../../src'; +import { FirebaseProvider } from 'firekit'; import configureStore from './store'; import { Root } from './containers/Root'; import { addLocalizationData } from './locales'; diff --git a/demo/src/store/reducers.js b/demo/src/store/reducers.js index a623ab3..5666960 100644 --- a/demo/src/store/reducers.js +++ b/demo/src/store/reducers.js @@ -5,7 +5,7 @@ import { reducer as formReducer } from 'redux-form' import dialogs from './dialogs/reducer'; import locale from './locale/reducer'; import theme from './theme/reducer'; -import firekitReducers from '../../../src'; +import firekitReducers from 'firekit'; const reducers = combineReducers({ browser: responsiveStateReducer, diff --git a/package-lock.json b/package-lock.json index bf21fc7..2cb2fad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { - "name": "firekit", - "version": "0.1.31", + "name": "firefrom", + "version": "0.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4016,6 +4016,12 @@ "firebase": "4.4.0" } }, + "firekit": { + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/firekit/-/firekit-0.1.31.tgz", + "integrity": "sha512-QhDL3BdSyuQpdGZp91LWAOJVhhxLzCvTQoGJrKhHl5GZ32/UM8JU9Ejcc0GFk/425y7CfCOtXeLDq6z5V7TDTg==", + "dev": true + }, "flatten": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", diff --git a/package.json b/package.json index 8c59172..6b1a28a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "firekit", - "version": "0.1.31", + "name": "firefrom", + "version": "0.2.0", "description": "Firebase toolkit for sync with redux", "main": "lib/index.js", "module": "es/index.js", @@ -28,6 +28,7 @@ "devDependencies": { "firebase": "^4.4.0", "firebaseui": "^2.3.0", + "firekit": "^0.1.31", "github-markdown-css": "^2.8.0", "immutable": "^3.8.1", "intl": "^1.2.5", @@ -63,9 +64,10 @@ "author": "Tarik Huber", "homepage": "https://www.react-most-wanted.com/", "license": "MIT", - "repository": "https://github.com/TarikHuber/firekit", + "repository": "https://github.com/TarikHuber/fireform", "keywords": [ "react-component", + "react-form", "firebase", "redux", "react" diff --git a/src/components/FireForm.js b/src/components/FireForm.js index f24558d..e50a567 100644 --- a/src/components/FireForm.js +++ b/src/components/FireForm.js @@ -1,7 +1,7 @@ import React, {Component} from 'react'; +import {connect} from 'react-redux'; import PropTypes from 'prop-types'; import { initialize } from 'redux-form'; -import withFirebase from '../withFirebase'; class FireForm extends Component { @@ -85,13 +85,13 @@ class FireForm extends Component { } componentWillMount(){ - const { path, uid, name, firebaseApp} = this.props; + const { path, uid, name, firebaseApp, initialize} = this.props; if(uid){ firebaseApp.database().ref(`${path}${uid}`).on('value', snapshot => { this.setState({initialized: true}, ()=>{ - this.props.dispatch(initialize(name, snapshot.val(), true)) + initialize(name, snapshot.val(), true) }) }) }else{ @@ -101,14 +101,14 @@ class FireForm extends Component { } componentWillReceiveProps = (nextProps) => { - const { uid, name, path, firebaseApp } = this.props; + const { uid, name, path, firebaseApp, initialize } = this.props; const { uid: nextUid } = nextProps; if(uid && uid!==nextUid){ firebaseApp.database().ref(`${path}${nextUid}`).on('value', snapshot => { this.setState({initialized: true}, ()=>{ - nextProps.dispatch(initialize(name, snapshot.val(), true)) + initialize(name, snapshot.val(), true) }) }) } @@ -133,6 +133,7 @@ class FireForm extends Component { FireForm.propTypes = { path: PropTypes.string.isRequired, name: PropTypes.string.isRequired, + firebaseApp: PropTypes.any.isRequired, uid: PropTypes.string, onSubmitSuccess: PropTypes.func, onDelete: PropTypes.func, @@ -141,4 +142,11 @@ FireForm.propTypes = { }; -export default withFirebase(FireForm); +const mapStateToProps = (state) => { + return { + }; +}; + +export default connect( + mapStateToProps, {initialize} +)(FireForm); diff --git a/src/components/FirebaseProvider.js b/src/components/FirebaseProvider.js deleted file mode 100644 index c9924ed..0000000 --- a/src/components/FirebaseProvider.js +++ /dev/null @@ -1,25 +0,0 @@ -import {Component} from 'react'; -import PropTypes from 'prop-types'; - -class FirebaseProvider extends Component { - - static propTypes = { - children: PropTypes.element, - }; - - static childContextTypes = { - firebaseApp: PropTypes.object.isRequired, - }; - - getChildContext() { - return { - firebaseApp: this.props.firebaseApp, - }; - } - - render() { - return this.props.children; - } -} - -export default FirebaseProvider; diff --git a/src/index.js b/src/index.js index b3c876e..18198a6 100644 --- a/src/index.js +++ b/src/index.js @@ -1,33 +1 @@ -import listsReducer from './store/lists/reducer' -import pathsReducer from './store/paths/reducer' -import authReducer from './store/auth/reducer' -import initializationReducer from './store/initialization/reducer' -import connectionReducer from './store/connection/reducer' -import messagingReducer from './store/messaging/reducer' - -const firekitReducers = { - lists: listsReducer, - paths: pathsReducer, - auth: authReducer, - connection: connectionReducer, - messaging: messagingReducer, - initialization: initializationReducer -} - -export { default as FirebaseProvider } from './components/FirebaseProvider' -export { default as FireForm } from './components/FireForm' -export { default as withFirebase } from './withFirebase' -export { default as authReducer } from './store/auth/reducer' -export { default as connectionReducer } from './store/connection/reducer' -export { default as messagingReducer } from './store/messaging/reducer' -export { default as listsReducer } from './store/lists/reducer' -export { default as pathsReducer } from './store/paths/reducer' -export { default as initializationReducer } from './store/initialization/reducer' -export { initMessaging, clearMessage } from './store/messaging/actions' -export { clearInitialization } from './store/initialization/actions' -export { initConnection, unsubscribeConnection } from './store/connection/actions' -export { watchAuth, authStateChanged, authError} from './store/auth/actions' -export { watchList, unwatchList, destroyList, unwatchAllLists } from './store/lists/actions' -export { watchPath, unwatchPath, destroyPath, unwatchAllPaths } from './store/paths/actions' - -export default firekitReducers +export default from './components/FireForm' diff --git a/src/store/auth/actions.js b/src/store/auth/actions.js deleted file mode 100644 index 8e75aef..0000000 --- a/src/store/auth/actions.js +++ /dev/null @@ -1,52 +0,0 @@ -import * as types from './types' - -export function authStateChanged (user) { - return { - type: types.AUTH_STATE_CHANGED, - payload: user - } -} - -export function authError (error) { - return { - type: types.AUTH_ERROR, - payload: error - } -} - -function defaultUserData (user) { - if (user != null) { - return { - displayName: user.displayName, - email: user.email, - photoURL: user.photoURL, - emailVerified: user.emailVerified, - isAnonymous: user.isAnonymous, - uid: user.uid, - providerData: user.providerData, - isAuthorised: true - } - } else { - return { - isAuthorised: false - } - } -} - -export function watchAuth (firebaseApp, onAuthStateChanged, onAuthError) { - return dispatch => { - firebaseApp.auth().onAuthStateChanged(user => { - if (onAuthStateChanged && onAuthStateChanged instanceof Function) { - dispatch(authStateChanged({isAuthorised: !!user, ...onAuthStateChanged(user)})) - } else { - dispatch(authStateChanged({isAuthorised: !!user, ...defaultUserData(user)})) - } - }, error => { - if (onAuthError && onAuthError instanceof Function) { - dispatch(authError(error)) - } else { - dispatch(authError(error)) - } - }) - } -} diff --git a/src/store/auth/reducer.js b/src/store/auth/reducer.js deleted file mode 100644 index 734e237..0000000 --- a/src/store/auth/reducer.js +++ /dev/null @@ -1,17 +0,0 @@ -import * as types from './types' - -export const initialState = { -} - -export default function auth (state = initialState, {payload, type}) { - switch (type) { - case types.AUTH_STATE_CHANGED: - return {...state, ...payload} - - case types.AUTH_ERROR: - return {...state, error: payload} - - default: - return state - } -} diff --git a/src/store/auth/reducer.spec.js b/src/store/auth/reducer.spec.js deleted file mode 100644 index 7ca7dd1..0000000 --- a/src/store/auth/reducer.spec.js +++ /dev/null @@ -1,32 +0,0 @@ -import expect from 'expect' -import reducer from './reducer' -import * as actions from './actions' - -const initialState = { -} - -describe('locale reducer', () => { - it('should return the initial state', () => { - expect( - reducer(undefined, {}) - ).toEqual(initialState) - }) - - it('should not affect state', () => { - expect( - reducer(initialState, {type: 'NOT_EXISTING'}) - ).toEqual(initialState) - }) - - it('should handle authStateChanged', () => { - expect( - reducer(initialState, actions.authStateChanged({displayName: 'test'})) - ).toEqual({...initialState, ...{displayName: 'test'}}) - }) - - it('should handle authError', () => { - expect( - reducer(initialState, actions.authError({message: 'test'})) - ).toEqual({...initialState, ...{error: {message: 'test'}}}) - }) -}) diff --git a/src/store/auth/types.js b/src/store/auth/types.js deleted file mode 100644 index aa0d633..0000000 --- a/src/store/auth/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export const AUTH_STATE_CHANGED = `@@firekit/AUTH@AUTH_STATE_CHANGED` -export const AUTH_ERROR = `@@firekit/AUTH@AUTH_ERROR` diff --git a/src/store/connection/actions.js b/src/store/connection/actions.js deleted file mode 100644 index 2ef7814..0000000 --- a/src/store/connection/actions.js +++ /dev/null @@ -1,23 +0,0 @@ -import * as types from './types' - -export function onConnectionStateChange (isConnected) { - return { - type: types.ON_CONNECTION_STATE_CHANGED, - payload: {isConnected} - } -} - -export function initConnection (firebaseApp) { - return dispatch => { - firebaseApp.database().ref('.info/connected').on('value', snapshot => { - dispatch(onConnectionStateChange(snapshot.val())) - }) - } -} - -export function unsubscribeConnection (firebaseApp) { - return dispatch => { - firebaseApp.database().ref('.info/connected').off() - onConnectionStateChange(false) - } -} diff --git a/src/store/connection/reducer.js b/src/store/connection/reducer.js deleted file mode 100644 index fffe233..0000000 --- a/src/store/connection/reducer.js +++ /dev/null @@ -1,15 +0,0 @@ -import * as types from './types' - -export const initialState = { - isConnected: true -} - -export default function connection (state = initialState, {payload, type}) { - switch (type) { - case types.ON_CONNECTION_STATE_CHANGED: - return {...state, ...payload} - - default: - return state - } -} diff --git a/src/store/connection/reducer.spec.js b/src/store/connection/reducer.spec.js deleted file mode 100644 index f91b55c..0000000 --- a/src/store/connection/reducer.spec.js +++ /dev/null @@ -1,27 +0,0 @@ -import expect from 'expect' -import reducer from './reducer' -import * as actions from './actions' - -const initialState = { - isConnected: true -} - -describe('connection reducer', () => { - it('should return the initial state', () => { - expect( - reducer(undefined, {}) - ).toEqual(initialState) - }) - - it('should not affect state', () => { - expect( - reducer(initialState, {type: 'NOT_EXISTING'}) - ).toEqual(initialState) - }) - - it('should handle onConnectionStateChange', () => { - expect( - reducer(initialState, actions.onConnectionStateChange(true)) - ).toEqual({...initialState, isConnected: true}) - }) -}) diff --git a/src/store/connection/selector.js b/src/store/connection/selector.js deleted file mode 100644 index 8787383..0000000 --- a/src/store/connection/selector.js +++ /dev/null @@ -1,3 +0,0 @@ -export const isConnected = (connection) => { - return connection ? connection.isConnected : false -} diff --git a/src/store/connection/types.js b/src/store/connection/types.js deleted file mode 100644 index 59120c1..0000000 --- a/src/store/connection/types.js +++ /dev/null @@ -1 +0,0 @@ -export const ON_CONNECTION_STATE_CHANGED = `@@firekit/CONNECTION@ON_CONNECTION_STATE_CHANGED` diff --git a/src/store/initialization/actions.js b/src/store/initialization/actions.js deleted file mode 100644 index 0653712..0000000 --- a/src/store/initialization/actions.js +++ /dev/null @@ -1,7 +0,0 @@ -import * as types from './types' - -export function clearInitialization () { - return { - type: types.CLEAR_INITIALIZATION - } -} diff --git a/src/store/initialization/reducer.js b/src/store/initialization/reducer.js deleted file mode 100644 index c56cd4f..0000000 --- a/src/store/initialization/reducer.js +++ /dev/null @@ -1,48 +0,0 @@ -import * as listsTypes from '../lists/types' -import * as pathsTypes from '../paths/types' -import * as types from './types' - - -function locations (state = [], action) { - const {path, location} = action - switch (action.type) { - case listsTypes.INIIALIZE: - return { - ...state, [location]:true - } - - default: - return state - } -} - -export default function initialization (state = {}, action) { - const { path, location } = action - - switch (action.type) { - case listsTypes.INIIALIZE: - return { - ...state, - [path]: locations(state[path], action) - } - - case pathsTypes.VALUE_CHANGED: - return { - ...state, - [path]: locations(state[path], action) - } - - case types.CLEAR_INITIALIZATION: - return {} - - case listsTypes.DESTROY: - case listsTypes.UNWATCH: - case pathsTypes.DESTROY: - case pathsTypes.UNWATCH: - let {[path]: omit, ...rest} = state - return { ...rest} - - default: - return state - } -} diff --git a/src/store/initialization/reducer.spec.js b/src/store/initialization/reducer.spec.js deleted file mode 100644 index 2ca34e5..0000000 --- a/src/store/initialization/reducer.spec.js +++ /dev/null @@ -1,27 +0,0 @@ -import expect from 'expect' -import reducer from './reducer' -import * as actions from './actions' - -const initialState = { -} - -describe('initialization reducer', () => { - it('should return the initial state', () => { - expect( - reducer(undefined, {}) - ).toEqual(initialState) - }) - - it('should not affect state', () => { - expect( - reducer(initialState, {type: 'NOT_EXISTING'}) - ).toEqual(initialState) - }) - - it('should handle clearInitialization', () => { - expect( - reducer(initialState, actions.clearInitialization()) - ).toEqual({}) - }) - -}) diff --git a/src/store/initialization/selectors.js b/src/store/initialization/selectors.js deleted file mode 100644 index 1e3d2b5..0000000 --- a/src/store/initialization/selectors.js +++ /dev/null @@ -1,7 +0,0 @@ -export function isInitialised (state, path, location) { - if (state.initialization !== undefined && state.initialization[path]) { - return state.initialization[path][location] - } - - return false -} diff --git a/src/store/initialization/types.js b/src/store/initialization/types.js deleted file mode 100644 index 104d9b3..0000000 --- a/src/store/initialization/types.js +++ /dev/null @@ -1 +0,0 @@ -export const CLEAR_INITIALIZATION = `@@firekit/INITIALIZATION@CLEAR_INITIALIZATION` diff --git a/src/store/lists/actions.js b/src/store/lists/actions.js deleted file mode 100644 index b9a9202..0000000 --- a/src/store/lists/actions.js +++ /dev/null @@ -1,171 +0,0 @@ -import * as types from './types' -import * as selectors from './selectors' -import * as initSelectors from '../initialization/selectors' - -export const initialize = (list, location, path, append) => { - return { - type: types.INIIALIZE, - payload: list, - path, - location, - append - } -} - - -export const childAdded = (child, location) => { - return { - type: types.CHILD_ADDED, - payload: child, - location - } -} - -export const childChanged = (child, location) => { - return { - type: types.CHILD_CHANGED, - payload: child, - location - } -} - -export const childRemoved = (child, location) => { - return { - type: types.CHILD_REMOVED, - payload: child, - location - } -} - -export const destroy = (location) => { - return { - type: types.DESTROY, - location - } -} - -export const unWatch = (path) => { - return { - type: types.UNWATCH, - path - } -} - -const getPayload = (snapshot) => { - return {key: snapshot.key, val: snapshot.val() } -} - -const getPath = (firebaseApp, ref) => { - return ref.toString().substring(firebaseApp.database().ref().root.toString().length) -} - -const getRef = (firebaseApp, path) => { - if (typeof path === 'string' || path instanceof String) { - return firebaseApp.database().ref(path) - } else { - return path - } -} - -const getLocation = (firebaseApp, path) => { - if (typeof path === 'string' || path instanceof String) { - return path - } else { - return getPath(firebaseApp, path) - } -} - -export function watchList (firebaseApp, firebasePath, reduxPath=false, append=false) { - let ref = getRef(firebaseApp, firebasePath) - let path = ref.toString() - let location = reduxPath?reduxPath:getLocation(firebaseApp, firebasePath) - - return (dispatch, getState) => { - let initialized = false - const isInitialized = initSelectors.isInitialised(getState(), path, location) - - if (!isInitialized) { - ref.once('value', snapshot => { - initialized = true - - let list = [] - - snapshot.forEach(function (childSnapshot) { - let childKey = childSnapshot.key - let childData = childSnapshot.val() - - list.push({key: childKey, val: childData}) - }) - - dispatch(initialize(list, location, path, append)) - - }) - - ref.on('child_added', snapshot => { - if (initialized) { - dispatch(childAdded(getPayload(snapshot), location)) - } - }) - - ref.on('child_changed', snapshot => { - dispatch(childChanged(getPayload(snapshot), location)) - }) - - ref.on('child_removed', snapshot => { - dispatch(childRemoved(getPayload(snapshot), location)) - }) - } - } -} - -export function unwatchList (firebaseApp, firebasePath) { - return dispatch => { - let ref = getRef(firebaseApp, firebasePath) - ref.off() - dispatch(unWatch(ref.toString())) - } -} - -export function destroyList (firebaseApp, firebasePath, reduxPath=false) { - return (dispatch, getState) => { - let ref = getRef(firebaseApp, firebasePath) - const locations=getState().initialization[ref.toString()] - - ref.off() - dispatch(unWatch(ref.toString())) - - if(reduxPath){ - dispatch(destroy(reduxPath)) - }else if(locations){ - Object.keys(locations).forEach(location=>{ - dispatch(destroy(location)) - }) - } - - } -} - - -export function unwatchAllLists (firebaseApp, path) { - return (dispatch, getState) => { - const allLists = selectors.getAllLists(getState()) - - Object.keys(allLists).forEach(function (key, index) { - const ref = firebaseApp.database().ref(key) - ref.off() - dispatch(unWatch(ref.toString())) - }) - } -} - -export function destroyAllLists (firebaseApp, path) { - return (dispatch, getState) => { - const allLists = selectors.getAllLists(getState()) - - Object.keys(allLists).forEach(function (key, index) { - const ref = firebaseApp.database().ref(key) - ref.off() - dispatch(destroyList(firebaseApp, ref.toString())) - }) - } -} diff --git a/src/store/lists/reducer.js b/src/store/lists/reducer.js deleted file mode 100644 index e74961f..0000000 --- a/src/store/lists/reducer.js +++ /dev/null @@ -1,47 +0,0 @@ -import _ from 'lodash' -import * as types from './types' - -function list (list = [], action) { - const { payload, append } = action - switch (action.type) { - - case types.INIIALIZE: - return append?[ ...list, ...payload]:payload - - case types.CHILD_ADDED: - return [ ...list, payload] - - case types.CHILD_CHANGED: - return list.map(child => payload.key === child.key ? payload : child) - - case types.CHILD_REMOVED: - return list.filter(child => payload.key !== child.key) - - default: - return list - } -} - -export default function lists (state = {}, action) { - const { location } = action - - switch (action.type) { - case types.INIIALIZE: - return { - ...state, - [location]: list(state[action.location], action) - } - - case types.CHILD_ADDED: - case types.CHILD_CHANGED: - case types.CHILD_REMOVED: - return {...state, [location]: list(state[action.location], action)} - - case types.DESTROY: - const {[location]: omitData, ...rest} = state - return {...rest} - - default: - return state - } -} diff --git a/src/store/lists/reducer.spec.js b/src/store/lists/reducer.spec.js deleted file mode 100644 index b1fb152..0000000 --- a/src/store/lists/reducer.spec.js +++ /dev/null @@ -1,135 +0,0 @@ -import expect from 'expect' -import reducer from './reducer' -import * as actions from './actions' - -const initialState = { - -} - -describe('lists reducer', () => { - it('should return the initial state', () => { - expect( - reducer(undefined, {}) - ).toEqual(initialState) - }) - - it('should not affect state', () => { - expect( - reducer(initialState, {type: 'NOT_EXISTING'}) - ).toEqual(initialState) - }) - - it('should handle initialize', () => { - expect( - reducer(initialState, actions.initialize( - [1,2,3], - 'test_location', - 'test_path', - false - )) - ).toEqual({ - ...initialState, - test_location: [1,2, 3] - }) - }) - - it('should handle initialize with append', () => { - - const initState={ - test_location: [1] - } - - expect( - reducer(initState, actions.initialize( - [2,3], - 'test_location', - 'test_path', - true - )) - ).toEqual({ - ...initState, - test_location: [1 , 2, 3] - }) - }) - - it('should handle childAdded', () => { - - const initState={ - test_location: [1] - } - - expect( - reducer(initState, actions.childAdded( - 2, - 'test_location', - )) - ).toEqual({ - ...initState, - test_location: [1 , 2] - }) - }) - - it('should handle childChanged', () => { - - const initState={ - test_location: [{ key: 1, val: 'test'}] - } - - expect( - reducer(initState, actions.childChanged( - { key: 1, val: 'test2'}, - 'test_location', - )) - ).toEqual({ - ...initState, - test_location: [{ key: 1, val: 'test2'}] - }) - }) - - it('should handle childRemoved', () => { - - const initState={ - test_location: [{ key: 1, val: 'test'}] - } - - expect( - reducer(initState, actions.childRemoved( - { key: 1, val: 'test2'}, - 'test_location', - )) - ).toEqual({ - ...initState, - test_location: [] - }) - }) - - it('should handle destroy', () => { - - const initState={ - test_location: [{ key: 1, val: 'test'}] - } - - expect( - reducer(initState, actions.destroy( - 'test_location', - )) - ).toEqual({ - }) - }) - - it('should handle unWatch', () => { - - const initState={ - test_location: [{ key: 1, val: 'test'}] - } - - expect( - reducer(initState, actions.unWatch( - 'test_location', - )) - ).toEqual({ - ...initState - }) - }) - -}) diff --git a/src/store/lists/selectors.js b/src/store/lists/selectors.js deleted file mode 100644 index 2c3cc60..0000000 --- a/src/store/lists/selectors.js +++ /dev/null @@ -1,4 +0,0 @@ - -export function getAllLists (state) { - return state.lists -} diff --git a/src/store/lists/types.js b/src/store/lists/types.js deleted file mode 100644 index abf120c..0000000 --- a/src/store/lists/types.js +++ /dev/null @@ -1,7 +0,0 @@ -export const APPEND_INIIALIZE = `@@firekit/LISTS@APPEND_INIIALIZE` -export const INIIALIZE = `@@firekit/LISTS@INIIALIZE` -export const DESTROY = `@@firekit/LISTS@DESTROY` -export const UNWATCH = `@@firekit/LISTS@UNWATCH` -export const CHILD_ADDED = `@@firekit/LISTS@CHILD_ADDED` -export const CHILD_CHANGED = `@@firekit/LISTS@CHILD_CHANGED` -export const CHILD_REMOVED = `@@firekit/LISTS@CHILD_REMOVED` diff --git a/src/store/messaging/actions.js b/src/store/messaging/actions.js deleted file mode 100644 index c40724b..0000000 --- a/src/store/messaging/actions.js +++ /dev/null @@ -1,67 +0,0 @@ -import * as types from './types' - -export function onTokenChanged (token) { - return { - type: types.TOKEN_CHANGED, - payload: {token, isInitialized: true} - } -} - -export function onPermissionChanged (hasPermission, onMessage) { - return { - type: types.PERMISSION_CHANGED, - payload: {hasPermission, isInitialized: true} - } -} - -export function onMessage (message) { - return { - type: types.ON_MESSAGE, - payload: {message} - } -} -export function clearMessage () { - return { - type: types.ON_CLEAR_MESSAGE, - } -} - -export function onMessagingError (error) { - return { - type: types.MESSAGING_ERROR, - payload: {error} - } -} - -export function initMessaging (firebaseApp, handleTokenChange, onMessageReceieved) { - return dispatch => { - const messaging = firebaseApp.messaging() - - try { - messaging.requestPermission() - .then(() => { - return messaging.getToken() - }) - .then(token => { - if (handleTokenChange !== undefined && handleTokenChange instanceof Function) { - handleTokenChange(token) - } - - dispatch(onTokenChanged(token)) - }) - .catch(error => { - dispatch(onPermissionChanged(false)) - }) - } catch (e) { - dispatch(onTokenChanged(token)) - } - - messaging.onMessage(payload => { - if (onMessageReceieved !== undefined && onMessageReceieved instanceof Function) { - onMessageReceieved(payload) - } - - dispatch(onMessage(payload)) - }) - } -} diff --git a/src/store/messaging/reducer.js b/src/store/messaging/reducer.js deleted file mode 100644 index ab4ca22..0000000 --- a/src/store/messaging/reducer.js +++ /dev/null @@ -1,23 +0,0 @@ -import * as types from './types' - -export const initialState = { - hasPermission: false, - token: undefined -} - -export default function messaging (state = initialState, {payload, type}) { - switch (type) { - case types.PERMISSION_CHANGED: - case types.TOKEN_CHANGED: - case types.MESSAGING_ERROR: - case types.ON_MESSAGE: - return {...state, ...payload} - - case types.ON_CLEAR_MESSAGE: - const { message, ...rest }= state - return {...rest} - - default: - return state - } -} diff --git a/src/store/messaging/reducer.spec.js b/src/store/messaging/reducer.spec.js deleted file mode 100644 index ff7bcbb..0000000 --- a/src/store/messaging/reducer.spec.js +++ /dev/null @@ -1,62 +0,0 @@ -import expect from 'expect' -import reducer from './reducer' -import * as actions from './actions' - -const initialState = { - hasPermission: false, - token: undefined -} - -describe('messaging reducer', () => { - it('should return the initial state', () => { - expect( - reducer(undefined, {}) - ).toEqual(initialState) - }) - - it('should not affect state', () => { - expect( - reducer(initialState, {type: 'NOT_EXISTING'}) - ).toEqual(initialState) - }) - - it('should handle onTokenChanged', () => { - expect( - reducer(initialState, actions.onTokenChanged('testToken')) - ).toEqual({...initialState, isInitialized: true, token: 'testToken'}) - }) - - it('should handle onMessage', () => { - expect( - reducer(initialState, actions.onMessage('testMessage')) - ).toEqual({...initialState, - token: undefined, - message: 'testMessage'} - ) - }) - it('should handle clearMessage', () => { - expect( - reducer( - { - hasPermission: true, - token: 'test', - message: 'test' - }, - actions.clearMessage() - ) - ).toEqual({ - hasPermission: true, - token: 'test'} - ) - }) - - it('should handle onMessagingError', () => { - expect( - reducer(initialState, actions.onMessagingError('testError')) - ).toEqual({ ...initialState, - hasPermission: false, - error: 'testError', - token: undefined} - ) - }) -}) diff --git a/src/store/messaging/types.js b/src/store/messaging/types.js deleted file mode 100644 index f1a4938..0000000 --- a/src/store/messaging/types.js +++ /dev/null @@ -1,5 +0,0 @@ -export const TOKEN_CHANGED = `@@firekit/MESSAGING@TOKEN_CHANGED` -export const PERMISSION_CHANGED = `@@firekit/MESSAGING@PERMISSION_CHANGED` -export const MESSAGING_ERROR = `@@firekit/MESSAGING@MESSAGING_ERROR` -export const ON_MESSAGE = `@@firekit/MESSAGING@ON_MESSAGE` -export const ON_CLEAR_MESSAGE = `@@firekit/MESSAGING@ON_CLEAR_MESSAGE` diff --git a/src/store/paths/actions.js b/src/store/paths/actions.js deleted file mode 100644 index 2e23172..0000000 --- a/src/store/paths/actions.js +++ /dev/null @@ -1,76 +0,0 @@ -import * as types from './types' -import * as selectors from './selectors' -import * as initSelectors from '../initialization/selectors' - -export const valueChanged = (value, location, path) => { - return { - type: types.VALUE_CHANGED, - payload: value, - path, - location - } -} - -export const destroy = (location) => { - return { - type: types.DESTROY, - location - } -} - -export const unWatch = (location) => { - return { - type: types.UNWATCH, - location - } -} - -export function watchPath (firebaseApp, firebasePath, reduxPath=false) { - - const location = reduxPath?reduxPath:firebasePath - - return (dispatch, getState) => { - const isInitialized = initSelectors.isInitialised(getState(), location) - - if (!isInitialized) { - const ref = firebaseApp.database().ref(firebasePath) - const path = ref.toString() - - ref.on('value', snapshot => { - dispatch(valueChanged(snapshot.val(), location, path)) - }) - } - } -} - -export function unwatchPath (firebaseApp, path, reduxPath=false) { - - const location = reduxPath?reduxPath:path - - return dispatch => { - firebaseApp.database().ref(path).off() - dispatch(unWatch(dispatch)) - } -} - -export function destroyPath (firebaseApp, path, reduxPath=false) { - - const location = reduxPath?reduxPath:path - - return dispatch => { - firebaseApp.database().ref(path).off() - dispatch(unWatch(location)) - dispatch(destroy(location)) - } -} - -export function unwatchAllPaths (firebaseApp) { - return (dispatch, getState) => { - const allPaths = selectors.getAllPaths(getState()) - - Object.keys(allPaths).forEach(function (key, index) { - firebaseApp.database().ref(allPaths[index]).off() - dispatch(unWatch(key)) - }) - } -} diff --git a/src/store/paths/reducer.js b/src/store/paths/reducer.js deleted file mode 100644 index 5de7242..0000000 --- a/src/store/paths/reducer.js +++ /dev/null @@ -1,17 +0,0 @@ -import * as types from './types' - -export default function paths (state = {}, action) { - const { location } = action - - switch (action.type) { - case types.VALUE_CHANGED: - return {...state, [location]: action.payload} - - case types.DESTROY: - const {[location]: omitData, ...rest} = state - return {...rest} - - default: - return state - } -} diff --git a/src/store/paths/reducer.spec.js b/src/store/paths/reducer.spec.js deleted file mode 100644 index 1a29e2e..0000000 --- a/src/store/paths/reducer.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -import expect from 'expect' -import reducer from './reducer' -import * as actions from './actions' - -const initialState = { - -} - -describe('paths reducer', () => { - it('should return the initial state', () => { - expect( - reducer(undefined, {}) - ).toEqual(initialState) - }) - - it('should not affect state', () => { - expect( - reducer(initialState, {type: 'NOT_EXISTING'}) - ).toEqual(initialState) - }) - - it('should handle valueChanged', () => { - expect( - reducer(initialState, actions.valueChanged( - 'test', - 'test_location', - 'test_path' - )) - ).toEqual({ - ...initialState, - test_location: 'test' - }) - }) - - it('should handle destroy', () => { - - const initState={ - test_location: 'test' - } - - expect( - reducer(initState, actions.destroy( - 'test_location' - )) - ).toEqual({ - - }) - }) - - it('should handle unWatch', () => { - - const initState={ - test_location: 'test' - } - - expect( - reducer(initState, actions.unWatch( - 'test_location' - )) - ).toEqual({ - ...initState - }) - }) - - -}) diff --git a/src/store/paths/selectors.js b/src/store/paths/selectors.js deleted file mode 100644 index 39d82c3..0000000 --- a/src/store/paths/selectors.js +++ /dev/null @@ -1,4 +0,0 @@ - -export function getAllPaths (state) { - return state.paths -} diff --git a/src/store/paths/types.js b/src/store/paths/types.js deleted file mode 100644 index 51639b6..0000000 --- a/src/store/paths/types.js +++ /dev/null @@ -1,4 +0,0 @@ -export const INIIALIZE = `@@firekit/PATHS@INIIALIZE` -export const DESTROY = `@@firekit/PATHS@DESTROY` -export const UNWATCH = `@@firekit/PATHS@UNWATCH` -export const VALUE_CHANGED = `@@firekit/PATHS@VALUE_CHANGED` diff --git a/src/withFirebase.js b/src/withFirebase.js deleted file mode 100644 index 55a3ba3..0000000 --- a/src/withFirebase.js +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import { clearInitialization } from './store/initialization/actions' -import { initConnection, unsubscribeConnection } from './store/connection/actions' -import { watchAuth, authStateChanged, authError} from './store/auth/actions' -import { watchList, unwatchList, destroyList, unwatchAllLists } from './store/lists/actions' -import { watchPath, unwatchPath, destroyPath, unwatchAllPaths } from './store/paths/actions' -import { initMessaging, clearMessage } from './store/messaging/actions' - -const withFirebase = (Component) => { - const ChildComponent = (props, context) => { - const {firebaseApp, store} = context - const {dispatch} = store - - return { - dispatch(watchAuth(firebaseApp, onAuthStateChanged, onAuthError)) - }} - - clearInitialization={() => { dispatch(clearInitialization()) }} - - authStateChanged={(user) => { dispatch(authStateChanged(user)) }} - authError={(error) => { dispatch(authError(error)) }} - - watchConnection={() => { dispatch(initConnection(firebaseApp)) }} - unwatchConnection={() => { dispatch(unsubscribeConnection(firebaseApp)) }} - - watchList={(path, alias, append) => { dispatch(watchList(firebaseApp, path, alias, append)) }} - unwatchList={(path, alias) => { dispatch(unwatchList(firebaseApp, path, alias)) }} - destroyList={(path, alias) => { dispatch(destroyList(firebaseApp, path, alias)) }} - unwatchAllLists={() => { dispatch(unwatchAllLists(firebaseApp)) }} - - watchPath={(path, alias) => { dispatch(watchPath(firebaseApp, path, alias)) }} - unwatchPath={(path, alias) => { dispatch(unwatchPath(firebaseApp, path, alias)) }} - destroyPath={(path, alias) => { dispatch(destroyPath(firebaseApp, path, alias)) }} - unwatchAllPaths={() => { dispatch(unwatchAllPaths(firebaseApp)) }} - - clearApp={() => { - dispatch(unwatchAllLists(firebaseApp)) - dispatch(unwatchAllPaths(firebaseApp)) - dispatch(unsubscribeConnection(firebaseApp)) - }} - - initMessaging={(handleTokenChange, onMessageReceieved) => { dispatch(initMessaging(firebaseApp, handleTokenChange, onMessageReceieved)) }} - clearMessage={() => { dispatch(clearMessage()) }} - - {...props} - /> - } - - ChildComponent.contextTypes = { - firebaseApp: PropTypes.object.isRequired, - store: PropTypes.object.isRequired - } - - return ChildComponent -} - -export default withFirebase