Created
June 28, 2018 17:33
-
-
Save stevenleeg/f95208060e35c4f624d51d90cf717673 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {generateRestfulTransitions} from 'utils/restful-transitions'; | |
import translateTransitions from 'utils/translate-transitions'; | |
const { | |
transitions: restfulTransitions, | |
initialState: restfulInitialState, | |
} = generateRestfulTransitions({ | |
singularNoun: 'client', | |
pluralNoun: 'clients', | |
}); | |
export const initialState = restfulInitialState; | |
export const { | |
Actions: ClientActions, | |
ActionTypes: ClientActionTypes, | |
reducers, | |
saga, | |
prefix, | |
} = translateTransitions({ | |
prefix: 'services/clients', | |
transitions: restfulTransitions, | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Immutable from 'immutable'; | |
import {call, put, select, take} from 'redux-saga/effects'; | |
import WSApi from 'utils/ws-api'; | |
import {isLoading} from './restful-selectors'; | |
export const generateRestfulTransitions = ({ | |
// singularNoun, | |
pluralNoun, | |
// apiNoun, | |
urlGenerator, | |
}) => { | |
const generateRoute = ({path, urlParams}) => { | |
path = path === '/' ? '' : path; | |
const base = urlGenerator ? | |
urlGenerator({params: urlParams}) : `/${pluralNoun}`; | |
return `${base}${path}`; | |
}; | |
const initialState = Immutable.fromJS({ | |
loading: { | |
fetchItems: false, | |
fetchItem: false, | |
}, | |
items: [], | |
}); | |
const transitions = [ | |
/** | |
* fetchItems - Calls the index endpoint for the resource | |
*/ | |
{ | |
name: 'fetchItems', | |
generateAsync: true, | |
* saga({Actions}, {queryParams = {}, urlParams = {}, persist = true}) { | |
let resp; | |
try { | |
resp = yield call(WSApi.get, { | |
params: { | |
...queryParams, | |
}, | |
route: generateRoute({urlParams, path: '/'}), | |
}); | |
} catch (error) { | |
yield put(Actions.fetchItemsFailure({error})); | |
return; | |
} | |
const {data, included, pagination} = resp; | |
const items = data.map((item) => { | |
return WSApi.parseApiItem({item, included}); | |
}); | |
yield put(Actions.fetchItemsSuccess({ | |
items, | |
persist, | |
pagination, | |
queryParams, | |
urlParams, | |
})); | |
}, | |
beginReducer(state) { | |
return state | |
.setIn(['loading', 'fetchItems'], true) | |
.merge({items: new Immutable.List()}); | |
}, | |
successReducer(state, {items}) { | |
return state | |
.setIn(['loading', 'fetchItems'], false) | |
.merge({items}); | |
}, | |
failureReducer(state) { | |
return state.setIn(['loading', 'fetchItems'], false); | |
}, | |
}, | |
/** | |
* fetchItem - Calls the index endpoint for the resource | |
*/ | |
{ | |
name: 'fetchItem', | |
generateAsync: true, | |
* saga({Actions, ActionTypes}, {id, queryParams = {}, urlParams = {}}) { | |
let resp; | |
try { | |
resp = yield call(WSApi.get, { | |
route: generateRoute({urlParams, path: `/${id}`}), | |
params: queryParams, | |
}); | |
} catch (error) { | |
yield put(Actions.fetchItemFailure({error})); | |
return; | |
} | |
// If we're loading an index let's wait for it to finish, otherwise we | |
// might get into a race condition and override data. | |
const loadingItems = yield select(isLoading, { | |
service: pluralNoun, | |
op: 'fetchItems', | |
}); | |
if (loadingItems) { | |
yield take([ | |
ActionTypes.FETCH_ITEMS_SUCCESS, | |
ActionTypes.FETCH_ITEMS_FAILURE, | |
]); | |
} | |
const {data, included} = resp; | |
const item = WSApi.parseApiItem({item: data, included}); | |
yield put(Actions.fetchItemSuccess({item})); | |
}, | |
beginReducer(state, {silent = false}) { | |
return state | |
.merge({errors: new Immutable.List()}) | |
.setIn(['loading', 'fetchItem'], !silent); | |
}, | |
successReducer(state, {item}) { | |
let items = state.get('items'); | |
const existingIndex = items.findIndex(i => i.get('id') === item.get('id')); | |
if (existingIndex !== -1) { | |
items = items.set(existingIndex, item); | |
} else { | |
items = items.push(item); | |
} | |
return state | |
.merge({items}) | |
.setIn(['loading', 'fetchItem'], false); | |
}, | |
failureReducer(state) { | |
return state.setIn(['loading', 'fetchItem'], false); | |
}, | |
}, | |
]; | |
return {transitions, initialState}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment