Skip to content

Commit 10b3448

Browse files
committed
add basic patterns
1 parent 267bf05 commit 10b3448

22 files changed

+1723
-0
lines changed

.flowconfig

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[ignore]
2+
3+
.*/node_modules/react-native-firebase/.*

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

__tests__/actions.js

Whitespace-only changes.

__tests__/reducer.js

Whitespace-only changes.

actions.js

Whitespace-only changes.

createReducer.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@flow
2+
3+
export default function createReducer(initialState: Object, handlers: Object) {
4+
return function reducer(state: Object = initialState, action: { type: string }) {
5+
if (handlers.hasOwnProperty(action.type)) {
6+
return handlers[action.type](state, action)
7+
} else {
8+
return state
9+
}
10+
}
11+
}

firebase.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import RNFirebase from 'react-native-firebase'
2+
3+
const configurationOptions = {
4+
debug: false
5+
}
6+
7+
firebase = RNFirebase.initializeApp(configurationOptions)
8+
9+
export default firebase

package.json

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"devDependencies": {
3+
"babel-cli": "^6.24.1",
4+
"babel-preset-flow": "^6.23.0",
5+
"flow-bin": "^0.47.0"
6+
},
7+
"dependencies": {
8+
"react-native-firebase": "^1.1.0"
9+
}
10+
}

patterns/firebase_listen.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//@flow
2+
3+
import firebase from '../firebase'
4+
5+
firebase.database().ref('messages').on('value', (snap) => {
6+
//do something with snap
7+
})

patterns/generic_actions.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//@flow
2+
3+
import firebase from '../firebase'
4+
5+
export function listenRequested(metaType: string) {
6+
return {
7+
type: 'FIREBASE_LISTEN_REQUESTED',
8+
metaType,
9+
}
10+
}
11+
12+
export function listenFulfilled(metaType: string, items: Object) {
13+
return {
14+
type: 'FIREBASE_LISTEN_FULFILLED',
15+
metaType,
16+
items
17+
}
18+
}
19+
20+
type Action = {
21+
type: string,
22+
metaType: string,
23+
items?: Object
24+
}
25+
26+
export function listenToPath(metaType: string, path: string) {
27+
return (dispatch: (Action => void)) => {
28+
dispatch(listenRequested(metaType))
29+
firebase.database().ref(path)
30+
.on('value', (snap) => {
31+
dispatch(listenFulfilled(metaType, snap.val()))
32+
})
33+
}
34+
}
35+
36+
export function listenToMessages() {
37+
return listenToPath('messages', 'messages')
38+
}
39+
export function listenToUserContacts() {
40+
return listenToPath('userContacts', 'user/contacts')
41+
}

patterns/generic_reducer.js

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//@flow
2+
3+
import createReducer from '../createReducer'
4+
5+
export const metaTypes = {
6+
messages: 'messages',
7+
userContacts: 'userContacts',
8+
}
9+
10+
function getInitialState() {
11+
let initialState = { }
12+
Object.keys(metaTypes).forEach((metaType) => {
13+
initialState[metaType] = { inProgress: false, items: { } }
14+
})
15+
16+
return initialState
17+
}
18+
19+
const initialState = getInitialState()
20+
21+
export const reducer = createReducer(initialState, {
22+
['FIREBASE_LISTEN_REQUESTED'](state, action) {
23+
const newState = {
24+
...state,
25+
[action.metaType]: { inProgress: true, items: { } }
26+
}
27+
return newState
28+
},
29+
['FIREBASE_LISTEN_FULFILLED'](state, action) {
30+
const newState = {
31+
...state,
32+
[action.metaType]: { inProgress: true, items: action.items }
33+
}
34+
return newState
35+
},
36+
})
+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//@flow
2+
3+
import firebase from '../firebase'
4+
5+
export function listenRequested(metaType: string) {
6+
return {
7+
type: 'FIREBASE_LISTEN_REQUESTED',
8+
metaType
9+
}
10+
}
11+
export function listenRejected(metaType: string, error: string) {
12+
return {
13+
type: 'FIREBASE_LISTEN_REJECTED',
14+
metaType,
15+
error
16+
}
17+
}
18+
export function listenFulfilled(metaType: string, items: Object) {
19+
return {
20+
type: 'FIREBASE_LISTEN_FULFILLED',
21+
metaType,
22+
items
23+
}
24+
}
25+
export function listenChildAdded(metaType: string, id: string, value: Object) {
26+
return {
27+
type: 'FIREBASE_LISTEN_CHILD_ADDED',
28+
metaType,
29+
id,
30+
value,
31+
}
32+
}
33+
export function listenChildChanged(metaType: string, id: string, value: Object) {
34+
return {
35+
type: 'FIREBASE_LISTEN_CHILD_CHANGED',
36+
metaType,
37+
id,
38+
value,
39+
}
40+
}
41+
export function listenChildRemoved(metaType: string, id: string) {
42+
return {
43+
type: 'FIREBASE_LISTEN_CHILD_REMOVED',
44+
metaType,
45+
id,
46+
}
47+
}
48+
49+
type Action = {
50+
type: string,
51+
metaType: string,
52+
error?: string,
53+
items?: Object,
54+
id?: string,
55+
value?: Object,
56+
}
57+
58+
export function listenToPath(path: string, metaType: string) {
59+
return (dispatch: Action => void, getState: () => Object) => {
60+
const ref = firebase.database().ref(path)
61+
dispatch(listenRequested(metaType))
62+
ref.on('child_added', (snap) => {
63+
if (getState().database[metaType].inProgress) {
64+
return
65+
}
66+
const val: Object = snap.val()
67+
dispatch(listenChildAdded(metaType, snap.key, val))
68+
})
69+
ref.on('child_changed', (snap) => {
70+
if (getState().database[metaType].inProgress) {
71+
return
72+
}
73+
const val: Object = snap.val()
74+
dispatch(listenChildChanged(metaType, snap.key, val))
75+
})
76+
ref.on('child_removed', (snap) => {
77+
if (getState().database[metaType].inProgress) {
78+
return
79+
}
80+
dispatch(listenChildRemoved(metaType, snap.key))
81+
})
82+
return ref.once('value').then(snap => {
83+
//better to have an empty object then a null
84+
//value if data does not exist
85+
const val = snap.val()
86+
const value = val ? val : { }
87+
dispatch(listenFulfilled(metaType, value))
88+
})
89+
.catch(error => {
90+
dispatch(listenRejected(metaType, error))
91+
})
92+
}
93+
}
+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//@flow
2+
3+
import createReducer from '../createReducer'
4+
5+
export const metaTypes = {
6+
messages: 'messages',
7+
userContacts: 'userContacts',
8+
}
9+
10+
function getInitialState() {
11+
let initialState = { }
12+
Object.keys(metaTypes).forEach((metaType) => {
13+
initialState[metaType] = { inProgress: false, items: { } }
14+
})
15+
16+
return initialState
17+
}
18+
19+
const initialState = getInitialState()
20+
21+
export const reducer = createReducer(initialState, {
22+
['FIREBASE_LISTEN_REQUESTED'](state, action) {
23+
const newState = {
24+
...state,
25+
[action.metaType]: {
26+
inProgress: true, error: '', items: { }
27+
}
28+
}
29+
return newState
30+
},
31+
['FIREBASE_LISTEN_FULFILLED'](state, action) {
32+
const newState = {
33+
...state,
34+
[action.metaType]: {
35+
inProgress: true, error: '', items: action.items
36+
}
37+
}
38+
return newState
39+
},
40+
['FIREBASE_LISTEN_REJECTED'](state, action) {
41+
const error = action.error
42+
const newState = {
43+
...state,
44+
[action.metaType]: { inProgress: false, error, items: { } }
45+
}
46+
return newState
47+
},
48+
['FIREBASE_LISTEN_CHILD_ADDED'](state, action) {
49+
const currentItems = state[action.metaType].items
50+
const items = { ...currentItems, [action.id]: action.value }
51+
const newState = {
52+
...state,
53+
[action.metaType]: { inProgress: false, error: '', items }
54+
}
55+
return newState
56+
},
57+
['FIREBASE_LISTEN_CHILD_CHANGED'](state, action) {
58+
const currentItems = state[action.metaType].items
59+
const items = { ...currentItems, [action.id]: action.value }
60+
const newState = {
61+
...state,
62+
[action.metaType]: { inProgress: false, error: '', items }
63+
}
64+
return newState
65+
},
66+
['FIREBASE_LISTEN_CHILD_REMOVED'](state, action) {
67+
const currentItems = state[action.metaType].items
68+
const items = { ...currentItems }
69+
delete items[action.id]
70+
const newState = {
71+
...state,
72+
[action.metaType]: { inProgress: false, error: '', items }
73+
}
74+
return newState
75+
},
76+
})

