Skip to content

Commit b76e638

Browse files
authored
#7 v1.0.2
* adds `profileDecorator` configuration option (change format of profile data stored on Firebase) * exposes firebase through `getFirebase` function that can be passed as the third argument when creating thunk actions * adds `updateProfileOnLogin` configuration option that toggles whether or not account is updated when logging in
2 parents ba055c6 + 53ea594 commit b76e638

File tree

5 files changed

+113
-33
lines changed

5 files changed

+113
-33
lines changed

README.md

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,15 +199,71 @@ The simple example implemented using decorators built from the output of [create
199199

200200
An example that user Material UI built on top of the output of [create-react-app](https://github.com/facebookincubator/create-react-app)'s eject command. Shows a list of todo items and allows you to add to them. This is what is deployed to [react-redux-firebase.firebaseapp.com](https://react-redux-firebase.firebaseapp.com/).
201201

202+
## Using with `redux-thunk`
203+
If you user using `redux-thunk`, make sure to set up your thunk middleware using it's redux-thunk's `withExtraArgument` method so that firebase is available within your actions. Here is an example `createStore` function that adds `getFirebase` as third argument along with a thunk that uses it:
204+
205+
createStore:
206+
207+
```javascript
208+
import { applyMiddleware, compose, createStore } from 'redux';
209+
import thunk from 'redux-thunk';
210+
import { reduxReactFirebase } from 'react-redux-firebase';
211+
import makeRootReducer from './reducers';
212+
import { getFirebase } from 'react-redux-firebase';
213+
214+
const fbConfig = {} // your firebase config
215+
216+
const store = createStore(
217+
makeRootReducer(),
218+
initialState,
219+
compose(
220+
applyMiddleware([
221+
thunk.withExtraArgument(getFirebase) // Pass getFirebase function as extra argument
222+
]),
223+
reduxReactFirebase(fbConfig, { userProfile: 'users', enableLogging: false })
224+
)
225+
);
226+
227+
```
228+
Action:
229+
230+
```javascript
231+
const sendNotification = (payload) => {
232+
type: NOTIFICATION,
233+
payload
234+
}
235+
export const addTodo = (newTodo) =>
236+
(dispatch, getState, getFirebase) => {
237+
const firebase = getFirebase()
238+
firebase
239+
.push('todos', newTodo)
240+
.then(() => {
241+
dispatch(sendNotification('Todo Added'))
242+
})
243+
};
244+
245+
```
202246

203247
## Generator
204248

205249
[generator-react-firebase](https://github.com/prescottprue/generator-react-firebase) uses react-redux-firebase when opting to include redux
206250

207-
## In the future
208-
- Redux Form Example
209-
- More Unit Tests/Coverage
210-
- Ideas are welcome :)
251+
## FAQ
252+
253+
1. How is this different than [`redux-react-firebase`](https://github.com/tiberiuc/redux-react-firebase)?
254+
255+
This library was actually originally forked from redux-react-firebase, but adds extended functionality such as:
256+
* populate functionality
257+
* profileDecorator - change format of profile stored on Firebase
258+
* getFirebase - access to firebase that fires actions
259+
* capability for thunk integration - using `getFirebase` and `thunk.withExtraArgument`
260+
261+
Bottom line: The auth of redux-react-firebase was absent when functionality was needed by me and others, so this library was created.
262+
263+
2. Why use redux if I have Firebase?
264+
265+
This isn't a super quick answer, so I wrote up [a medium article to explain](https://medium.com/@prescottprue/firebase-with-redux-82d04f8675b9)
266+
211267

212268
## Contributors
213269
- [Prescott Prue](https://github.com/prescottprue)

package.json

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "react-redux-firebase",
3-
"version": "1.0.1",
4-
"description": "A Higher Order Component to use Firebase version 3 with Redux",
3+
"version": "1.0.2",
4+
"description": "Redux integration for Firebase. Comes with a Higher Order Component for use with React.",
55
"main": "dist/index.js",
66
"module": "src/index.js",
77
"jsnext:main": "src/index.js",
@@ -36,15 +36,10 @@
3636
{
3737
"name": "Rahav Lussato",
3838
"url": "https://github.com/RahavLussato"
39-
},
40-
{
41-
"name": "Tiberiu Craciun",
42-
"email": "[email protected]",
43-
"url": "https://github.com/tiberiuc"
4439
}
4540
],
4641
"dependencies": {
47-
"firebase": "^3.5.0",
42+
"firebase": "^3.5.2",
4843
"immutable": "^3.8.1",
4944
"jwt-decode": "^2.1.0",
5045
"lodash": "^4.16.4"
@@ -55,27 +50,27 @@
5550
"redux": "^3.0.5"
5651
},
5752
"devDependencies": {
58-
"babel-cli": "^6.16.0",
59-
"babel-core": "^6.17.0",
60-
"babel-eslint": "^7.0.0",
53+
"babel-cli": "^6.18.0",
54+
"babel-core": "^6.18.0",
55+
"babel-eslint": "^7.1.0",
6156
"babel-plugin-add-module-exports": "^0.2.1",
6257
"babel-plugin-es6-promise": "^1.0.0",
6358
"babel-plugin-lodash": "^3.2.9",
6459
"babel-plugin-transform-decorators-legacy": "^1.3.4",
65-
"babel-preset-es2015": "^6.16.0",
60+
"babel-preset-es2015": "^6.18.0",
6661
"babel-preset-react": "^6.16.0",
6762
"babel-preset-stage-1": "^6.16.0",
6863
"chai": "^3.5.0",
6964
"codecov": "^1.0.1",
70-
"eslint": "^3.7.1",
71-
"eslint-config-standard": "^6.2.0",
65+
"eslint": "^3.9.0",
66+
"eslint-config-standard": "^6.2.1",
7267
"eslint-config-standard-react": "^4.2.0",
7368
"eslint-plugin-babel": "^3.3.0",
7469
"eslint-plugin-promise": "^3.0.0",
7570
"eslint-plugin-react": "^6.4.1",
7671
"eslint-plugin-standard": "^2.0.1",
7772
"isparta": "^4.0.0",
78-
"jsdom": "^9.8.0",
73+
"jsdom": "^9.8.3",
7974
"mocha": "^3.1.2",
8075
"react-addons-test-utils": "^15.3.2",
8176
"react-dom": "^15.3.2",

src/actions/auth.js

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
AUTHENTICATION_INIT_FINISHED,
99
defaultJWTKeys
1010
} from '../constants'
11-
import { capitalize, omit, isArray, isString } from 'lodash'
11+
import { capitalize, omit, isArray, isString, isFunction } from 'lodash'
1212
import jwtDecode from 'jwt-decode'
1313

1414
/**
@@ -172,8 +172,9 @@ export const createUserProfile = (dispatch, firebase, userData, profile) =>
172172
.child(`${firebase._.config.userProfile}/${userData.uid}`)
173173
.once('value')
174174
.then(profileSnap =>
175-
// Update the profile
176-
profileSnap.ref.update(profile)
175+
!firebase._.config.updateProfileOnLogin && profileSnap.val() !== null
176+
? profile
177+
: profileSnap.ref.update(profile) // Update the profile
177178
.then(() => profile)
178179
.catch(err => {
179180
// Error setting profile
@@ -204,39 +205,54 @@ export const login = (dispatch, firebase, credentials) => {
204205

205206
return firebase.auth()[method](...params)
206207
.then((userData) => {
207-
// Handle null response from getRedirectResult before redirect has happen
208+
// Handle null response from getRedirectResult before redirect has happened
208209
if (!userData) return Promise.resolve(null)
209210

210211
// For email auth return uid (createUser is used for creating a profile)
211212
if (userData.email) return userData.uid
212213

214+
const { profileDecorator } = firebase._.config
215+
213216
// For token auth, the user key doesn't exist. Instead, return the JWT.
214217
if (method === 'signInWithCustomToken') {
215218
// Extract the extra data in the JWT token for user object
216219
const { stsTokenManager: { accessToken }, uid } = userData.toJSON()
217220
const jwtData = jwtDecode(accessToken)
218221
const extraJWTData = omit(jwtData, defaultJWTKeys)
222+
223+
// Handle profile decorator
224+
const profileData = profileDecorator && isFunction(profileDecorator)
225+
? profileDecorator(Object.assign(userData.toJSON(), extraJWTData))
226+
: extraJWTData
227+
219228
return createUserProfile(
220229
dispatch,
221230
firebase,
222231
{ uid },
223-
extraJWTData
232+
profileData
224233
)
225234
}
226235

227236
// Create profile when logging in with external provider
228237
const { user } = userData
229-
return createUserProfile(
230-
dispatch,
231-
firebase,
232-
user,
233-
Object.assign(
238+
239+
// Handle profile decorator
240+
const profileData = profileDecorator && isFunction(profileDecorator)
241+
? profileDecorator(user)
242+
: Object.assign(
234243
{},
235244
{
236245
email: user.email,
246+
displayName: user.providerData[0].displayName || user.email,
237247
providerData: user.providerData
238248
}
239249
)
250+
251+
return createUserProfile(
252+
dispatch,
253+
firebase,
254+
user,
255+
profileData
240256
)
241257
})
242258
.catch(err => {

src/compose.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import Firebase from 'firebase'
22
import { authActions, queryActions } from './actions'
3+
let firebaseInstance
34

4-
export default (config, otherConfig) =>
5-
next => (reducer, initialState) => {
5+
export default (config, otherConfig) => next =>
6+
(reducer, initialState) => {
67
const defaultConfig = {
78
userProfile: null,
8-
enableLogging: false
9+
enableLogging: false,
10+
updateProfileOnLogin: true
911
}
1012

1113
const store = next(reducer, initialState)
@@ -104,6 +106,16 @@ export default (config, otherConfig) =>
104106
authActions.init(dispatch, firebase)
105107

106108
store.firebase = firebase
109+
firebaseInstance = firebase
107110

108111
return store
109112
}
113+
114+
// Expose Firebase instance
115+
export const getFirebase = () => {
116+
if (!firebaseInstance) {
117+
console.error('Firebase instance does not yet exist. Check your compose function.')
118+
return null
119+
}
120+
return firebaseInstance
121+
}

src/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import connect from './connect'
2-
import compose from './compose'
2+
import compose, { getFirebase } from './compose'
33
import reducer from './reducer'
44
import * as helpers from './helpers'
55

@@ -9,5 +9,6 @@ module.exports = {
99
firebaseStateReducer: reducer,
1010
reduxReactFirebase: compose,
1111
reduxFirebase: compose,
12+
getFirebase,
1213
helpers
1314
}

0 commit comments

Comments
 (0)