Skip to content

Commit 2d39f3a

Browse files
authored
v2.0.0 beta.5 (#229)
* Fix bug in `updateProfile` method - #210 * Fix population with deep root - #223 * Fix RN sources must be an object error - #228, #231 * Fix an issue using string notation within `profileParamsToPopulate` * `hoist-non-react-statics` updated * `npm run docs:upload` added for uploading version specific docs (`npm run docs:publish` still used for publishing main version) * fixed login method return signature (object including `user`) - #206
1 parent 6386c2d commit 2d39f3a

File tree

10 files changed

+144
-41
lines changed

10 files changed

+144
-41
lines changed

.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
examples/**
22
coverage/**
33
node_modules/**
4+
_book/**
5+
_site/**

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ coverage
55
dist
66
es
77
lib
8-
_book
8+
_book/**
9+
_site/**
910
# Logs
1011
*.log
1112
.DS_Store
1213
examples/complete/react-native/ios/build
14+
/.idea

bin/api-docs-upload.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
const exec = require('child-process-promise').exec
2+
const version = require('../package.json').version
3+
4+
/**
5+
NOTE: Split into two arrays because gsutil acts differently when
6+
no files exist at a location. First array includes at least one file for each
7+
folder that will be copied in the second.
8+
*/
9+
const first = [
10+
'_book/index.html',
11+
'_book/search_index.json',
12+
'_book/gitbook/gitbook.js',
13+
'_book/docs/README.md'
14+
]
15+
16+
const second = [
17+
'_book/gitbook/**',
18+
'_book/docs/**'
19+
]
20+
21+
const project = 'docs.react-redux-firebase.com'
22+
23+
/**
24+
* Run shell command with error handling.
25+
* @param {String} cmd - Command to run
26+
* @return {Promise} Resolves with stdout of running command
27+
* @private
28+
*/
29+
const runCommand = (cmd) => {
30+
const baseCommand = cmd.split(' ')[0]
31+
return exec(baseCommand)
32+
.catch((err) =>
33+
err.message && err.message.indexOf('not found') !== -1
34+
? Promise.reject(new Error(`${baseCommand} must be installed to upload`))
35+
: Promise.reject(err)
36+
)
37+
}
38+
39+
/**
40+
* Upload file or folder to cloud storage. gsutil is used instead of
41+
* google-cloud/storage module so that folders can be uploaded.
42+
* @param {String} entityPath - Local path for entity (file/folder) to upload
43+
* @return {Promise} Resolve with an object containing stdout and uploadPath
44+
* @private
45+
*/
46+
const upload = (entityPath) => {
47+
const prefix = `history/${version.split('-')[0]}`
48+
const uploadPath = `${project}/${prefix}/${entityPath.replace('_book/', '').replace('/**', '')}`
49+
return runCommand(`gsutil -m cp -r -a public-read ${entityPath} gs://${uploadPath}`)
50+
.then((stdout) => ({ stdout, uploadPath }))
51+
}
52+
53+
/**
54+
* Upload list of files or folders to Google Cloud Storage
55+
* @param {Array} files - List of files/folders to upload
56+
* @return {Promise} Resolves with an array of upload results
57+
* @private
58+
*/
59+
const uploadList = (files) => {
60+
return Promise.all(
61+
files.map(file =>
62+
upload(file)
63+
.then(({ uploadPath }) => {
64+
console.log(`Successfully uploaded: ${uploadPath}`) // eslint-disable-line no-console
65+
return file
66+
})
67+
)
68+
)
69+
}
70+
71+
(function () {
72+
uploadList(first)
73+
.then(() => uploadList(second))
74+
.then(() => {
75+
console.log('Docs uploaded successfully') // eslint-disable-line no-console
76+
process.exit(0)
77+
})
78+
.catch((err) => {
79+
console.log('Error uploading docs:', err.message) // eslint-disable-line no-console
80+
process.exit(1)
81+
})
82+
})()

examples/complete/material/src/routes/Home/containers/HomeContainer.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
firebaseConnect,
88
isLoaded,
99
isEmpty,
10-
populate // for populated list
10+
// populate // for populated list
1111
} from 'react-redux-firebase'
1212
import CircularProgress from 'material-ui/CircularProgress'
1313
import Snackbar from 'material-ui/Snackbar'
@@ -20,27 +20,30 @@ import classes from './HomeContainer.scss'
2020

