Skip to content

Commit fc0cce8

Browse files
authored
Version v1.2.1 (prescottprue#44)
* Single item with iterable child population now supported with `populatedDataToJS` * `getRedirectResult` no longer calls dispatches `LOGOUT` on null response (fixes refresh issue with redux-auth-wrapper). * `isLoading` typo corrected to `isInitalizing` in logout reducer case
1 parent 62daf9c commit fc0cce8

File tree

7 files changed

+106
-82
lines changed

7 files changed

+106
-82
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-redux-firebase",
3-
"version": "1.2.0",
3+
"version": "1.2.1",
44
"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",

src/actions/auth.js

+19-20
Original file line numberDiff line numberDiff line change
@@ -184,27 +184,26 @@ export const init = (dispatch, firebase) => {
184184
if (firebase._.config.enableRedirectHandling) {
185185
firebase.auth().getRedirectResult()
186186
.then((authData) => {
187-
if (!authData || !authData.user) {
188-
return dispatch({ type: LOGOUT })
187+
if (authData && authData.user) {
188+
const { user } = authData
189+
190+
firebase._.authUid = user.uid
191+
watchUserProfile(dispatch, firebase)
192+
193+
dispatchLogin(dispatch, user)
194+
195+
createUserProfile(
196+
dispatch,
197+
firebase,
198+
user,
199+
{
200+
email: user.email,
201+
displayName: user.providerData[0].displayName || user.email,
202+
avatarUrl: user.providerData[0].photoURL,
203+
providerData: user.providerData
204+
}
205+
)
189206
}
190-
const { user } = authData
191-
192-
firebase._.authUid = user.uid
193-
watchUserProfile(dispatch, firebase)
194-
195-
dispatchLogin(dispatch, user)
196-
197-
createUserProfile(
198-
dispatch,
199-
firebase,
200-
user,
201-
{
202-
email: user.email,
203-
displayName: user.providerData[0].displayName || user.email,
204-
avatarUrl: user.providerData[0].photoURL,
205-
providerData: user.providerData
206-
}
207-
)
208207
}).catch((error) => {
209208
dispatchLoginError(dispatch, error)
210209
return Promise.reject(error)

src/helpers.js

+63-50
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,29 @@ export const dataToJS = (data, path, notSetValue) => {
176176

177177
return data
178178
}
179+
180+
/**
181+
* @private
182+
* @description Build child list based on populate
183+
* @param {Map} data - Immutable Map to be converted to JS object (state.firebase)
184+
* @param {Object} list - Path of parameter to load
185+
* @param {Object} populate - Object with population settings
186+
*/
187+
export const buildChildList = (data, list, populate) =>
188+
mapValues(list, (val, key) => {
189+
let getKey = val
190+
// Handle key: true lists
191+
if (val === true) {
192+
getKey = key
193+
}
194+
// Set to child under key if populate child exists
195+
if (dataToJS(data, `${populate.root}/${getKey}`)) {
196+
return dataToJS(data, `${populate.root}/${getKey}`)
197+
}
198+
// Populate child does not exist
199+
return val === true ? val : getKey
200+
})
201+
179202
/**
180203
* @description Convert parameter under "data" path of Immutable Map to a
181204
* Javascript object with parameters populated based on populates array
@@ -188,71 +211,61 @@ export const dataToJS = (data, path, notSetValue) => {
188211
* import { connect } from 'react-redux'
189212
* import { firebaseConnect, helpers } from 'react-redux-firebase'
190213
* const { dataToJS } = helpers
214+
* const populates = [{ child: 'owner', root: 'users' }]
191215
*
192-
* const fbWrapped = firebaseConnect(['/todos'])(App)
216+
* const fbWrapped = firebaseConnect([
217+
* { path: '/todos', populates } // load "todos" and matching "users" to redux
218+
* ])(App)
193219
*
194220
* export default connect(({ firebase }) => ({
195221
* // this.props.todos loaded from state.firebase.data.todos
196222
* // each todo has child 'owner' populated from matching uid in 'users' root
197-
* todos: populatedDataToJS(firebase, 'todos', [{ child: 'owner', root: 'users' }])
223+
* todos: populatedDataToJS(firebase, 'todos', populates)
198224
* }))(fbWrapped)
199225
*/
200226
export const populatedDataToJS = (data, path, populates, notSetValue) => {
201227
if (!data) {
202228
return notSetValue
203229
}
204230

205-
const pathArr = `/data${fixPath(path)}`.split(/\//).slice(1)
206-
207-
if (data.getIn) {
208-
if (!toJS(data.getIn(pathArr, notSetValue))) {
209-
return toJS(data.getIn(pathArr))
210-
}
211-
const populateObjs = getPopulateObjs(populates)
212-
// reduce array of populates to object of combined populated data
213-
return reduce(
214-
map(populateObjs, (p, obj) =>
215-
// map values of list
216-
mapValues(toJS(data.getIn(pathArr)), (child, i) => {
217-
// no matching child parameter
218-
if (!child[p.child]) {
219-
return child
220-
}
221-
// populate child is key
222-
if (isString(child[p.child])) {
223-
if (toJS(data.getIn(['data', p.root, child[p.child]]))) {
224-
return {
225-
...child,
226-
[p.child]: toJS(data.getIn(['data', p.root, child[p.child]]))
227-
}
231+
const populateObjs = getPopulateObjs(populates)
232+
// reduce array of populates to object of combined populated data
233+
return reduce(
234+
map(populateObjs, (p, obj) => {
235+
// single item with iterable child
236+
if (dataToJS(data, path)[p.child]) {
237+
return {
238+
...dataToJS(data, path),
239+
[p.child]: buildChildList(data, dataToJS(data, path)[p.child], p)
240+
}
241+
}
242+
// list with child param in each item
243+
return mapValues(dataToJS(data, path), (child, i) => {
244+
// no matching child parameter
245+
if (!child[p.child]) {
246+
return child
247+
}
248+
// populate child is key
249+
if (isString(child[p.child])) {
250+
if (dataToJS(data, `${p.root}/${child[p.child]}`)) {
251+
return {
252+
...child,
253+
[p.child]: dataToJS(data, `${p.root}/${child[p.child]}`)
228254
}
229-
// matching child does not exist
230-
return child
231255
}
232-
// populate child list
233-
return {
234-
...child,
235-
[p.child]: mapValues(child[p.child], (val, key) => { // iterate of child list
236-
let getKey = val
237-
// Handle key: true lists
238-
if (val === true) {
239-
getKey = key
240-
}
241-
// Set to child under key if populate child exists
242-
if (toJS(data.getIn(['data', p.root, getKey]))) {
243-
return toJS(data.getIn(['data', p.root, getKey]))
244-
}
245-
// Populate child does not exist
246-
return val === true ? val : getKey
247-
})
248-
}
249-
})
250-
), (obj, v) =>
256+
// matching child does not exist
257+
return child
258+
}
259+
// populate child list
260+
return {
261+
...child,
262+
[p.child]: buildChildList(data, child[p.child], p)
263+
}
264+
})
265+
}), (obj, v) =>
266+
// reduce data from all populates to one object
251267
Object.assign({}, v, obj),
252-
)
253-
}
254-
255-
return data
268+
)
256269
}
257270

258271
/**

src/reducer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export default (state = initialState, action = {}) => {
121121
auth: null,
122122
authError: null,
123123
profile: null,
124-
isLoading: false,
124+
isInitializing: false,
125125
data: {}
126126
})
127127

src/utils/populate.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ export const promisesForPopulate = (firebase, originalData, populatesIn) => {
168168
})
169169

170170
// Return original data after population promises run
171-
return Promise.all(promisesArray).then(d => results)
171+
return Promise.all(promisesArray).then(() => results)
172172
}
173173

174174
export default { promisesForPopulate }

test/unit/helpers.spec.js

+19-6
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ describe('Helpers:', () => {
3535
it('exists', () => {
3636
expect(helpers).to.respondTo('toJS')
3737
})
38+
3839
it('handles non-immutable data', () => {
3940
expect(helpers.toJS(exampleData)).to.equal(exampleData)
4041
})
42+
4143
it('handles immutable data', () => {
4244
expect(helpers.toJS(exampleState)).to.be.an.object
4345
})
@@ -47,22 +49,26 @@ describe('Helpers:', () => {
4749
it('exists', () => {
4850
expect(helpers).to.respondTo('pathToJS')
4951
})
52+
5053
it('passes notSetValue', () => {
5154
expect(helpers.pathToJS(null, '/some', exampleData))
5255
.to
5356
.equal(exampleData)
5457
})
58+
5559
it('gets data', () => {
5660
expect(helpers.pathToJS(exampleState, '/some', exampleData))
5761
.to
5862
.equal(exampleData)
5963
})
64+
6065
it('gets meta (string key)', () => {
6166
expect(helpers.pathToJS(exampleState, 'timestamp/some/path'))
6267
.to
6368
.have
6469
.keys('test')
6570
})
71+
6672
it('returns state if its not an immutable Map', () => {
6773
const fakeState = {}
6874
expect(helpers.pathToJS(fakeState, 'asdf'))
@@ -75,17 +81,20 @@ describe('Helpers:', () => {
7581
it('exists', () => {
7682
expect(helpers).to.respondTo('dataToJS')
7783
})
84+
7885
it('passes notSetValue', () => {
7986
expect(helpers.dataToJS(null, '/some', exampleData))
8087
.to
8188
.equal(exampleData)
8289
})
90+
8391
it('gets data from state', () => {
8492
const path = 'some'
8593
expect(helpers.dataToJS(exampleState, path, exampleData))
8694
.to
8795
.equal(exampleData.data[path])
8896
})
97+
8998
it('returns state if its not an immutable Map', () => {
9099
const fakeState = { }
91100
expect(helpers.dataToJS(fakeState, 'asdf'))
@@ -98,22 +107,19 @@ describe('Helpers:', () => {
98107
it('exists', () => {
99108
expect(helpers).to.respondTo('populatedDataToJS')
100109
})
110+
101111
it('passes notSetValue', () => {
102112
expect(helpers.populatedDataToJS(null, '/some', [], exampleData))
103113
.to
104114
.equal(exampleData)
105115
})
116+
106117
it('returns undefined for non existant path', () => {
107118
expect(helpers.populatedDataToJS(exampleState, '/asdf', []))
108119
.to
109120
.equal(undefined)
110121
})
111-
it('returns state if its not an immutable Map', () => {
112-
const fakeState = { }
113-
expect(helpers.populatedDataToJS(fakeState, 'asdf'))
114-
.to
115-
.equal(fakeState)
116-
})
122+
117123
it('returns unpopulated data for no populates', () => {
118124
const path = '/projects'
119125
expect(helpers.populatedDataToJS(exampleState, path, []))
@@ -185,16 +191,19 @@ describe('Helpers:', () => {
185191
it('exists', () => {
186192
expect(helpers).to.respondTo('customToJS')
187193
})
194+
188195
it('handles non-immutable state', () => {
189196
expect(helpers.customToJS(exampleData, '/some', 'some'))
190197
.to
191198
.equal(exampleData)
192199
})
200+
193201
it('passes notSetValue', () => {
194202
expect(helpers.customToJS(null, '/some', 'some', exampleData))
195203
.to
196204
.equal(exampleData)
197205
})
206+
198207
it('passes custom data', () => {
199208
expect(helpers.customToJS(exampleState, '/some', 'snapshot'))
200209
.to
@@ -206,9 +215,11 @@ describe('Helpers:', () => {
206215
it('exists', () => {
207216
expect(helpers).to.respondTo('isLoaded')
208217
})
218+
209219
it('defaults to true when no arguments passed', () => {
210220
expect(helpers.isLoaded()).to.be.true
211221
})
222+
212223
it('returns true when is loaded', () => {
213224
expect(helpers.isLoaded('some')).to.be.true
214225
})
@@ -218,9 +229,11 @@ describe('Helpers:', () => {
218229
it('exists', () => {
219230
expect(helpers).to.respondTo('isEmpty')
220231
})
232+
221233
it('returns false when not loaded', () => {
222234
expect(helpers.isEmpty('asdf')).to.be.false
223235
})
236+
224237
it('returns true when is loaded', () => {
225238
expect(helpers.isEmpty([{}])).to.be.false
226239
})

test/unit/reducer.spec.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ const exampleEmptyState = fromJS(emptyState)
2929

3030
describe('reducer', () => {
3131
it('is a function', () => {
32-
expect(firebaseStateReducer)
33-
.to.be.a.function
32+
expect(firebaseStateReducer).to.be.a.function
3433
})
3534

3635
it('handles no initialState', () => {
@@ -109,7 +108,7 @@ describe('reducer', () => {
109108
auth: null,
110109
authError: null,
111110
profile: null,
112-
isLoading: false,
111+
isInitializing: false,
113112
data: {}
114113
}))
115114
})

0 commit comments

Comments
 (0)