Skip to content

Commit

Permalink
userKey -> userType
Browse files Browse the repository at this point in the history
  • Loading branch information
dpikt committed Aug 20, 2018
1 parent f375c7d commit eff6e05
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 45 deletions.
2 changes: 1 addition & 1 deletion src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createAction } from 'redux-actions'
const ACTION_NAMESPACE = '@@redux-sessions/'

export const setToken = createAction(ACTION_NAMESPACE + 'SET_TOKEN',
(token, { userKey, persist }={}) => ({ token, userKey, persist })
(token, { userType, persist }={}) => ({ token, userType, persist })
)

export const clearToken = createAction(ACTION_NAMESPACE + 'CLEAR_TOKEN')
Expand Down
4 changes: 3 additions & 1 deletion src/enhancer.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { saveSessionState } from './persistenceHelpers'
import { debounce } from 'lodash'

const DEFAULT_DEBOUNCE_INTERVAL = 500

// Adds storage functionality to sessions info
function enhancer ({ persist=true, debounceInterval=500 }={}) {
function enhancer ({ persist=true, debounceInterval=DEFAULT_DEBOUNCE_INTERVAL }={}) {
return function enhance (createStore) {
return function newCreateStore (...args) {
const store = createStore(...args)
Expand Down
57 changes: 38 additions & 19 deletions src/persistenceHelpers.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,59 @@
import { map, last, uniq, set } from 'lodash'
import { map, uniq, set } from 'lodash'
import { storage } from './utils'
import { get } from 'lodash/fp'

// Storage keys
/******************************************************
Helpers for saving/loading session info from storage
*******************************************************/

// This string prefixes the key of everything we store
const STORAGE_PREFIX = 'redux-sessions'

function tokenStorageKey (userKey) {
return STORAGE_PREFIX + ':token:' + userKey
// Creates a storage key for a given user type and the data type being stored.
// E.g. ('user', 'token') -> 'redux-sessions:user:token'
function serializeStorageKey (userType, dataType) {
return [ STORAGE_PREFIX, dataType, userType ].join(':')
}

function persistStorageKey (userKey) {
return STORAGE_PREFIX + ':persist:' + userKey
// Splits a storage key into its parts so we can retrieve info about what's being stored.
function deserializeStorageKey (storageKey) {
// eslint-disable-next-line
const [ _, dataType, userType ] = storageKey.split(':')
return { dataType, userType }
}

function getUserKeyFromStorageKey (storageKey) {
return last(storageKey.split(':'))
// Given a storage key, returns the user type.
function getUserTypeFromStorageKey (storageKey) {
const { userType } = deserializeStorageKey(storageKey)
return userType
}

// Storage helpers
// Returns the storage key for storing a user token.
function tokenStorageKey (userType) {
return serializeStorageKey(userType, 'token')
}

// Returns the storage key for storing a user's persistence.
function persistStorageKey (userType) {
return serializeStorageKey(userType, 'persist')
}

// Loads the redux state from local / session storage.
// We use the storage prefix to figure out which values we've saved.
export function loadSessionState () {
const userKeys = uniq(storage.getAllKeys()
.filter(key => key.startsWith(STORAGE_PREFIX))
.map(getUserKeyFromStorageKey))
const storageKeys = storage.getAllKeys().filter(key => key.startsWith(STORAGE_PREFIX))
const userTypes = uniq(storageKeys.map(getUserTypeFromStorageKey))
const state = {}
userKeys.forEach(userKey => set(state, userKey, {
token: storage.getItem(tokenStorageKey(userKey)),
persist: !!storage.getItem(persistStorageKey(userKey)),
userTypes.forEach(userType => set(state, userType, {
token: storage.getItem(tokenStorageKey(userType)),
persist: !!storage.getItem(persistStorageKey(userType)),
}))
return state
}

// Saves the redux state to local / session storage.
export function saveSessionState (state) {
return map(state, ({ token, persist }, userKey) => {
storage.setItem(tokenStorageKey(userKey), token, { persist })
storage.setItem(persistStorageKey(userKey), persist, { persist })
return map(state, ({ token, persist }, userType) => {
storage.setItem(tokenStorageKey(userType), token, { persist })
storage.setItem(persistStorageKey(userType), persist, { persist })
})
}
14 changes: 7 additions & 7 deletions src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@ import { set, get } from 'lodash/fp'
import * as actions from './actions'
import { loadSessionState } from './persistenceHelpers'

const DEFAULT_USER_KEY = 'user'
const DEFAULT_USER_TYPE = 'user'

// Reducer

const initialState = loadSessionState()

const reducer = handleActions({
[actions.setToken]: (state, { payload: { token, userKey=DEFAULT_USER_KEY, persist=true } }) => {
return set(userKey, { token, persist }, state)
[actions.setToken]: (state, { payload: { token, userType=DEFAULT_USER_TYPE, persist=true } }) => {
return set(userType, { token, persist }, state)
},
[actions.clearToken]: (state, { payload: { userKey=DEFAULT_USER_KEY }={}}) => {
return set(userKey, { token: null, persist: false }, state)
[actions.clearToken]: (state, { payload: { userType=DEFAULT_USER_TYPE }={}}) => {
return set(userType, { token: null, persist: false }, state)
},
}, initialState)

// Selectors

const selectors = {}

selectors.token = function (state, { userKey=DEFAULT_USER_KEY }={}) {
selectors.token = function (state, { userType=DEFAULT_USER_TYPE }={}) {
if (!get('sessions', state)) throw new Error('redux-sessions: state not found. Did you remember to attach the reducer at key `sessions`?')
return get('sessions.' + userKey + '.token', state)
return get('sessions.' + userType + '.token', state)
}

selectors.isAuthenticated = function (state, options) {
Expand Down
2 changes: 1 addition & 1 deletion test/persistenceHelpers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('loadSessionState()', () => {
const clientPersist = false
storage.setItem('redux-sessions:token:advisor', advisorToken)
storage.setItem('redux-sessions:persist:advisor', advisorPersist)
storage.setItem('something-else', 'baz')
storage.setItem('something-else', 'baz') // should be ignored
storage.setItem('redux-sessions:token:client', clientToken, { persist: false })
storage.setItem('redux-sessions:persist:client', clientPersist, { persist: false })
const state = loadSessionState()
Expand Down
30 changes: 15 additions & 15 deletions test/reducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ describe('actions.setToken()', () => {
const newState = reducer(initialState, action)
expect(newState.user.token).toEqual(token)
})
it('can receive a custom user key', () => {
it('can receive a custom user type', () => {
const token = 'foo'
const userKey = 'bar'
const userType = 'bar'
const initialState = {}
const action = actions.setToken(token, { userKey })
const action = actions.setToken(token, { userType })
const newState = reducer(initialState, action)
expect(newState.bar.token).toEqual(token)
})
Expand Down Expand Up @@ -47,10 +47,10 @@ describe('actions.clearToken()', () => {
const newState = reducer(initialState, action)
expect(newState.user.persist).toEqual(false)
})
it('can receive a custom user key', () => {
const userKey = 'bar'
it('can receive a custom user type', () => {
const userType = 'bar'
const initialState = { user: { token: 'foo' } }
const action = actions.clearToken({ userKey })
const action = actions.clearToken({ userType })
const newState = reducer(initialState, action)
expect(newState.user.token).toEqual('foo')
expect(newState.bar.token).toEqual(null)
Expand All @@ -69,11 +69,11 @@ describe('selectors.token()', () => {
const state = { sessions: { user: { token }}}
expect(selectors.token(state)).toEqual(token)
})
it('can receive a custom user key', () => {
it('can receive a custom user type', () => {
const token = 'foo'
const userKey = 'bar'
const userType = 'bar'
const state = { sessions: { bar: { token }}}
expect(selectors.token(state, { userKey })).toEqual(token)
expect(selectors.token(state, { userType })).toEqual(token)
})
})

Expand All @@ -91,11 +91,11 @@ describe('selectors.isAuthenticated()', () => {
const state = { sessions: {}}
expect(selectors.isAuthenticated(state)).toEqual(false)
})
it('can receive a custom user key', () => {
it('can receive a custom user type', () => {
const token = 'foo'
const userKey = 'bar'
const userType = 'bar'
const state = { sessions: { bar: { token }}}
expect(selectors.isAuthenticated(state, { userKey })).toEqual(true)
expect(selectors.isAuthenticated(state, { userType })).toEqual(true)
})
})

Expand All @@ -113,11 +113,11 @@ describe('selectors.isUnauthenticated()', () => {
const state = { sessions: {}}
expect(selectors.isUnauthenticated(state)).toEqual(true)
})
it('can receive a custom user key', () => {
it('can receive a custom user type', () => {
const token = 'foo'
const userKey = 'bar'
const userType = 'bar'
const state = { sessions: { bar: { token }}}
expect(selectors.isUnauthenticated(state, { userKey })).toEqual(false)
expect(selectors.isUnauthenticated(state, { userType })).toEqual(false)
})
})

Expand Down
2 changes: 1 addition & 1 deletion test/setup.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Storage from 'dom-storage'

// This file will be run before each individual test file.
// Here we use it to set up some storage mocks.
// Here we're using it to set up some storage mocks.

global.localStorage = new Storage(null, { strict: true })
global.sessionStorage = new Storage(null, { strict: true })

0 comments on commit eff6e05

Please sign in to comment.