Skip to content

Commit 5e39750

Browse files
authored
* fix(auth): `signInWithPhoneNumber` method fixed - prescottprue#374 * feat(auth): `login` supports `signInWithPhoneNumber` by passing `phoneNumber` and `applicationVerifier` * feat(examples): material example includes example usage of `login` using `phoneNumber` (multi step process unlike other usage of `login`) * feat(docs): auth docs updated with `signInWithPhoneNumber` and additions to `login`
1 parent a7de6ae commit 5e39750

File tree

23 files changed

+420
-332
lines changed

23 files changed

+420
-332
lines changed

README.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -288,15 +288,15 @@ Join us on the [redux-firebase gitter](https://gitter.im/redux-firebase/Lobby).
288288

289289
View docs for recipes on integrations with:
290290

291-
* [redux-firestore](/docs/firestore.md)
292-
* [redux-thunk](/docs/integrations/thunks.md)
293-
* [redux-observable](/docs/integrations/epics.md)
294-
* [redux-saga](/docs/integrations/redux-saga.md)
295-
* [redux-form](/docs/integrations/redux-form.md)
296-
* [redux-auth-wrapper](/docs/integrations/routing.md#advanced)
297-
* [redux-persist](/docs/integrations/redux-persist.md) - [improved integration with `v2.0.0`](http://docs.react-redux-firebase.com/history/v2.0.0/docs/integrations/redux-persist.html)
291+
* [redux-firestore](http://react-redux-firebase.com/docs/firestore.md)
292+
* [redux-thunk](http://react-redux-firebase.com/docs/integrations/thunks.md)
293+
* [redux-observable](http://react-redux-firebase.com/docs/integrations/epics.md)
294+
* [redux-saga](http://react-redux-firebase.com/docs/integrations/redux-saga.md)
295+
* [redux-form](http://react-redux-firebase.com/docs/integrations/redux-form.md)
296+
* [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)
298298
* [react-native](/docs/integrations/react-native.md)
299-
* [react-native-firebase](http://docs.react-redux-firebase.com/history/v2.0.0/docs/integrations/react-native.html#native-modules) - requires `v2.0.0`
299+
* [react-native-firebase](http://react-redux-firebase.com/docs/integrations/react-native.html#native-modules) - requires `v2.0.0`
300300

301301
## Firestore
302302

docs/auth.md

+39-7
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export default firebaseConnect()(SomeComponent) // or withFirebase(SomeComponent
6969
* credential (runs `ref.signInWithCredential(credential)`) :
7070
```js
7171
{
72-
credential : firebase.auth.AuthCredential // created using specific provider
72+
credential : [firebase.auth.AuthCredential](https://firebase.google.com/docs/reference/js/firebase.auth.AuthCredential.html) // created using specific provider
7373
}
7474
```
7575
The credential parameter is a firebase.auth.AuthCredential specific to the provider (i.e. `firebase.auth.GoogleAuthProvider.credential(null, 'some accessToken')`). For more details [please view the Firebase API reference](https://firebase.google.com/docs/reference/js/firebase.auth.GoogleAuthProvider#methods)
@@ -87,6 +87,13 @@ export default firebaseConnect()(SomeComponent) // or withFirebase(SomeComponent
8787
profile: Object // required (optional if updateProfileOnLogin: false config set)
8888
}
8989
```
90+
* phone number (runs `ref.signInWithPhoneNumber(phoneNumber, applicationVerifier)`). Automatic profile creation is enabled by default if you are using the `userProfile` config option. `updateProfileOnLogin` config option can be set to `false` in order to prevent this behavior.
91+
```js
92+
{
93+
phoneNumber: String,
94+
applicationVerifier: [`firebase.auth.ApplicationVerifier`](https://firebase.google.com/docs/reference/js/firebase.auth.ApplicationVerifier.html)
95+
}
96+
```
9097

9198
##### Returns
9299
[**Promise**][promise-url] that resolves with the response from firebase's login method (an [**Object**][object-url]). `credential` property is also included if using oAuth provider.
@@ -121,7 +128,7 @@ props.firebase.login({
121128

122129
*Credential*
123130
```js
124-
// `googleUser` from the onsuccess Google Sign In callback.
131+
// `googleUser` from the onsuccess Google Sign In callback
125132
props.firebase.login({
126133
credential: firebase.auth.GoogleAuthProvider.credential(googleUser.getAuthResponse().id_token)
127134
})
@@ -257,23 +264,48 @@ props.firebase.verifyPasswordResetCode('some reset code')
257264
258265
259266
## signInWithPhoneNumber(code)
260-
Verify a password reset code from password reset email.
261267
262-
Calls Firebase's `firebase.auth().signInWithPhoneNumber()`. If there is an error, it is added into redux state under `state.firebase.authError`.
268+
Signs in using a phone number in an async pattern (i.e. requires calling a second method). Calls Firebase's [`firebase.auth().signInWithPhoneNumber()`](https://firebase.google.com/docs/reference/js/firebase.auth.Auth#signInWithPhoneNumber). If there is an error, it is added into redux state under `state.firebase.authError`.
269+
270+
From Firebase's docs:
271+
272+
> Asynchronously signs in using a phone number. This method sends a code via SMS to the given phone number, and returns a [firebase.auth.ConfirmationResult](https://firebase.google.com/docs/reference/js/firebase.auth.ConfirmationResult.html). After the user provides the code sent to their phone, call [firebase.auth.ConfirmationResult#confirm](https://firebase.google.com/docs/reference/js/firebase.auth.ConfirmationResult.html#confirm) with the code to sign the user in.
273+
274+
For more info, check out the following:
275+
* [Firebase's phone-auth guide](https://firebase.google.com/docs/auth/web/phone-auth)
276+
* [Firebase's auth docs reference for signInWithPhoneNumber](https://firebase.google.com/docs/reference/js/firebase.auth.Auth#signInWithPhoneNumber)
263277
264278
##### Examples
265279
266280
```js
267-
props.firebase.signInWithPhoneNumber('some reset code')
281+
const phoneNumber = "+11234567899" // for US number (123) 456-7899
282+
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
283+
'size': 'invisible',
284+
});
285+
firebase.signInWithPhoneNumber(phoneNumber, appVerifier)
286+
.then((confirmationResult) => {
287+
// SMS sent. Prompt user to type the code from the message, then sign the
288+
// user in with confirmationResult.confirm(code).
289+
const verificationCode = window.prompt('Please enter the verification ' +
290+
'code that was sent to your mobile device.');
291+
return confirmationResult.confirm(verificationCode);
292+
})
293+
.catch((error) => {
294+
// Error; SMS not sent
295+
// Handle Errors Here
296+
return Promise.reject(error)
297+
});
268298
```
269299
270300
##### Parameters
271-
* `code` [**String**][string-url] - Password reset code
301+
* `phoneNumber` [**String**][string-url] - The user's phone number in E.164 format (e.g. `+16505550101`).
302+
* `applicationVerifier` [**firebase.auth.ApplicationVerifier**][firebase-app-verifier] `required` - App verifier made with Firebase's `RecaptchaVerifier`
272303
273304
##### Returns
274-
[**Promise**][promise-url] - Email associated with reset code
305+
[**Promise**][promise-url] - Resolves with [firebase.auth.ConfirmationResult](https://firebase.google.com/docs/reference/js/firebase.auth.ConfirmationResult.html)
275306
276307
277308
[promise-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
278309
[string-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
279310
[object-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
311+
[firebase-app-verifier]: https://firebase.google.com/docs/reference/js/firebase.auth.ApplicationVerifier.html

docs/getting_started.md

-5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@
22

33
## Before Use
44

5-
## Install
6-
```bash
7-
npm install --save react-redux-firebase
8-
```
9-
105
### Peer Dependencies
116

127
Install peer dependencies: `npm i --save redux react-redux`

docs/integrations/react-native.md

+1-190
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Passing in an instance also allows for libraries with similar APIs (such as [`re
4646
};
4747
```
4848

49-
Full `react-native-firebase` example app source with styling available [in the react-native-firebase complete example](https://github.com/prescottprue/react-redux-firebase/tree/v2.0.0/examples/complete/react-native-firebase).
49+
Full `react-native-firebase` example app source with styling available [in the react-native-firebase complete example](https://github.com/prescottprue/react-redux-firebase/tree/master/examples/complete/react-native-firebase).
5050

5151
### Setup
5252
1. Run `create-react-native-app my-app`
@@ -77,195 +77,6 @@ Instantiate a Firebase instance outside of `react-redux-firebase` then pass it i
7777
1. Copy your client id out of the `GoogleService-info.plist` file (should end in `.apps.googleusercontent.com`)
7878
1. Place the client id into `iosClientId` variable within the example
7979

80-
## Example App Snippets
81-
82-
This snippet is a condensed version of [react-native complete example](/examples/complete/react-native).
83-
84-
**NOTE**: The API used in this snippet [changes in `v2.0.0`](http://docs.react-redux-firebase.com/history/v2.0.0/docs/recipes/react-native.html#jsweb), if you are starting a new project, the new syntax is suggested
85-
86-
**store.js**
87-
```js
88-
import * as firebase from 'firebase/app'
89-
import 'firebase/auth'
90-
import 'firebase/database'
91-
import 'firebase/storage'
92-
93-
const fbConfig = {} // object containing Firebase config
94-
firebase.initializeApp(fbConfig) // initialize firebase instance
95-
const reduxConfig = {
96-
enableRedirectHandling: false // required
97-
}
98-
99-
const store = createStore(
100-
reducer,
101-
undefined,
102-
compose(
103-
reactReduxFirebase(firebase, reduxConfig), // pass in firebase instance instead of config
104-
applyMiddleware(...middleware)
105-
)
106-
)
107-
```
108-
import { createStore, compose } from 'redux'
109-
import rootReducer from './reducer'
110-
import { firebase as fbConfig } from './config'
111-
import { reactReduxFirebase } from 'react-redux-firebase'
112-
import { AsyncStorage } from 'react-native'
113-
114-
export default function configureStore (initialState, history) {
115-
// use compose to make a function that will create store
116-
const createStoreWithMiddleware = compose(
117-
reactReduxFirebase(fbConfig,
118-
{
119-
userProfile: 'users',
120-
enableLogging: false,
121-
ReactNative: { AsyncStorage },
122-
}
123-
)
124-
)(createStore)
125-
126-
// create store
127-
const store = createStoreWithMiddleware(rootReducer)
128-
129-
// Enable Webpack hot module replacement for reducers
130-
if (module.hot) {
131-
module.hot.accept('./reducer', () => {
132-
const nextRootReducer = require('./reducer')
133-
store.replaceReducer(nextRootReducer)
134-
})
135-
}
136-
137-
return store
138-
}
139-
```
140-
141-
**App.js**:
142-
143-
```js
144-
import React, { Component } from 'react'
145-
import { GoogleSignin, GoogleSigninButton } from 'react-native-google-signin'
146-
import { firebaseConnect, pathToJS, isLoaded } from 'react-redux-firebase'
147-
import { connect } from 'react-redux'
148-
import {
149-
AppRegistry,
150-
StyleSheet,
151-
Text,
152-
View,
153-
TouchableOpacity,
154-
} from 'react-native'
155-
import configureStore from './store'
156-
const initialState = { firebase: { authError: null, auth: undefined }}
157-
const store = configureStore(initialState)
158-
159-
const iosClientId = '499842460400-teaflfd8695oilltk5qkvl5688ebgq6b.apps.googleusercontent.com' // get this from plist file
160-
161-
const styles = StyleSheet.create({
162-
container: {
163-
flex: 1,
164-
justifyContent: 'center',
165-
alignItems: 'center',
166-
backgroundColor: '#F5FCFF',
167-
},
168-
welcome: {
169-
fontSize: 20,
170-
textAlign: 'center',
171-
margin: 10,
172-
},
173-
instructions: {
174-
textAlign: 'center',
175-
color: '#333333',
176-
marginBottom: 5,
177-
},
178-
})
179-
180-
@firebaseConnect()
181-
@connect(({ firebase }) => ({
182-
auth: pathToJS(firebase, 'auth', undefined)
183-
}))
184-
export default class GoogleSigninSampleApp extends Component {
185-
componentDidMount() {
186-
this._setupGoogleSignin()
187-
}
188-
189-
render() {
190-
const { auth } = this.props
191-
if (!isLoaded(auth)) {
192-
return (
193-
<View style={styles.container}>
194-
<Text>Loading...</Text>
195-
</View>
196-
)
197-
}
198-
if (!this.props.auth) {
199-
return (
200-
<View style={styles.container}>
201-
<GoogleSigninButton
202-
style={{width: 212, height: 48}}
203-
size={GoogleSigninButton.Size.Standard}
204-
color={GoogleSigninButton.Color.Auto}
205-
onPress={() => this._signIn()}
206-
/>
207-
</View>
208-
)
209-
}
210-
return (
211-
<View style={styles.container}>
212-
<Text style={{fontSize: 18, fontWeight: 'bold', marginBottom: 20}}>
213-
Welcome {this.props.auth.displayName}
214-
</Text>
215-
<Text>
216-
Your email is: {this.props.auth.email}</Text>
217-
218-
<TouchableOpacity onPress={() => {this._signOut() }}>
219-
<View style={{marginTop: 50}}>
220-
<Text>Log out</Text>
221-
</View>
222-
</TouchableOpacity>
223-
</View>
224-
)
225-
}
226-
227-
// based on react-native-google-signin example
228-
async _setupGoogleSignin() {
229-
try {
230-
await GoogleSignin.hasPlayServices({ autoResolve: true })
231-
await GoogleSignin.configure({
232-
iosClientId,
233-
offlineAccess: false
234-
})
235-
236-
const user = await GoogleSignin.currentUserAsync()
237-
const creds = this.props.firebase.auth.GoogleAuthProvider.credential(null, user.accessToken)
238-
await this.props.firebase.auth().signInWithCredential(creds)
239-
}
240-
catch(err) {
241-
console.log("Google signin error", err.code, err.message)
242-
}
243-
}
244-
245-
_signIn() {
246-
const { auth } = this.props.firebase
247-
return GoogleSignin.signIn()
248-
.then((user) => {
249-
const creds = auth.GoogleAuthProvider.credential(null, user.accessToken)
250-
return auth().signInWithCredential(creds)
251-
})
252-
.catch((err) => {
253-
console.error('error authing with firebase:', err)
254-
return Promise.reject(err)
255-
})
256-
}
257-
258-
_signOut() {
259-
return GoogleSignin.revokeAccess()
260-
.then(() => GoogleSignin.signOut())
261-
.then(() => this.props.firebase.logout())
262-
}
263-
}
264-
265-
AppRegistry.registerComponent('GoogleSigninSampleApp', () => GoogleSigninSampleApp)
266-
267-
```
268-
26980
## Creating Your Own
27081

27182
We are going to use the project name Devshare for example here. For your project, use your project name everywhere where Devshare is used.

examples/complete/material/src/constants.js

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const SIGNUP_PATH = '/signup'
77
export const ACCOUNT_FORM_NAME = 'account'
88
export const LOGIN_FORM_NAME = 'login'
99
export const SIGNUP_FORM_NAME = 'signup'
10+
export const PHONE_FORM_NAME = 'phone'
1011
export const NEW_PROJECT_FORM_NAME = 'newProject'
1112
export const RECOVER_CODE_FORM_NAME = 'recoverCode'
1213
export const RECOVER_EMAIL_FORM_NAME = 'recoverEmail'
@@ -16,6 +17,7 @@ export const formNames = {
1617
account: ACCOUNT_FORM_NAME,
1718
signup: SIGNUP_FORM_NAME,
1819
login: LOGIN_FORM_NAME,
20+
phone: PHONE_FORM_NAME,
1921
recoverCode: RECOVER_CODE_FORM_NAME,
2022
recoverEmail: RECOVER_EMAIL_FORM_NAME,
2123
newTodo: NEW_TODO_FORM_NAME

examples/complete/material/src/modules/notification/components/withNotifications.js

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const withNotifications = compose(
66
withStore,
77
withHandlers({
88
showError: ({ store }) => err => actions.showError(err)(store.dispatch),
9+
showSuccess: ({ store }) => err => actions.showSuccess(err)(store.dispatch),
910
dismissNotification: ({ store }) => id =>
1011
actions.dismissNotification(id)(store.dispatch)
1112
})

examples/complete/material/src/routes/Home/components/TodosList/TodosList.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,18 @@ import React from 'react'
22
import PropTypes from 'prop-types'
33
import { map } from 'lodash'
44
import { compose, withHandlers } from 'recompose'
5-
import { isLoaded, isEmpty, withFirebase } from 'react-redux-firebase'
5+
import { isEmpty, withFirebase } from 'react-redux-firebase'
66
import { List } from 'material-ui/List'
7-
import CircularProgress from 'material-ui/CircularProgress'
87
import Paper from 'material-ui/Paper'
98
import Subheader from 'material-ui/Subheader'
109
import { withNotifications } from 'modules/notification'
10+
import { spinnerWhileLoading } from 'utils/components'
1111
import TodoItem from '../TodoItem'
1212
import classes from './TodosList.scss'
1313

1414
const TodosList = ({ todos, toggleDone, deleteTodo }) => (
1515
<Paper className={classes.container}>
16-
{!isLoaded(todos) ? (
17-
<CircularProgress />
18-
) : !isEmpty(todos) ? (
16+
{!isEmpty(todos) ? (
1917
<div>
2018
<Subheader>Todos</Subheader>
2119
<List className={classes.list}>
@@ -31,7 +29,7 @@ const TodosList = ({ todos, toggleDone, deleteTodo }) => (
3129
</List>
3230
</div>
3331
) : (
34-
<div className={classes.list}>No Todos</div>
32+
<div className={classes.empty}>No Todos</div>
3533
)}
3634
</Paper>
3735
)
@@ -46,6 +44,7 @@ TodosList.propTypes = {
4644
export default compose(
4745
withFirebase, // firebaseConnect() can also be used
4846
withNotifications, // adds props.showError from notfication module
47+
spinnerWhileLoading(['todos']),
4948
withHandlers({
5049
toggleDone: props => (todo, id) => {
5150
const { firebase, auth } = props

examples/complete/material/src/routes/Home/components/TodosList/TodosList.scss

+3
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
min-width: 300px;
55
margin-bottom: 2rem;
66
}
7+
.empty {
8+
@extend .flex-row-center;
9+
}

0 commit comments

Comments
 (0)