diff options
Diffstat (limited to 'app/assets/javascripts/lib/utils/vuex_module_mappers.js')
-rw-r--r-- | app/assets/javascripts/lib/utils/vuex_module_mappers.js | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/app/assets/javascripts/lib/utils/vuex_module_mappers.js b/app/assets/javascripts/lib/utils/vuex_module_mappers.js new file mode 100644 index 00000000000..95a794dd268 --- /dev/null +++ b/app/assets/javascripts/lib/utils/vuex_module_mappers.js @@ -0,0 +1,91 @@ +import { mapValues, isString } from 'lodash'; +import { mapState, mapActions } from 'vuex'; + +export const REQUIRE_STRING_ERROR_MESSAGE = + '`vuex_module_mappers` can only be used with an array of strings, or an object with string values. Consider using the regular `vuex` map helpers instead.'; + +const normalizeFieldsToObject = (fields) => { + return Array.isArray(fields) + ? fields.reduce((acc, key) => Object.assign(acc, { [key]: key }), {}) + : fields; +}; + +const mapVuexModuleFields = ({ namespaceSelector, fields, vuexHelper, selector } = {}) => { + // The `vuexHelper` needs an object which maps keys to field selector functions. + const map = mapValues(normalizeFieldsToObject(fields), (value) => { + if (!isString(value)) { + throw new Error(REQUIRE_STRING_ERROR_MESSAGE); + } + + // We need to use a good ol' function to capture the right "this". + return function mappedFieldSelector(...args) { + const namespace = namespaceSelector(this); + + return selector(namespace, value, ...args); + }; + }); + + return vuexHelper(map); +}; + +/** + * Like `mapState`, but takes a function in the first param for selecting a namespace. + * + * ``` + * computed: { + * ...mapVuexModuleState(vm => vm.vuexModule, ['foo']), + * } + * ``` + * + * @param {Function} namespaceSelector + * @param {Array|Object} fields + */ +export const mapVuexModuleState = (namespaceSelector, fields) => + mapVuexModuleFields({ + namespaceSelector, + fields, + vuexHelper: mapState, + selector: (namespace, value, state) => state[namespace][value], + }); + +/** + * Like `mapActions`, but takes a function in the first param for selecting a namespace. + * + * ``` + * methods: { + * ...mapVuexModuleActions(vm => vm.vuexModule, ['fetchFoos']), + * } + * ``` + * + * @param {Function} namespaceSelector + * @param {Array|Object} fields + */ +export const mapVuexModuleActions = (namespaceSelector, fields) => + mapVuexModuleFields({ + namespaceSelector, + fields, + vuexHelper: mapActions, + selector: (namespace, value, dispatch, ...args) => dispatch(`${namespace}/${value}`, ...args), + }); + +/** + * Like `mapGetters`, but takes a function in the first param for selecting a namespace. + * + * ``` + * computed: { + * ...mapGetters(vm => vm.vuexModule, ['hasSearchInfo']), + * } + * ``` + * + * @param {Function} namespaceSelector + * @param {Array|Object} fields + */ +export const mapVuexModuleGetters = (namespaceSelector, fields) => + mapVuexModuleFields({ + namespaceSelector, + fields, + // `mapGetters` does not let us pass an object which maps to functions. Thankfully `mapState` does + // and gives us access to the getters. + vuexHelper: mapState, + selector: (namespace, value, state, getters) => getters[`${namespace}/${value}`], + }); |