Skip to content

Commit 3ec0c6d

Browse files
committed
Merge branch 'v2.1.0' into v2.0.5
2 parents 4cf6ec9 + 6763afc commit 3ec0c6d

File tree

10 files changed

+93
-72
lines changed

10 files changed

+93
-72
lines changed

.prettierrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
singleQuote: true
2+
semi: false
3+
trailingComma: 'none'

README.md

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@ The [Material Example](https://github.com/prescottprue/react-redux-firebase/tree
3030
- Server Side Rendering Support
3131
- [`react-native` support](/docs/recipes/react-native.md) using [native modules](http://docs.react-redux-firebase.com/history/v2.0.0/docs/recipes/react-native.html#native-modules) or [web sdk](/docs/recipes/react-native.md#jsweb)
3232

33-
## Install
33+
## Installation
3434

3535
```bash
3636
npm install --save react-redux-firebase
3737
```
3838

39+
This assumes you are using [npm](https://www.npmjs.com/) as your package manager.
40+
41+
If you're not, you can access the library on [unpkg](https://unpkg.com/redux-firestore@latest/dist/redux-firestore.min.js), download it, or point your package manager to it. Theres more on this in the [Builds section below](#builds).
42+
3943
## Use
4044

4145
Include `reactReduxFirebase` (store enhancer) and `firebaseReducer` (reducer) while creating your redux store:
@@ -116,7 +120,7 @@ const Todos = ({ firebase }) => {
116120
}
117121

118122
export default withFirebase(Todos)
119-
// or firebaseConnect()(Todos) if attaching listeners
123+
// or firebaseConnect()(Todos)
120124
```
121125

122126
**Load Data (listeners automatically managed on mount/unmount)**
@@ -157,12 +161,10 @@ export default compose(
157161
firebaseConnect([
158162
'todos' // { path: '/todos' } // object notation
159163
]),
160-
connect(
161-
(state) => ({
162-
todos: state.firebase.data.todos,
163-
// profile: state.firebase.profile // load profile
164-
})
165-
)
164+
connect((state) => ({
165+
todos: state.firebase.data.todos,
166+
// profile: state.firebase.profile // load profile
167+
}))
166168
)(Todos)
167169
```
168170

@@ -250,6 +252,14 @@ export default compose(
250252
)(Todos)
251253
```
252254

255+
## Firestore
256+
257+
If you plan to use Firestore, you should checkout [`redux-firestore`][redux-firestore]. It integrates nicely with `react-redux-firebase` and it allows you to run Real Time Database and Firestore along side each other.
258+
259+
`react-redux-firebase` provides the `firestoreConnect` HOC (similar to `firebaseConnect`) for easy setting/unsetting of listeners.
260+
261+
Currently `react-redux-firebase` still handles auth when using [`redux-firestore`][redux-firestore] - The future plan is to also have auth standalone auth library that will allow the developer to choose which pieces they do/do not want.
262+
253263
## [Docs](http://react-redux-firebase.com)
254264
See full documentation at [react-redux-firebase.com](http://react-redux-firebase.com)
255265

@@ -262,11 +272,18 @@ See full documentation at [react-redux-firebase.com](http://react-redux-firebase
262272

263273
## [Examples](examples)
264274

265-
Examples folder is broken into two categories [complete](https://github.com/prescottprue/react-redux-firebase/tree/master/examples/complete) and [snippets](https://github.com/prescottprue/react-redux-firebase/tree/master/examples/snippets). `/complete` contains full applications that can be run as is, while `/snippets` contains small amounts of code to show functionality (dev tools and deps not included).
275+
### Real World Applications
276+
* [fireadmin.io](http://fireadmin.io) - Firebase Instance Management Tool (source [available here](https://github.com/prescottprue/fireadmin))
277+
278+
If you would like a project added to this section please reach out [over gitter][gitter-url]
279+
280+
### [Examples Folder](examples)
281+
282+
Examples folder is broken into two categories [snippets](examples/snippets) and [complete](examples/complete). `/complete` contains full applications that can be run as is, where as `/snippets` contains small amounts of code to highlight specific functionality (dev tools and deps not included).
266283

267284
#### [State Based Query Snippet](examples/snippets/stateBasedQuery)
268285

269-
Snippet showing querying based on data in redux state. One of the most common examples of this is querying based on the current users auth UID.
286+
Snippet showing querying based on data in redux state. One of the more common examples is querying based on the current users auth UID.
270287

271288
#### [Decorators Snippet](examples/snippets/decorators)
272289

@@ -294,17 +311,9 @@ View docs for recipes on integrations with:
294311
* [redux-saga](http://react-redux-firebase.com/docs/integrations/redux-saga.md)
295312
* [redux-form](http://react-redux-firebase.com/docs/integrations/redux-form.md)
296313
* [redux-auth-wrapper](http://react-redux-firebase.com/docs/integrations/routing.md#advanced)
297-
* [redux-persist](http://react-redux-firebase.com/docs/integrations/redux-persist.md) - [improved integration with `v2.0.0`](http://react-redux-firebase.com/docs/integrations/redux-persist.html)
314+
* [redux-persist](http://react-redux-firebase.com/docs/integrations/redux-persist.md)
298315
* [react-native](/docs/integrations/react-native.md)
299-
* [react-native-firebase](http://react-redux-firebase.com/docs/integrations/react-native.html#native-modules) - requires `v2.0.0`
300-
301-
## Firestore
302-
303-
If you plan to use Firestore, you should checkout [`redux-firestore`][redux-firestore]. It integrates nicely with `react-redux-firebase` (v2 only) and it allows you to run Real Time Database and Firestore along side each other.
304-
305-
`react-redux-firebase` provides the `firestoreConnect` HOC (similar to `firebaseConnect`) for easy setting/unsetting of listeners.
306-
307-
Currently `react-redux-firebase` still handles auth when using [`redux-firestore`][redux-firestore] - The future plan is to also have auth standalone auth library that will allow the developer to choose which pieces they do/do not want.
316+
* [react-native-firebase](http://react-redux-firebase.com/docs/integrations/react-native.html#native-modules)
308317

309318
## Starting A Project
310319

@@ -316,10 +325,26 @@ Currently `react-redux-firebase` still handles auth when using [`redux-firestore
316325

317326
The [examples folder](/examples) contains full applications that can be copied/adapted and used as a new project.
318327

319-
### FAQ
328+
## FAQ
320329

321330
Please visit the [FAQ section of the docs](http://docs.react-redux-firebase.com/history/v2.0.0/docs/FAQ.html)
322331

332+
## Builds
333+
334+
Most commonly people consume Redux Firestore as a [CommonJS module](http://webpack.github.io/docs/commonjs.html). This module is what you get when you import redux in a Webpack, Browserify, or a Node environment.
335+
336+
If you don't use a module bundler, it's also fine. The redux-firestore npm package includes precompiled production and development [UMD builds](https://github.com/umdjs/umd) in the [dist folder](https://unpkg.com/redux-firestore@latest/dist/). They can be used directly without a bundler and are thus compatible with many popular JavaScript module loaders and environments. For example, you can drop a UMD build as a `<script>` tag on the page. The UMD builds make Redux Firestore available as a `window.ReduxFirestore` global variable.
337+
338+
It can be imported like so:
339+
340+
```html
341+
<script src="../node_modules/react-redux-firebase/dist/react-redux-firebase.min.js"></script>
342+
<!-- or through cdn: <script src="https://unpkg.com/react-redux-firebase@latest/dist/react-redux-firebase.min.js"></script> -->
343+
<script>console.log('react redux firebase:', window.ReactReduxFirebase)</script>
344+
```
345+
346+
Note: In an effort to keep things simple, the wording from this explanation was modeled after [the installation section of the Redux Docs](https://redux.js.org/#installation).
347+
323348
## Contributors
324349

325350
This project exists thanks to all the people who contribute.

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-redux-firebase",
3-
"version": "2.0.4",
3+
"version": "2.1.0",
44
"description": "Redux integration for Firebase. Comes with a Higher Order Components for use with React.",
55
"main": "lib/index.js",
66
"module": "es/index.js",
@@ -11,7 +11,7 @@
1111
"clean": "rimraf es lib dist coverage",
1212
"lint": "eslint src/** test/unit/** test/setup.js",
1313
"lint:fix": "npm run lint -- --fix",
14-
"format": "prettier --single-quote --no-semi --trailing-comma none --write \"src/**/*.js\" \"test/**/*.js\"",
14+
"format": "prettier --write \"src/**/*.js\" \"test/**/*.js\"",
1515
"test": "mocha -R spec ./test/unit/**",
1616
"test:cov": "istanbul cover ./node_modules/mocha/bin/_mocha ./test/unit/**",
1717
"codecov": "cat coverage/lcov.info | codecov",
@@ -117,7 +117,7 @@
117117
"rimraf": "^2.6.2",
118118
"sinon": "^3.3.0",
119119
"sinon-chai": "^2.14.0",
120-
"webpack": "^3.6.0",
120+
"webpack": "^3.11.0",
121121
"webpack-bundle-analyzer": "^2.9.0",
122122
"ws": "^3.2.0",
123123
"xmlhttprequest": "^1.8.0"

src/actions/auth.js

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ export const createUserProfile = (dispatch, firebase, userData, profile) => {
190190
if (isFunction(config.profileFactory)) {
191191
// catch errors in user provided profileFactory function
192192
try {
193-
profile = config.profileFactory(userData, profile) // eslint-disable-line no-param-reassign
193+
profile = config.profileFactory(userData.user, profile, userData) // eslint-disable-line no-param-reassign
194194
} catch (err) {
195195
/* eslint-disable no-console */
196196
console.error(
@@ -468,52 +468,35 @@ export const login = (dispatch, firebase, credentials) => {
468468
.auth()
469469
[method](...params)
470470
.then(userData => {
471-
// Handle null response from getRedirectResult before redirect has happened
472-
if (!userData) return Promise.resolve(null)
473-
474-
// For email auth return uid (createUser is used for creating a profile)
475-
if (method === 'signInWithEmailAndPassword') {
476-
return { user: userData }
477-
}
478-
// TODO: Only call createUserProfile once, and just pass different settings
479-
480-
// For token auth, the user key doesn't exist. Instead, return the JWT.
481-
if (method === 'signInWithCustomToken') {
482-
if (!firebase._.config.updateProfileOnLogin) {
483-
return { user: userData }
484-
}
485-
return createUserProfile(
486-
dispatch,
487-
firebase,
488-
userData,
489-
credentials.profile
490-
)
491-
}
492-
471+
// signInWithPhoneNumber is a two step process which requires modifying
472+
// the confirm method already existing on the response
493473
if (method === 'signInWithPhoneNumber') {
494474
// Modify confirm method to include profile creation
495475
return {
496476
...userData,
497477
confirm: code =>
498-
// Call original confirm
499-
userData.confirm(code).then(({ user, additionalUserInfo }) =>
500-
createUserProfile(dispatch, firebase, user, {
501-
phoneNumber: user.providerData[0].phoneNumber,
502-
providerData: user.providerData
503-
}).then(profile => ({ profile, user, additionalUserInfo }))
478+
// Call original confirm with profile creation after
479+
userData.confirm(code).then(confirmResponse =>
480+
createUserProfile(dispatch, firebase, confirmResponse, {
481+
phoneNumber: confirmResponse.user.providerData[0].phoneNumber,
482+
providerData: confirmResponse.user.providerData
483+
}).then(profile => ({ profile, ...confirmResponse }))
504484
)
505485
}
506486
}
507-
508-
// Create profile when logging in with external provider
509-
const user = userData.user || userData
510-
511-
return createUserProfile(dispatch, firebase, user, {
512-
email: user.email,
513-
displayName: user.providerData[0].displayName || user.email,
514-
avatarUrl: user.providerData[0].photoURL,
515-
providerData: user.providerData
516-
}).then(profile => ({ profile, ...userData }))
487+
return userData
488+
})
489+
.then(userData => {
490+
// Create user profile if returned data exists and not type signInWithPhoneNumber
491+
if (userData && method !== 'signInWithPhoneNumber') {
492+
return createUserProfile(
493+
dispatch,
494+
firebase,
495+
userData,
496+
credentials.profile
497+
).then(profile => ({ profile, ...userData }))
498+
}
499+
return userData
517500
})
518501
.catch(err => {
519502
dispatchLoginError(dispatch, err)
@@ -567,7 +550,11 @@ export const createUser = (
567550
.auth()
568551
.createUserWithEmailAndPassword(email, password)
569552
.then(
570-
userData =>
553+
userData => {
554+
if () {
555+
556+
}
557+
}
571558
// Login to newly created account if signIn flag is not set to false
572559
firebase.auth().currentUser || (!!signIn && signIn === false)
573560
? createUserProfile(

src/firestoreConnect.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ export const createFirestoreConnect = (storeKey = 'store') => (
5353
}
5454
}
5555

56-
// TODO: Re-attach listeners on query path change
5756
componentWillReceiveProps(np) {
5857
const { firebase, firestore } = this.store
5958
const inputAsFunc = createCallable(dataOrFn)
@@ -73,7 +72,6 @@ export const createFirestoreConnect = (storeKey = 'store') => (
7372
return (
7473
<WrappedComponent
7574
{...this.props}
76-
{...this.state}
7775
firebase={{ ...firebase, ...firebase.helpers }}
7876
firestore={firestore}
7977
/>

src/helpers.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ const buildChildList = (state, list, p) =>
189189
mapValues(list, (val, key) => {
190190
let getKey = val
191191
// Handle key: true lists
192-
if (val === true) {
192+
if (val === true || p.populateByKey) {
193193
getKey = key
194194
}
195195
// Allow for aliasing populated data see #126 for more details
@@ -210,7 +210,7 @@ const buildChildList = (state, list, p) =>
210210
: get(state.data, pathString)
211211
}
212212
// Populate child does not exist
213-
return val === true ? val : getKey
213+
return val === true || p.populateByKey ? val : getKey
214214
})
215215

216216
/**

src/utils/populate.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export const populateList = (firebase, list, p, results) => {
108108
return Promise.all(
109109
map(list, (id, childKey) => {
110110
// handle list of keys
111-
const populateKey = id === true ? childKey : id
111+
const populateKey = id === true || p.populateByKey ? childKey : id
112112
return getPopulateChild(firebase, p, populateKey).then(pc => {
113113
if (pc) {
114114
// write child to result object under root name if it is found

test/unit/actions/auth.spec.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ const addSpyWithArgsToAuthMethod = (methodName, spyFunc, args = []) => ({
5050
[methodName]: () => spyFunc(args)
5151
})
5252
})
53-
const fakeLogin = { email: 'test@tst.com', password: 'asdfasdf', role: 'admin' }
53+
const fakeLogin = {
54+
email: 'test@tst.com',
55+
password: 'asdfasdf',
56+
role: 'admin'
57+
}
5458

5559
describe('Actions: Auth -', () => {
5660
beforeEach(() => {

test/unit/reducer.spec.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,11 @@ describe('reducer', () => {
181181

182182
it('sets data to path with already existing data with numeric keys', () => {
183183
initialData = { data: { test: { [childKey]: { 123: 'bar1' } } } }
184-
action = { type: actionTypes.SET, path: childPath, data: { 124: 'bar2' } }
184+
action = {
185+
type: actionTypes.SET,
186+
path: childPath,
187+
data: { 124: 'bar2' }
188+
}
185189
expect(firebaseReducer(initialData, action).data).to.deep.equal({
186190
...initialState.data,
187191
test: {

0 commit comments

Comments
 (0)