Skip to content

Instantly share code, notes, and snippets.

@bradennapier
Created June 15, 2017 23:56
Show Gist options
  • Save bradennapier/57bdc528bdc8e53d709e6d2800c63ea2 to your computer and use it in GitHub Desktop.
Save bradennapier/57bdc528bdc8e53d709e6d2800c63ea2 to your computer and use it in GitHub Desktop.
Geolocation with Redux-Saga-Process
import { Process } from 'redux-saga-process'
import { call, put } from 'redux-saga/effects'
import { createSelector } from 'reselect'
import { createTaskManager } from 'saga-task-manager'
import startUserPositionObserver from 'saga-geolocation-observer'
import handleUserPosition from './sagas/handleUserPosition'
const nilLocation = {
accuracy: undefined,
latitude: undefined,
longitude: undefined,
lastUpdated: undefined
}
const build_type = (type, config) => `${config.types.prefix}_${config.types[type]}`
const build_config = config => ({
reduces: 'user',
pid: 'userLocation',
stateKey: 'location',
exports: [ 'actions', 'selectors' ],
autoStart: false,
log: false,
initialState: nilLocation,
positionOptions: {
enableHighAccuracy: true
},
...config,
actions: {
start: 'geolocationStart',
stop: 'geolocationStop',
...config.aations,
},
types: {
prefix: 'USER',
location: 'LOCATION',
...config.types,
},
})
export default (_config, callback) => {
const config = build_config(_config)
const processSelectors = {}
const stateKeySelector = state => state[config.reduces] && state[config.reduces][config.stateKey]
processSelectors.userLocation = createSelector(
stateKeySelector,
userLocation => ({
accuracy: userLocation.accuracy,
latitude: userLocation.latitude,
longitude: userLocation.longitude,
lastUpdated: userLocation.lastUpdated,
})
)
const processActionRoutes = {
[config.actions.stop]: 'handleStop',
[config.actions.start]: 'handleStart',
}
const processActionCreators = {
[config.actions.stop]: null,
[config.actions.start]: null,
}
const processInitialState = {
[config.stateKey]: config.initialState
}
const processReducer = {
[build_type('location', config)]: (state, action) => ({
...state,
[config.stateKey]: {
accuracy: action.accuracy,
latitude: action.latitude,
longitude: action.longitude,
lastUpdated: action.lastUpdated,
}
}),
}
const processConfig = {
pid: config.pid,
reduces: config.reduces,
}
return class GeoLocationProcess extends Process {
static config = processConfig;
static exports = config.exports
static initialState = processInitialState;
static actionCreators = processActionCreators;
static actionRoutes = processActionRoutes;
static selectors = processSelectors;
static reducer = processReducer;
constructor(processID, proc) {
super(processID, proc)
this.state = {
coords: undefined
}
this.task = createTaskManager(processID, {
name: build_type('location', config),
log: true
})
}
* handleStop() {
yield call([ this.task, this.task.cancel ], 'observers')
}
* handleStart() {
const handlers = {
onEvent: [ this, this.handleEvent ],
onError: [ this, this.handleError ],
onCancel: [ this, this.handleCancelled ],
}
yield* this.task.create(
'observers', 'geolocation',
startUserPositionObserver,
'user-geolocation-observer',
config.positionOptions,
handlers
)
}
* handleEvent(event, value, uid) {
switch(event) {
case 'watchPosition': {
const position = yield call([ this, handleUserPosition ], value)
if ( position ) {
yield put({
type: build_type('location', config),
...position
})
}
break
}
}
}
* handleError(event, error, uid) {
console.error(`[saga-process-geolocation]: ${error.message}`)
}
* handleCancelled(event, uid) {
console.warn('Geolocation Observer Cancelled')
// console.warn(event, uid)
}
* processStarts() {
if ( config.autoStart ) { yield call([ this, this.handleStart ]) }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment