UNPKG

@mezereon/bigcommerce-stencil

Version:

BigCommerce UI components for Mezereon Xperience

504 lines (482 loc) 13.3 kB
/* eslint-disable eqeqeq */ import { isArray, isEmpty } from '@/helpers' export const namespaced = true export const state = () => ({ hits: [], queryId: '', segments: [], keyword: '', pageId: 0, aggregations: [], pagination: {}, selections: [], filters: undefined, sorting: [], paging: [], banners: [], layout: null, toggleLayout: false, sort: undefined, pageSize: undefined, page: 1, overlay: false, primaryKey: null, events: [], complete: '', suggestResult: {}, suggestItems: {}, currentSuggestion: null, context: {}, fallbackMode: false, gridItem: '', listItem: '', css: '', config: {}, queryParam: 'q', translation: undefined, filterLayout: 'vertical', redirect: undefined }) export const mutations = { LOAD_BANNERS(state, data) { state.banners = data }, LOAD_CONFIG(state, data) { state.config = data.autocomplete state.translation = data.translation }, RUN_AUTOCOMPLETE(state, payload) { if (payload.includeSuggestResult) { state.suggestResult = payload.data.suggestResult state.currentSuggestion = payload.data.suggestion state.complete = payload.data.complete } state.suggestItems = payload.data.searchResult state.primaryKey = payload.primaryKey state.redirect = payload.data.searchResult.redirect }, RUN_QUERY(state, data) { const pagingType = data.pagination.pagingType if (data.pagination.current_page == 1) { state.hits = data.hits } else { if (pagingType === 'more' || pagingType === 'infinite') { // avoid duplicates const existingIds = new Set( state.hits.items.map((item) => item.item.id) ) const uniqueItems = data.hits.items.filter( (item) => !existingIds.has(item.item.id) ) if (uniqueItems.length > 0) { state.hits.items.push(...uniqueItems) } } else { state.hits = data.hits } } state.queryId = data.queryId state.segments = data.segments state.primaryKey = data.primaryKey // add .state and .open properties data.aggregations.forEach((agg) => { agg.state = {} agg.open = {} }) // flatten tree aggregations to simplify value lookup const flat = {} const flatten = (name, item) => { flat[name] = flat[name] || {} flat[name][item.key] = item if (item.children) { item.children.forEach((child) => flatten(name, child)) } } data.aggregations .filter((y) => y.control === 'tree') .forEach((tree) => tree.items.forEach((item) => flatten(tree.name, item))) // helper function to get updated selection const getSelection = (agg, x, v) => { const item = agg.control === 'tree' ? flat[agg.name][v] : agg.items.find((a) => a.key == v) const value = item ? item.value : v return { ...x, action: 'add', key: v, label: agg.label, value } } // replace initial selections with new objects that contain updated action, label, key and value state.selections .filter((x) => x.action === 'init') .forEach((x) => { const agg = data.aggregations.find((y) => y.name === x.name) if (!agg) { return } if (agg.control === 'slider') { state.selections.push({ ...x, action: 'add', label: agg.label }) } else if (isArray(x.value)) { x.value.forEach((v) => state.selections.push(getSelection(agg, x, v))) } else { state.selections.push(getSelection(agg, x, x.value)) } }) state.selections = state.selections.filter((x) => x.action !== 'init') state.aggregations = data.aggregations state.pagination = data.pagination if (data.banners) { state.banners = data.banners } if (data.paging) { state.paging = data.paging } if (data.sorting) { state.sorting = data.sorting } if (data.grid) { state.gridItem = data.grid } if (data.list) { state.listItem = data.list } if (data.css) { state.css = data.css } if (data.filterLayout) { state.filterLayout = data.filterLayout } if (data.redirect) { state.redirect = data.redirect } }, SET_LAYOUT(state, data) { state.layout = data }, SET_SORT(state, data) { state.sort = data }, SET_PAGE_SIZE(state, data) { state.pageSize = data }, SET_PAGE(state, data) { state.page = data }, SET_OVERLAY(state, data) { state.overlay = data }, SET_KEYWORD(state, data) { state.keyword = data }, SET_TOGGLE_LAYOUT(state, data) { state.toggleLayout = data }, SET_PAGE_ID(state, data) { state.pageId = data }, SET_COMPLETE(state, data) { state.complete = data }, SET_CURRENT_SUGGESTION(state, data) { state.currentSuggestion = data }, CLEAR_AUTOCOMPLETE(state) { state.complete = '' state.currentSuggestion = '' state.suggestItems = {} state.suggestResult = {} }, SET_STATE(state, data) { state.page = data.page state.sort = data.sort state.pageSize = data.pageSize state.keyword = data.keyword state.filters = data.filters state.selections = data.selections }, SET_QUERY_PARAM(state, data) { state.queryParam = data }, SET_CONTEXT(state, data) { state.context = data }, SET_FALLBACK_MODE(state, data) { state.fallbackMode = data }, UPDATE_AGGREGATION(state, agg) { const aggregation = state.aggregations.find((x) => x.name === agg.name) if (aggregation) { aggregation.selected = agg.value } }, UPDATE_SELECTIONS(state, last) { switch (last.action) { case 'remove-all': state.selections = state.selections.filter((x) => x.name !== last.name) if (state.filters && state.filters[last.name]) { delete state.filters[last.name] } break case 'replace': state.selections = state.selections.filter((x) => x.name !== last.name) state.selections.push(last) if (last.key == '_Keyword') { break } state.filters = state.filters || {} if (last.value && isArray(last.value)) { state.filters[last.name] = last.value } else { state.filters[last.name] = [last.key] } break case 'add': state.selections.push(last) if (last.key == '_Keyword') { break } state.filters = state.filters || {} state.filters[last.name] = state.filters[last.name] || [] if (last.value && isArray(last.value)) { state.filters[last.name] = last.value } else { state.filters[last.name].push(last.key) } break default: state.selections = state.selections.filter( (x) => x.name !== last.name || x.key !== last.key ) if (state.filters && state.filters[last.name]) { state.filters[last.name] = state.filters[last.name].filter( (x) => x !== last.key ) if (state.filters[last.name].length === 0) { delete state.filters[last.name] } } break } }, CLEAR_ONE_SELECTION(state, toClear) { state.selections = state.selections.filter( (x) => x.name !== toClear.name || x.key !== toClear.key ) if (state.filters && state.filters[toClear.name]) { if (toClear.value && isArray(toClear.value)) { delete state.filters[toClear.name] } else { state.filters[toClear.name] = state.filters[toClear.name].filter( (x) => x !== toClear.key ) if (state.filters[toClear.name].length === 0) { delete state.filters[toClear.name] } } } // special case for keyword selection if (toClear.key === '_Keyword') { state.keyword = '' // clear autocomplete state.complete = '' state.currentSuggestion = '' state.suggestItems = {} state.suggestResult = {} } const aggregation = state.aggregations.find((x) => x.name === toClear.name) if (aggregation) { if (aggregation.control === 'slider') { aggregation.selected = [] } else { aggregation.selected = aggregation.selected.filter( (x) => x !== toClear.key ) } } }, CLEAR_ALL_SELECTIONS(state, payload) { state.keyword = '' state.selections = [] state.aggregations.forEach((agg) => { agg.selected = [] }) state.filters = undefined }, TRACK_EVENT(state, payload) { state.events.push(payload) }, CLEAR_EVENTS(state) { state.events = [] } } export const actions = { setLayout({ commit }, payload) { commit('SET_LAYOUT', payload) }, setSort({ commit }, payload) { commit('SET_SORT', payload) }, setPageSize({ commit }, payload) { commit('SET_PAGE_SIZE', payload) }, setPage({ commit }, payload) { commit('SET_PAGE', payload) }, setOverlay({ commit }, payload) { commit('SET_OVERLAY', payload) }, setKeyword({ commit }, payload) { commit('SET_KEYWORD', payload) }, setToggleLayout({ commit }, payload) { commit('SET_TOGGLE_LAYOUT', payload) }, setComplete({ commit }, payload) { commit('SET_COMPLETE', payload) }, setCurrentSuggestion({ commit }, payload) { commit('SET_CURRENT_SUGGESTION', payload) }, clearAutocomplete({ commit }, payload) { commit('CLEAR_AUTOCOMPLETE', payload) }, setPageId({ commit }, payload) { commit('SET_PAGE_ID', payload) }, setState({ commit }, payload) { commit('SET_STATE', payload) }, setQueryParam({ commit }, payload) { commit('SET_QUERY_PARAM', payload) }, setContext({ commit }, payload) { commit('SET_CONTEXT', payload) }, updateAggregation({ commit }, payload) { commit('UPDATE_AGGREGATION', payload) }, updateSelections({ commit }, payload) { commit('UPDATE_SELECTIONS', payload) }, clearOneSelection({ commit }, payload) { commit('CLEAR_ONE_SELECTION', payload) }, clearAllSelections({ commit }, payload) { commit('CLEAR_ALL_SELECTIONS', payload) }, trackEvent({ commit }, payload) { commit('TRACK_EVENT', payload) }, getEvents({ commit, state }) { const events = state.events commit('CLEAR_EVENTS') return events }, async loadConfig({ commit }, payload) { try { const { data } = await this.$axios.get('/search/config') commit('LOAD_CONFIG', data) } catch { commit('SET_FALLBACK_MODE', true) } }, async runAutocomplete({ commit }, payload) { const { data } = await this.$axios.post('/search/autocomplete/', payload) commit('RUN_AUTOCOMPLETE', { includeSuggestResult: payload.autocompleteConfig.includeSuggestResult, primaryKey: data.searchResult.primaryKey, data }) }, async runQuery({ commit, state }, payload) { commit('SET_PAGE_ID', payload.query.pageId || 0) try { const res = await this.$axios.post('/search/query', payload) // set default pagination for (const paging of res.data.paging) { if (paging.default && !state.pageSize) { commit('SET_PAGE_SIZE', paging.value) break } } // set default sorting for (const sorting of res.data.sorting) { if (sorting.default && !state.sort) { commit('SET_SORT', sorting.key) break } } const skip = (payload.query.page - 1) * state.pageSize const total = res.data.total || 0 const pagination = { pagingType: res.data.pagingType || 'standard', current_page: payload.query.page, per_page: state.pageSize, total, from: skip + 1, to: skip + state.pageSize, last_page: Math.ceil(total / state.pageSize) } const data = { hits: res.data, primaryKey: res.data.primaryKey, queryId: res.data.queryId, segments: res.data.segments, pagination, aggregations: res.data.aggregations, banners: res.data.banners, paging: res.data.paging, sorting: res.data.sorting, grid: res.data.grid, list: res.data.list, css: res.data.css, filterLayout: res.data.filterLayout, redirect: res.data.redirect } commit('RUN_QUERY', data) } catch { commit('SET_FALLBACK_MODE', true) } } } export const getters = { getFacetBanners: (state) => { const banners = { ...state.banners } for (const banner in banners) { if (!banner.startsWith('facet')) { delete banners[banner] } if (isEmpty(banners[banner])) { delete banners[banner] } } return banners }, getBannerByZone: (state) => (zone) => { return state.banners[zone] }, getQuery: (state) => () => { return { page: state.page, sort: state.sort, pageSize: state.pageSize, keyword: state.keyword, filters: state.filters } } } export const search = { namespaced, state, getters, mutations, actions }