2121
const populates = [{ child: 'owner', root: 'users' }]
2222

23+
// Pass an array of path settings to create Firebase queries
2324
@firebaseConnect([
2425
// 'todos' // sync full list of todos
2526
// { path: 'todos', populates }, // gather data to populate owners (uid => object)
2627
// { path: 'todos', type: 'once' } // for loading once instead of binding
27-
{ path: 'todos', queryParams: ['orderByKey', 'limitToLast=5'] } // 10 most recent
28+
{ path: 'todos', queryParams: ['orderByKey', 'limitToLast=10'] }, // 10 most recent
29+
// { path: 'todos', storeAs: 'myTodos' }, // store somewhere else in redux
30+
// { path: 'todos', queryParams: ['orderByKey', 'limitToLast=5'] } // 10 most recent
2831
])
32+
// Get data from redux and pass in as props
2933
@connect(
30-
// get auth, profile, and data from
3134
({ firebase, firebase: { auth, profile, data: { todos } } }) => ({
3235
auth,
3336
profile,
3437
todos,
3538
// todos: populate(firebase, 'todos', populates) // populate todos with users data from redux
36-
// todos: firebase.ordered.todos // if using ordering such as orderByChild
39+
// todos: firebase.ordered.todos // if using ordering such as orderByChild or orderByKey
3740
})
3841
)
3942
export default class Home extends Component {
4043
static propTypes = {
4144
todos: PropTypes.oneOfType([
42-
PropTypes.object, // object if using dataToJS
43-
PropTypes.array // array if using orderedToJS
45+
PropTypes.object, // object if using firebase.data
46+
PropTypes.array // array if using firebase.ordered
4447
]),
4548
firebase: PropTypes.shape({
4649
set: PropTypes.func.isRequired,

examples/complete/material/yarn.lock

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2849,6 +2849,10 @@ istanbul-lib-instrument@^1.1.4:
28492849
istanbul-lib-coverage "^1.1.1"
28502850
semver "^5.3.0"
28512851

2852+
jest-docblock@^20.0.1:
2853+
version "20.0.3"
2854+
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-20.0.3.tgz#17bea984342cc33d83c50fbe1545ea0efaa44712"
2855+
28522856
joi@^6.10.1:
28532857
version "6.10.1"
28542858
resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06"
@@ -4073,7 +4077,7 @@ promise@^7.0.3, promise@^7.1.1:
40734077
dependencies:
40744078
asap "~2.0.3"
40754079

4076-
[email protected], prop-types@^15.5.4, prop-types@^15.5.6:
4080+
40774081
version "15.5.8"
40784082
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.8.tgz#6b7b2e141083be38c8595aa51fc55775c7199394"
40794083
dependencies:

package.json

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-redux-firebase",
3-
"version": "2.0.0-beta.4",
3+
"version": "2.0.0-beta.5",
44
"description": "Redux integration for Firebase. Comes with a Higher Order Component for use with React.",
55
"main": "lib/index.js",
66
"module": "es/index.js",
@@ -28,7 +28,8 @@
2828
"docs:api": "node bin/api-docs-generate",
2929
"docs:build": "npm run docs:prepare && gitbook build -g prescottprue/react-redux-firebase && npm run docs:api",
3030
"docs:watch": "npm run docs:prepare && gitbook serve",
31-
"docs:publish": "npm run docs:clean && npm run docs:build && cp CNAME _book && cd _book && git init && git commit --allow-empty -m 'update book' && git checkout -b gh-pages && touch .nojekyll && git add . && git commit -am 'update book' && git push [email protected]:prescottprue/react-redux-firebase gh-pages --force"
31+
"docs:publish": "npm run docs:clean && npm run docs:build && cp CNAME _book && cd _book && git init && git commit --allow-empty -m 'update book' && git checkout -b gh-pages && touch .nojekyll && git add . && git commit -am 'update book' && git push [email protected]:prescottprue/react-redux-firebase gh-pages --force",
32+
"docs:upload": "node bin/api-docs-upload"
3233
},
3334
"license": "MIT",
3435
"homepage": "https://github.com/prescottprue/react-redux-firebase#readme",
@@ -56,10 +57,10 @@
5657
"redux-react-firebase"
5758
],
5859
"dependencies": {
59-
"hoist-non-react-statics": "^1.2.0",
60+
"hoist-non-react-statics": "^2.2.2",
6061
"jwt-decode": "^2.2.0",
6162
"lodash": "^4.17.4",
62-
"prop-types": "^15.5.8"
63+
"prop-types": "^15.5.10"
6364
},
6465
"peerDependencies": {
6566
"react": "^0.14.6 || ^15.0.0-0 || ^16.0.0-0"
@@ -69,8 +70,8 @@
6970
"babel-core": "^6.24.0",
7071
"babel-eslint": "^7.2.1",
7172
"babel-loader": "^7.1.1",
72-
"babel-plugin-lodash": "^3.2.11",
7373
"babel-plugin-add-module-exports": "^0.2.1",
74+
"babel-plugin-lodash": "^3.2.11",
7475
"babel-plugin-transform-class-properties": "^6.23.0",
7576
"babel-plugin-transform-decorators-legacy": "^1.3.4",
7677
"babel-plugin-transform-object-assign": "^6.22.0",
@@ -81,6 +82,7 @@
8182
"babel-register": "^6.24.0",
8283
"chai": "^3.5.0",
8384
"chai-as-promised": "^6.0.0",
85+
"child-process-promise": "^2.2.1",
8486
"codecov": "^2.1.0",
8587
"cross-env": "^1.0.7",
8688
"docdown": "^0.7.2",

src/actions/auth.js

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export const watchUserProfile = (dispatch, firebase) => {
6464
} else {
6565
// TODO: Share population logic with query action
6666
// Convert each populate string in array into an array of once query promises
67-
promisesForPopulate(firebase, snap.val(), profileParamsToPopulate)
67+
promisesForPopulate(firebase, snap.key, snap.val(), profileParamsToPopulate)
6868
.then(data => {
6969
// Fire actions for placement of data gathered in populate into redux
7070
forEach(data, (result, path) => {
@@ -262,15 +262,17 @@ export const init = (dispatch, firebase) => {
262262
*/
263263
export const login = (dispatch, firebase, credentials) => {
264264
dispatchLoginError(dispatch, null)
265-
let { method, params } = getLoginMethodAndParams(firebase, credentials)
265+
const { method, params } = getLoginMethodAndParams(firebase, credentials)
266266

267267
return firebase.auth()[method](...params)
268268
.then((userData) => {
269269
// Handle null response from getRedirectResult before redirect has happened
270270
if (!userData) return Promise.resolve(null)
271271

272272
// For email auth return uid (createUser is used for creating a profile)
273-
if (method === 'signInWithEmailAndPassword') return userData.uid
273+
if (method === 'signInWithEmailAndPassword') {
274+
return { user: userData }
275+
}
274276

275277
// For token auth, the user key doesn't exist. Instead, return the JWT.
276278
if (method === 'signInWithCustomToken') {
@@ -470,17 +472,20 @@ export const updateProfile = (dispatch, firebase, profileUpdate) => {
470472
dispatch({ type: actionTypes.PROFILE_UPDATE_START, payload: profileUpdate })
471473

472474
const { database, _: { config, authUid } } = firebase
473-
474-
return database()
475-
.ref(`${config.userProfile}/${authUid}`)
475+
const profileRef = database().ref(`${config.userProfile}/${authUid}`)
476+
return profileRef
476477
.update(profileUpdate)
477-
.then((snap) => {
478-
dispatch({
479-
type: actionTypes.PROFILE_UPDATE_SUCCESS,
480-
payload: snap.val()
481-
})
482-
return snap.val()
483-
})
478+
.then(() =>
479+
profileRef
480+
.once('value')
481+
.then((snap) => {
482+
dispatch({
483+
type: actionTypes.PROFILE_UPDATE_SUCCESS,
484+
payload: snap.val()
485+
})
486+
return snap
487+
})
488+
)
484489
.catch((payload) => {
485490
dispatch({ type: actionTypes.PROFILE_UPDATE_ERROR, payload })
486491
return Promise.reject(payload)

src/actions/query.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export const watchEvent = (firebase, dispatch, { type, path, populates, queryPar
8585
if (snapshot.val() !== null) {
8686
const ordered = []
8787
snapshot.forEach((child) => {
88-
ordered.push({ key: child.key, ...child.val() })
88+
ordered.push({ key: child.key, value: child.val() })
8989
})
9090
dispatch({
9191
type: SET,
@@ -112,10 +112,10 @@ export const watchEvent = (firebase, dispatch, { type, path, populates, queryPar
112112
// create an array for preserving order of children under ordered
113113
const ordered = []
114114
if (e === 'child_added') {
115-
ordered.push({ key: snapshot.key, ...snapshot.val() })
115+
ordered.push({ key: snapshot.key, value: snapshot.val() })
116116
} else {
117117
snapshot.forEach((child) => {
118-
ordered.push({ key: child.key, ...child.val() })
118+
ordered.push({ key: child.key, value: child.val() })
119119
})
120120
}
121121

src/helpers.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,10 @@ export const buildChildList = (state, list, p) =>
105105
if (val === true) {
106106
getKey = key
107107
}
108+
const dotRoot = compact(p.root.split('/')).join('.')
108109
const pathString = p.childParam
109-
? `${p.root}.${getKey}.${p.childParam}`
110-
: `${p.root}.${getKey}`
111-
112-
// console.log('path string:', { pathString, state })
110+
? `${dotRoot}.${getKey}.${p.childParam}`
111+
: `${dotRoot}.${getKey}`
113112
// Set to child under key if populate child exists
114113
if (get(state.data, pathString)) {
115114
return p.keyProp
@@ -155,7 +154,7 @@ export const populate = (state, path, populates, notSetValue) => {
155154
return notSetValue
156155
}
157156
// test if data is a single object vs a list of objects, try generating
158-
// populates and testing for key presence
157+
// populates and testing for key existence
159158
const populatesForData = getPopulateObjs(
160159
isFunction(populates)
161160
? populates(last(split(path, '/')), get(data, dotPath))
@@ -171,9 +170,10 @@ export const populate = (state, path, populates, notSetValue) => {
171170
// populate child is key
172171
if (isString(get(get(data, dotPath), p.child))) {
173172
const key = get(get(data, dotPath), p.child)
173+
const dotRoot = compact(p.root.split('/')).join('.')
174174
const pathString = p.childParam
175-
? `${p.root}.${key}.${p.childParam}`
176-
: `${p.root}.${key}`
175+
? `${dotRoot}.${key}.${p.childParam}`
176+
: `${dotRoot}.${key}`
177177

178178
if (get(data, pathString)) {
179179
return set({}, p.child, p.keyProp
@@ -211,9 +211,10 @@ export const populate = (state, path, populates, notSetValue) => {
211211
if (isString(get(child, p.child))) {
212212
const key = get(child, p.child)
213213
// attach child paramter if it exists
214+
const dotRoot = compact(p.root.split('/')).join('.')
214215
const pathString = p.childParam
215-
? `${p.root}.${key}.${p.childParam}`
216-
: `${p.root}.${key}`
216+
? `${dotRoot}.${key}.${p.childParam}`
217+
: `${dotRoot}.${key}`
217218
if (get(data, pathString)) {
218219
return set({}, p.child, (p.keyProp
219220
? { [p.keyProp]: key, ...get(data, pathString) }

src/utils/populate.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,11 @@ export const promisesForPopulate = (firebase, dataKey, originalData, populatesIn
131131
let results = {}
132132

133133
// test if data is a single object, try generating populates and looking for the child
134-
const populatesForData = getPopulateObj(isFunction(populatesIn)
135-
? populatesIn(dataKey, originalData)
136-
: populatesIn)
134+
const populatesForData = getPopulateObjs(
135+
isFunction(populatesIn)
136+
? populatesIn(dataKey, originalData)
137+
: populatesIn
138+
)
137139

138140
const dataHasPopulateChilds = every(populatesForData, (populate) => (
139141
has(originalData, populate.child)

0 commit comments

Comments
 (0)