patterns/listen_requested_with_ref.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@flow
2+
3+
export function listenRequested(metaType: string, ref: Object) {
4+
return {
5+
type: 'FIREBASE_LISTEN_REQUESTED',
6+
metaType,
7+
ref
8+
}
9+
}

patterns/listen_to_path_with_ref.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const ref = firebase.database().ref(path)
2+
dispatch(listenRequested(metaType, ref))

patterns/messages_actions.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@flow
2+
3+
import firebase from '../firebase'
4+
5+
export function messagesRequested() {
6+
return {
7+
type: 'MESSAGES_REQUESTED'
8+
}
9+
}
10+
export function messagesFulfilled(items: Object) {
11+
return {
12+
type: 'MESSAGES_FULFILLED',
13+
items,
14+
}
15+
}
16+
17+
type Action = {
18+
type: string,
19+
items?: Object
20+
}
21+
22+
export function listenToMessages() {
23+
return (dispatch: (Action => void)) => {
24+
dispatch(messagesRequested())
25+
firebase.database().ref('messages')
26+
.on('value', (snap) => {
27+
dispatch(messagesFulfilled(snap.val()))
28+
})
29+
}
30+
}

patterns/messages_reducers.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@flow
2+
3+
import createReducer from '../createReducer'
4+
5+
const initialState = { messages: { inProgress: false, items: { } } }
6+
7+
export const reducer = createReducer(initialState, {
8+
['MESSAGES_REQUESTED'](state, action) {
9+
const newState = { ...state,
10+
messages: { inProgress: true, items: { } }
11+
}
12+
return newState
13+
},
14+
['MESSAGES_FULFILLED'](state, action) {
15+
const newState = { ...state,
16+
messages: { inProgress: false, items: action.items }
17+
}
18+
return newState
19+
},
20+
})

patterns/remove_listener_actions.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@flow
2+
3+
export function listenRemoved(metaType: string) {
4+
return {
5+
type: 'FIREBASE_LISTEN_REMOVED',
6+
metaType,
7+
}
8+
}
9+
export function removeListenerRef(state: Object, metaType: string) {
10+
if (state && state.database && state.database[metaType] &&
11+
state.database[metaType].ref) {
12+
return state.database[metaType].ref.off()
13+
}
14+
return Promise.resolve()
15+
}
16+
17+
type Action = {
18+
type: string,
19+
metaType: string,
20+
}
21+
22+
export function removeListener(metaType: string) {
23+
return (dispatch: Action => void, getState: () => Object) => {
24+
return removeListenerRef(getState(), metaType).then(() => {
25+
dispatch(listenRemoved(metaType))
26+
})
27+
}
28+
}

0 commit comments

Comments
 (0)