1 | import { createSelector } from 'redux-bundler'
|
2 |
|
3 | const FIREBASE_CONNECTED = 'FIREBASE_CONNECTED'
|
4 | const FIREBASE_DISCONNECTED = 'FIREBASE_DISCONNECTED'
|
5 | const FIREBASE_AUTHED = 'FIREBASE_AUTHED'
|
6 | const FIREBASE_AUTHENTICATING = 'FIREBASE_AUTHENTICATING'
|
7 | export const FIREBASE_TOKEN_FAILED = 'FIREBASE_TOKEN_FAILED'
|
8 |
|
9 | export default (fb) => ({
|
10 | name: 'firebase',
|
11 | selectFirebaseState: state => state.firebase,
|
12 | selectFirebaseConnected: state => state.firebase.connected,
|
13 | selectFirebaseAuthed: state => state.firebase.authed,
|
14 | selectFirebaseAuthUserId: createSelector(
|
15 | 'selectFirebaseAuthed',
|
16 | (fbAuthed) => {
|
17 | const { currentUser } = fb.auth()
|
18 | return currentUser && currentUser.uid
|
19 | }
|
20 | ),
|
21 | doFirebaseAuth: (fbToken) => ({dispatch}) => {
|
22 | dispatch({type: FIREBASE_AUTHENTICATING})
|
23 | fb.auth().signInWithCustomToken(fbToken).then((user) => {
|
24 | dispatch({type: FIREBASE_AUTHED})
|
25 | })
|
26 | .catch((error) => {
|
27 | if (error.code === 'auth/invalid-custom-token') {
|
28 | dispatch({type: FIREBASE_TOKEN_FAILED})
|
29 | }
|
30 | })
|
31 | },
|
32 | getReducer: () => {
|
33 | const initialState = {
|
34 | connected: false,
|
35 | authed: !!fb.auth().currentUser,
|
36 | disconnectedAt: null,
|
37 | connectedAt: null,
|
38 | loggingIn: false
|
39 | }
|
40 | return (state = initialState, {type}) => {
|
41 | if (type === FIREBASE_DISCONNECTED) {
|
42 | return Object.assign({}, state, {
|
43 | connected: false,
|
44 | disconnectedAt: Date.now()
|
45 | })
|
46 | }
|
47 | if (type === FIREBASE_CONNECTED) {
|
48 | return Object.assign({}, state, {
|
49 | connected: true,
|
50 | connectedAt: Date.now()
|
51 | })
|
52 | }
|
53 | if (type === FIREBASE_AUTHED) {
|
54 | return Object.assign({}, state, {
|
55 | authed: true,
|
56 | loggingIn: false
|
57 | })
|
58 | }
|
59 | if (type === FIREBASE_TOKEN_FAILED) {
|
60 | return Object.assign({}, state, {
|
61 | authed: false,
|
62 | loggingIn: false
|
63 | })
|
64 | }
|
65 | if (type === FIREBASE_AUTHENTICATING) {
|
66 | return Object.assign({}, state, {
|
67 | loggingIn: true
|
68 | })
|
69 | }
|
70 | return state
|
71 | }
|
72 | },
|
73 | init: (store) => {
|
74 | fb.database().ref('.info/connected').on('value', (snap) => {
|
75 | if (snap.val()) {
|
76 | store.dispatch({type: FIREBASE_CONNECTED})
|
77 | } else if (store.selectFirebaseConnected()) {
|
78 | store.dispatch({type: FIREBASE_DISCONNECTED})
|
79 | }
|
80 | })
|
81 | },
|
82 | reactShouldAuthFirebase: createSelector(
|
83 | 'selectFirebaseToken',
|
84 | 'selectFirebaseState',
|
85 | (token, fb) => {
|
86 | if (token && !fb.authed && !fb.loggingIn) {
|
87 | return {actionCreator: 'doFirebaseAuth', args: [token]}
|
88 | }
|
89 | }
|
90 | )
|
91 | })
|