Skip to content

Instantly share code, notes, and snippets.

@b2whats
Forked from nickbalestra/duck-on-wheels.js
Created December 28, 2016 22:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save b2whats/017b3ab98671a9fc2ece1d1132758af8 to your computer and use it in GitHub Desktop.
Save b2whats/017b3ab98671a9fc2ece1d1132758af8 to your computer and use it in GitHub Desktop.
An example of Duck Redux Reducer Bundle with Cycle.js apps to handle async
import xs from 'xstream'
import { combineCycles } from 'redux-cycle-middleware'
import { push } from 'react-router-redux'
import { API_URL } from '../constants/api'
// ACTION TYPES (Format: app-name/reducer/ACTION_TYPE)
// =======================================================
const LOGIN = 'app-name/auth/LOGIN'
const LOGIN_SUCCESS = 'app-name/auth/LOGIN_SUCCESS'
const LOGIN_FAIL = 'app-name/auth/LOGIN_FAIL'
export const LOGOUT = 'app-name/auth/LOGOUT'
// ACTION CREATORS
// =======================================================
export function doLogin (email, password) {
return {
type: LOGIN,
payload: {
email,
password
}
}
}
export function doLogout (msg) {
return {
type: LOGOUT,
payload: msg
}
}
function loginSuccess (token) {
return {
type: LOGIN_SUCCESS,
payload: token
}
}
// REDUCER
// =======================================================
const initialState = {
inProgress: false,
token: null,
error: null
}
export default function reducer (state = initialState, {type, payload}) {
switch (type) {
case LOGIN:
return {...state, inProgress: true}
case LOGIN_SUCCESS:
return {...state, inProgress: false, token: payload}
case LOGIN_FAIL:
return {...state, inProgress: false, error: payload}
case LOGOUT:
return {...state, token: null, inProgress: false, error: payload}
default:
return state
}
}
// CYCLE
// =======================================================
const cycleLogin = (sources) => {
function networking (sources) {
const loginAction$ = sources.ACTION
.filter(({ type }) => type === LOGIN)
const request$ = loginAction$
.map(({payload}) => ({
url: `${API_URL}/login`,
method: 'POST',
category: LOGIN,
headers: {
'Content-Type': 'application/json'
},
send: {
'email': payload.email,
'password': payload.password
}
}))
return request$
}
function intent (sources) {
const action$ = sources.HTTP
.select(LOGIN)
.map((response$) =>
response$.replaceError((error) =>
xs.of(error.response)
))
.flatten()
.map((res) =>
res.error
? {
type: LOGIN_FAIL,
payload: res.error,
error: true
}
: loginSuccess(res.body.accessToken)
)
return action$
}
return {
ACTION: intent(sources),
HTTP: networking(sources)
}
}
const cycleLoginSuccess = (sources) => {
function intent (sources) {
return sources.ACTION
.filter(({type}) => type === LOGIN_SUCCESS)
.mapTo(push('/'))
}
return {
ACTION: intent(sources)
}
}
const cycleLogout = (sources) => {
function intent (sources) {
return sources.ACTION
.filter(({type}) => type === LOGOUT)
.mapTo(push('/login'))
}
return {
ACTION: intent(sources)
}
}
const cycleLoginFail = (sources) => {
function intent (sources) {
return sources.ACTION
.filter(({type}) => type === LOGIN_FAIL)
.mapTo(doLogout())
}
return {
ACTION: intent(sources)
}
}
export const cycle = combineCycles(
cycleLogin,
cycleLoginSuccess,
cycleLogout,
cycleLoginFail
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment