UNPKG

redux-search-filter

Version:

[![NPM version][npm-image]][npm-url] [![build status][travis-image]][travis-url] [![Test coverage][codecov-image]][codecov-url] [![npm download][download-image]][download-url]

164 lines (154 loc) 3.99 kB
import { Map } from 'immutable'; import { RESET, UPDATE_FILTER, SET_OPERATOR, SET_NEGATED } from './constants/actionTypes'; import * as kinds from './constants/kinds'; import { AND, OR } from './constants/operators'; const defaultMultipleFilter = { value: [], negated: false, operator: AND }; const defaultValueFilter = { value: [], negated: false, operator: OR }; export default function searchFilterReducer(state = new Map(), action) { let name, filters, filterName, filterProp; if (action.meta && action.meta.name) { name = action.meta.name; filters = state.get(name) || new Map(); filterProp = action.meta.prop; filterName = action.meta.filterName || filterProp; } switch (action.type) { case RESET: { return state.set(name, filters.clear()); } case UPDATE_FILTER: { if (action.payload === null) { return state.set(name, filters.delete(filterName)); } else { return state.set( name, filters.set( filterName, formatValue( action.meta.kind, filterProp, filters.get(filterName), action.payload ) ) ); } } case SET_NEGATED: { const oldValue = filters.get(filterName); if (oldValue && oldValue.negated === action.payload) { return state; } else { return state.set( name, filters.set( filterName, setNegated(action.meta.kind, filterProp, oldValue, action.payload) ) ); } } case SET_OPERATOR: { const oldValue = filters.get(filterName); if (oldValue && oldValue.operator === action.payload) { return state; } else { return state.set( name, filters.set( filterName, setOperator(action.meta.kind, filterProp, oldValue, action.payload) ) ); } } default: return state; } } function setNegated(kind, prop, filter, payload) { const result = { prop }; if (typeof payload !== 'boolean') { throw new TypeError( `SET_NEGATED expects a boolean value. Received ${typeof payload}` ); } switch (kind) { case kinds.value: case kinds.multiple: { return Object.assign(result, getDefaultFilter(kind), filter, { negated: payload }); } default: throw unexpectedKind(kind); } } function setOperator(kind, prop, filter, payload) { const result = { prop }; if (payload !== AND && payload !== OR) { throw new RangeError(`wrong operator: ${payload}`); } switch (kind) { case kinds.value: case kinds.multiple: { return Object.assign(result, getDefaultFilter(kind), filter, { operator: payload }); } default: throw unexpectedKind(kind); } } function formatValue(kind, prop, filter, payload) { const result = { prop }; switch (kind) { case kinds.value: case kinds.multiple: return Object.assign(result, getDefaultFilter(kind), filter, { value: Array.isArray(payload) ? payload : [payload] }); case kinds.range: { if ( typeof payload !== 'object' || payload === null || typeof payload.min !== 'number' || typeof payload.max !== 'number' ) { throw new TypeError('range value must have a min and a max'); } if (payload.min >= payload.max) { throw new RangeError('range min must be smaller than range max'); } return Object.assign(result, payload); } default: throw unexpectedKind(kind); } } function getDefaultFilter(kind) { switch (kind) { case kinds.multiple: return defaultMultipleFilter; case kinds.value: return defaultValueFilter; default: throw unexpectedKind(kind); } } function unexpectedKind(kind) { return new Error(`unexpected kind: ${kind}`); }