From 5d2827c0c0f8b35800090218b8aa4b453c73edc0 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Wed, 8 May 2019 13:10:17 +0200 Subject: [PATCH 0001/1227] prepare module draft --- core/modules/catalog-magento/index.ts | 15 ++++++++++++ .../store/category/CategoryState.ts | 16 +++++++++++++ .../catalog-magento/store/category/actions.ts | 24 +++++++++++++++++++ .../catalog-magento/store/category/getters.ts | 8 +++++++ .../catalog-magento/store/category/index.ts | 18 ++++++++++++++ .../store/category/mutation-types.ts | 9 +++++++ .../store/category/mutations.ts | 13 ++++++++++ src/modules/index.ts | 2 ++ 8 files changed, 105 insertions(+) create mode 100644 core/modules/catalog-magento/index.ts create mode 100644 core/modules/catalog-magento/store/category/CategoryState.ts create mode 100644 core/modules/catalog-magento/store/category/actions.ts create mode 100644 core/modules/catalog-magento/store/category/getters.ts create mode 100644 core/modules/catalog-magento/store/category/index.ts create mode 100644 core/modules/catalog-magento/store/category/mutation-types.ts create mode 100644 core/modules/catalog-magento/store/category/mutations.ts diff --git a/core/modules/catalog-magento/index.ts b/core/modules/catalog-magento/index.ts new file mode 100644 index 000000000..627417329 --- /dev/null +++ b/core/modules/catalog-magento/index.ts @@ -0,0 +1,15 @@ +// import { productModule } from './store/product' +// import { attributeModule } from './store/attribute' +// import { stockModule } from './store/stock' +// import { taxModule } from './store/tax' +import { categoryModule } from './store/category' +import { createModule } from '@vue-storefront/core/lib/module' +// import { beforeRegistration } from './hooks/beforeRegistration' + +export const KEY = 'catalog-magento' +export default createModule({ + key: KEY, + store: { modules: [ + { key: 'category-magento', module: categoryModule } + ] } +}) diff --git a/core/modules/catalog-magento/store/category/CategoryState.ts b/core/modules/catalog-magento/store/category/CategoryState.ts new file mode 100644 index 000000000..317fe81d1 --- /dev/null +++ b/core/modules/catalog-magento/store/category/CategoryState.ts @@ -0,0 +1,16 @@ +export default interface CategoryState { + categories: any, + availableFilters: any, + products: any + // list: any, + // current: any, + // filters: { + // available: any, + // chosen: any + // }, + // breadcrumbs: { + // routes: any + // }, + // current_product_query: any, + // current_path: any +} diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts new file mode 100644 index 000000000..a71368ab2 --- /dev/null +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -0,0 +1,24 @@ +// import Vue from 'vue' +import { ActionTree } from 'vuex' +// import * as types from './mutation-types' +// import { quickSearchByQuery } from '@vue-storefront/core/lib/search' +// import { entityKeyName } from '@vue-storefront/core/store/lib/entities' +// import rootStore from '@vue-storefront/core/store' +// import i18n from '@vue-storefront/i18n' +// import chunk from 'lodash-es/chunk' +// import trim from 'lodash-es/trim' +// import toString from 'lodash-es/toString' +// import { optionLabel } from '../../helpers/optionLabel' +import RootState from '@vue-storefront/core/types/RootState' +import CategoryState from './CategoryState' +// import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' +// import { currentStoreView } from '@vue-storefront/core/lib/multistore' +// import { Logger } from '@vue-storefront/core/lib/logger' +// import { isServer } from '@vue-storefront/core/helpers' + + +const actions: ActionTree = { + +} + +export default actions diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts new file mode 100644 index 000000000..7ed835e31 --- /dev/null +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -0,0 +1,8 @@ +import { GetterTree } from 'vuex' +import RootState from '@vue-storefront/core/types/RootState' +import CategoryState from './CategoryState' + +const getters: GetterTree = { +} + +export default getters diff --git a/core/modules/catalog-magento/store/category/index.ts b/core/modules/catalog-magento/store/category/index.ts new file mode 100644 index 000000000..4ba814c6b --- /dev/null +++ b/core/modules/catalog-magento/store/category/index.ts @@ -0,0 +1,18 @@ +import { Module } from 'vuex' +import actions from './actions' +import getters from './getters' +import mutations from './mutations' +import RootState from '@vue-storefront/core/types/RootState' +import CategoryState from './CategoryState' + +export const categoryModule: Module = { + namespaced: true, + state: { + categories: [], + availableFilters: {}, + products: [] + }, + getters, + actions, + mutations +} diff --git a/core/modules/catalog-magento/store/category/mutation-types.ts b/core/modules/catalog-magento/store/category/mutation-types.ts new file mode 100644 index 000000000..c6bf9e841 --- /dev/null +++ b/core/modules/catalog-magento/store/category/mutation-types.ts @@ -0,0 +1,9 @@ +export const SN_CATEGORY = 'category' +export const CATEGORY_UPD_CATEGORIES = SN_CATEGORY + '/UPD_CATEGORIES' +export const CATEGORY_UPD_CURRENT_CATEGORY = SN_CATEGORY + '/UPD_CURRENT_CATEGORY' +export const CATEGORY_UPD_CURRENT_CATEGORY_PATH = SN_CATEGORY + '/UPD_CURRENT_CATEGORY_PATH' +export const CATEGORY_UPD_SEARCH_PRODUCT_QUERY = SN_CATEGORY + '/UPD_SEARCH_PRODUCT_QUERY' +export const CATEGORY_ADD_AVAILABLE_FILTER = `${SN_CATEGORY}/ADD_AVAILABLE_FILTER` +export const CATEGORY_REMOVE_FILTERS = SN_CATEGORY + '/REMOVE_FILTERS' +export const CATEGORY_SET_SEARCH_OPTIONS = `${SN_CATEGORY}/SET_SEARCH_OPTIONS` +export const CATEGORY_MERGE_SEARCH_OPTIONS = `${SN_CATEGORY}/MERGE_SEARCH_OPTIONS` \ No newline at end of file diff --git a/core/modules/catalog-magento/store/category/mutations.ts b/core/modules/catalog-magento/store/category/mutations.ts new file mode 100644 index 000000000..ae350616b --- /dev/null +++ b/core/modules/catalog-magento/store/category/mutations.ts @@ -0,0 +1,13 @@ +// import Vue from 'vue' +import { MutationTree } from 'vuex' +// import * as types from './mutation-types' +// import { slugify, formatBreadCrumbRoutes } from '@vue-storefront/core/helpers' +// import { entityKeyName } from '@vue-storefront/core/store/lib/entities' +import CategoryState from './CategoryState' +// import rootStore from '@vue-storefront/core/store' +// import { Logger } from '@vue-storefront/core/lib/logger' + +const mutations: MutationTree = { +} + +export default mutations diff --git a/src/modules/index.ts b/src/modules/index.ts index 2746a6d0e..c5ee936dd 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -1,6 +1,7 @@ // import { extendModule } from '@vue-storefront/core/lib/module' import { VueStorefrontModule } from '@vue-storefront/core/lib/module' import { Catalog } from "@vue-storefront/core/modules/catalog" +import CatalogMagento from "@vue-storefront/core/modules/catalog-magento" import { Cart } from '@vue-storefront/core/modules/cart' import { Checkout } from '@vue-storefront/core/modules/checkout' import { Compare } from '@vue-storefront/core/modules/compare' @@ -77,5 +78,6 @@ export const registerModules: VueStorefrontModule[] = [ AmpRenderer, InstantCheckout, Url, + CatalogMagento // Example ] From 3889092fa7e019f9c31215146ad5d892a965de23 Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 09:35:16 +0200 Subject: [PATCH 0002/1227] add default values --- core/helpers/index.ts | 4 ++-- core/lib/search.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/helpers/index.ts b/core/helpers/index.ts index 3e6183641..a2f6c304e 100644 --- a/core/helpers/index.ts +++ b/core/helpers/index.ts @@ -87,8 +87,8 @@ export function productThumbnailPath (product, ignoreConfig = false) { return thumbnail } -export function buildFilterProductsQuery (currentCategory, chosenFilters, defaultFilters = null) { - let filterQr = baseFilterProductsQuery(currentCategory, defaultFilters == null ? rootStore.state.config.products.defaultFilters : defaultFilters) +export function buildFilterProductsQuery (currentCategory, chosenFilters = {}, defaultFilters = null) { + let filterQr = baseFilterProductsQuery(currentCategory, !defaultFilters ? rootStore.state.config.products.defaultFilters : defaultFilters) // add choosedn filters for (let code of Object.keys(chosenFilters)) { diff --git a/core/lib/search.ts b/core/lib/search.ts index bc135d041..0bf78a58b 100644 --- a/core/lib/search.ts +++ b/core/lib/search.ts @@ -25,7 +25,7 @@ export function isOnline () : boolean { * @param {Int} size page size * @return {Promise} */ -export const quickSearchByQuery = async ({ query, start = 0, size = 50, entityType = 'product', sort = '', storeCode = null, excludeFields = null, includeFields = null }): Promise => { +export const quickSearchByQuery = async ({ query = {}, start = 0, size = 50, entityType = 'product', sort = '', storeCode = null, excludeFields = null, includeFields = null } = {}): Promise => { const searchAdapter = await getSearchAdapter() if (size <= 0) size = 50 if (start < 0) start = 0 From 9d2462aa0940494b126887cc060e86ef5d860048 Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 09:35:49 +0200 Subject: [PATCH 0003/1227] init module actions --- .../catalog-magento/store/category/actions.ts | 46 +++++++++++++------ .../catalog-magento/store/category/getters.ts | 2 + .../store/category/mutation-types.ts | 11 ++--- .../store/category/mutations.ts | 15 ++++-- 4 files changed, 46 insertions(+), 28 deletions(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index a71368ab2..4280211c9 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -1,24 +1,40 @@ // import Vue from 'vue' import { ActionTree } from 'vuex' -// import * as types from './mutation-types' -// import { quickSearchByQuery } from '@vue-storefront/core/lib/search' -// import { entityKeyName } from '@vue-storefront/core/store/lib/entities' -// import rootStore from '@vue-storefront/core/store' -// import i18n from '@vue-storefront/i18n' -// import chunk from 'lodash-es/chunk' -// import trim from 'lodash-es/trim' -// import toString from 'lodash-es/toString' -// import { optionLabel } from '../../helpers/optionLabel' +import * as types from './mutation-types' import RootState from '@vue-storefront/core/types/RootState' import CategoryState from './CategoryState' -// import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' -// import { currentStoreView } from '@vue-storefront/core/lib/multistore' -// import { Logger } from '@vue-storefront/core/lib/logger' -// import { isServer } from '@vue-storefront/core/helpers' - +import { quickSearchByQuery } from '@vue-storefront/core/lib/search' +import { buildFilterProductsQuery } from '@vue-storefront/core/helpers' +import config from 'config' const actions: ActionTree = { - + async initCategoryModule ({ getters, dispatch }) { + if (!getters.getCategories.length) { + await dispatch('getCategories') + } + }, + async searchProducts ({ commit, dispatch, rootState }, { category } = {}) { + await dispatch('initCategoryModule') + console.error('QUERIES', rootState.route.query) + // const category = await store.dispatch('category/single', { key: store.state.config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: route.params.slug }) + const searchCategory = category ? category : await dispatch('getCurrentCategory') + let filterQr = buildFilterProductsQuery(searchCategory) + const x = await quickSearchByQuery({ query: filterQr }) + commit(types.CATEGORY_SET_PRODUCTS, x.items) + return x.items + }, + async getCurrentCategory ({ dispatch, rootState }) { + return await dispatch('category/single', { key: config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: rootState.route.params.slug }, {root: true}) + }, + async fetchCategories ({ dispatch }) { + const res = await dispatch('category/list', {}, {root: true}) + return res.items + }, + async getCategories ({ commit, dispatch }) { + const categories = await dispatch('fetchCategories') + commit(types.CATEGORY_SET_CATEGORIES, categories) + return categories + } } export default actions diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index 7ed835e31..7490bf2ad 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -3,6 +3,8 @@ import RootState from '@vue-storefront/core/types/RootState' import CategoryState from './CategoryState' const getters: GetterTree = { + getCategories: (state) => state.categories, + getCategoryProducts: (state) => state.products } export default getters diff --git a/core/modules/catalog-magento/store/category/mutation-types.ts b/core/modules/catalog-magento/store/category/mutation-types.ts index c6bf9e841..7ade76f45 100644 --- a/core/modules/catalog-magento/store/category/mutation-types.ts +++ b/core/modules/catalog-magento/store/category/mutation-types.ts @@ -1,9 +1,4 @@ export const SN_CATEGORY = 'category' -export const CATEGORY_UPD_CATEGORIES = SN_CATEGORY + '/UPD_CATEGORIES' -export const CATEGORY_UPD_CURRENT_CATEGORY = SN_CATEGORY + '/UPD_CURRENT_CATEGORY' -export const CATEGORY_UPD_CURRENT_CATEGORY_PATH = SN_CATEGORY + '/UPD_CURRENT_CATEGORY_PATH' -export const CATEGORY_UPD_SEARCH_PRODUCT_QUERY = SN_CATEGORY + '/UPD_SEARCH_PRODUCT_QUERY' -export const CATEGORY_ADD_AVAILABLE_FILTER = `${SN_CATEGORY}/ADD_AVAILABLE_FILTER` -export const CATEGORY_REMOVE_FILTERS = SN_CATEGORY + '/REMOVE_FILTERS' -export const CATEGORY_SET_SEARCH_OPTIONS = `${SN_CATEGORY}/SET_SEARCH_OPTIONS` -export const CATEGORY_MERGE_SEARCH_OPTIONS = `${SN_CATEGORY}/MERGE_SEARCH_OPTIONS` \ No newline at end of file +export const CATEGORY_SET_PRODUCTS = `${SN_CATEGORY}/SET_PRODUCTS` +export const CATEGORY_SET_CATEGORIES = `${SN_CATEGORY}/SET_CATEGORIES` +export const CATEGORY_SET_AVAILABLE_FILTERS = `${SN_CATEGORY}/SET_AVAILABLE_FILTERS` diff --git a/core/modules/catalog-magento/store/category/mutations.ts b/core/modules/catalog-magento/store/category/mutations.ts index ae350616b..92fef3872 100644 --- a/core/modules/catalog-magento/store/category/mutations.ts +++ b/core/modules/catalog-magento/store/category/mutations.ts @@ -1,13 +1,18 @@ // import Vue from 'vue' import { MutationTree } from 'vuex' -// import * as types from './mutation-types' -// import { slugify, formatBreadCrumbRoutes } from '@vue-storefront/core/helpers' -// import { entityKeyName } from '@vue-storefront/core/store/lib/entities' +import * as types from './mutation-types' import CategoryState from './CategoryState' -// import rootStore from '@vue-storefront/core/store' -// import { Logger } from '@vue-storefront/core/lib/logger' const mutations: MutationTree = { + [types.CATEGORY_SET_PRODUCTS] (state, products = []) { + state.products = products + }, + [types.CATEGORY_SET_CATEGORIES] (state, categories = []) { + state.categories = categories + }, + [types.CATEGORY_SET_AVAILABLE_FILTERS] (state, availableFilters = {}) { + state.availableFilters = availableFilters + } } export default mutations From 16ca33e825e50bdc7d4044dc4f2f9be9abc3d1a4 Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 10:24:42 +0200 Subject: [PATCH 0004/1227] move helper from old module --- .../catalog-magento/helpers/optionLabel.ts | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 core/modules/catalog-magento/helpers/optionLabel.ts diff --git a/core/modules/catalog-magento/helpers/optionLabel.ts b/core/modules/catalog-magento/helpers/optionLabel.ts new file mode 100644 index 000000000..12549b658 --- /dev/null +++ b/core/modules/catalog-magento/helpers/optionLabel.ts @@ -0,0 +1,39 @@ +/** + * Helper method for getting attribute name - TODO: to be moved to external/shared helper + * + * @param {String} attributeCode + * @param {String} optionId - value to get label for + */ +import toString from 'lodash-es/toString' + +export function optionLabel (state, { attributeKey, searchBy = 'code', optionId }) { + let attrCache = state.labels[attributeKey] + + if (attrCache) { + let label = attrCache[optionId] + + if (label) { + return label + } + } + let attr = state['list_by_' + searchBy][attributeKey] + if (attr) { + let opt = attr.options.find((op) => { // TODO: cache it in memory + if (toString(op.value) === toString(optionId)) { + return op + } + }) // TODO: i18n support with multi-website attribute names + + if (opt) { + if (!state.labels[attributeKey]) { + state.labels[attributeKey] = {} + } + state.labels[attributeKey][optionId] = opt.label + return opt ? opt.label : optionId + } else { + return optionId + } + } else { + return optionId + } +} From 0207857dc9a72f1e5e4b4b5b7149a7cdc3f1142f Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 10:29:53 +0200 Subject: [PATCH 0005/1227] getting available filters --- .../catalog-magento/store/category/actions.ts | 73 ++++++++++++++++++- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 4280211c9..22480c3ff 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -6,11 +6,21 @@ import CategoryState from './CategoryState' import { quickSearchByQuery } from '@vue-storefront/core/lib/search' import { buildFilterProductsQuery } from '@vue-storefront/core/helpers' import config from 'config' +import trim from 'lodash-es/trim' +import toString from 'lodash-es/toString' +import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import { optionLabel } from '../../helpers/optionLabel' const actions: ActionTree = { + /** + * Initialise category module. + * - gets available categories + * - gets available filters for current category + */ async initCategoryModule ({ getters, dispatch }) { if (!getters.getCategories.length) { await dispatch('getCategories') + await dispatch('getAvailableFilters') } }, async searchProducts ({ commit, dispatch, rootState }, { category } = {}) { @@ -19,9 +29,10 @@ const actions: ActionTree = { // const category = await store.dispatch('category/single', { key: store.state.config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: route.params.slug }) const searchCategory = category ? category : await dispatch('getCurrentCategory') let filterQr = buildFilterProductsQuery(searchCategory) - const x = await quickSearchByQuery({ query: filterQr }) - commit(types.CATEGORY_SET_PRODUCTS, x.items) - return x.items + const searchResult = await quickSearchByQuery({ query: filterQr }) + commit(types.CATEGORY_SET_PRODUCTS, searchResult.items) + + return searchResult.items }, async getCurrentCategory ({ dispatch, rootState }) { return await dispatch('category/single', { key: config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: rootState.route.params.slug }, {root: true}) @@ -34,6 +45,62 @@ const actions: ActionTree = { const categories = await dispatch('fetchCategories') commit(types.CATEGORY_SET_CATEGORIES, categories) return categories + }, + /** + * Fetch and process filters from current category and sets them in available filters. + */ + async getAvailableFilters ({ commit, dispatch, rootState }) { + const filters = {} + const searchCategory = await dispatch('getCurrentCategory') + let filterQr = buildFilterProductsQuery(searchCategory) + const searchResult = await quickSearchByQuery({ query: filterQr }) + if (searchResult && searchResult.aggregations) { // populate filter aggregates + for (let attrToFilter of config.products.defaultFilters) { // fill out the filter options + let filterOptions = [] + + let uniqueFilterValues = new Set() + if (attrToFilter !== 'price') { + if (searchResult.aggregations['agg_terms_' + attrToFilter]) { + let buckets = searchResult.aggregations['agg_terms_' + attrToFilter].buckets + if (searchResult.aggregations['agg_terms_' + attrToFilter + '_options']) { + buckets = buckets.concat(searchResult.aggregations['agg_terms_' + attrToFilter + '_options'].buckets) + } + + for (let option of buckets) { + uniqueFilterValues.add(toString(option.key)) + } + } + + uniqueFilterValues.forEach(key => { + const label = optionLabel(rootState.attribute, { attributeKey: attrToFilter, optionId: key }) + if (trim(label) !== '') { // is there any situation when label could be empty and we should still support it? + filterOptions.push({ + id: key, + label: label + }) + } + }); + } else { // special case is range filter for prices + const storeView = currentStoreView() + const currencySign = storeView.i18n.currencySign + if (searchResult.aggregations['agg_range_' + attrToFilter]) { + let index = 0 + let count = searchResult.aggregations['agg_range_' + attrToFilter].buckets.length + for (let option of searchResult.aggregations['agg_range_' + attrToFilter].buckets) { + filterOptions.push({ + id: option.key, + from: option.from, + to: option.to, + label: (index === 0 || (index === count - 1)) ? (option.to ? '< ' + currencySign + option.to : '> ' + currencySign + option.from) : currencySign + option.from + (option.to ? ' - ' + option.to : '')// TODO: add better way for formatting, extract currency sign + }) + index++ + } + } + } + filters[attrToFilter] = filterOptions + } + } + commit(types.CATEGORY_SET_AVAILABLE_FILTERS, filters) } } From 087d45e2c05e64fcc9200e1cc4e1886012745b0f Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 15:27:14 +0200 Subject: [PATCH 0006/1227] invoke search with current filters --- .../catalog-magento/store/category/actions.ts | 17 ++++++++++++++--- .../catalog-magento/store/category/getters.ts | 3 ++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 22480c3ff..1e528f0b8 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -23,12 +23,23 @@ const actions: ActionTree = { await dispatch('getAvailableFilters') } }, - async searchProducts ({ commit, dispatch, rootState }, { category } = {}) { + async getCurrentFilters ({ getters, rootState }, filters) { + const currentQuery = filters ? filters : rootState.route.query + const chosenFilter = {} + Object.keys(currentQuery).map(filterKey => { + const filter = getters.getAvailableFilters[filterKey] + const queryValue = currentQuery[filterKey] + const variant = filter.find(filterVariant => filterVariant.id === queryValue) + chosenFilter[filterKey] = {...variant, attribute_code: filterKey} + }) + return chosenFilter + }, + async searchProducts ({ commit, dispatch }, { category, filters } = {}) { await dispatch('initCategoryModule') - console.error('QUERIES', rootState.route.query) // const category = await store.dispatch('category/single', { key: store.state.config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: route.params.slug }) + const currentFilters = await dispatch('getCurrentFilters', filters) const searchCategory = category ? category : await dispatch('getCurrentCategory') - let filterQr = buildFilterProductsQuery(searchCategory) + let filterQr = buildFilterProductsQuery(searchCategory, currentFilters) const searchResult = await quickSearchByQuery({ query: filterQr }) commit(types.CATEGORY_SET_PRODUCTS, searchResult.items) diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index 7490bf2ad..b50602e8d 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -4,7 +4,8 @@ import CategoryState from './CategoryState' const getters: GetterTree = { getCategories: (state) => state.categories, - getCategoryProducts: (state) => state.products + getCategoryProducts: (state) => state.products, + getAvailableFilters: state => state.availableFilters } export default getters From e834b21dc4eb1b9d94a81b65519bed7bb57a8058 Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 16:44:41 +0200 Subject: [PATCH 0007/1227] current category from getter --- core/modules/catalog-magento/store/category/actions.ts | 8 ++++---- core/modules/catalog-magento/store/category/getters.ts | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 1e528f0b8..88e128031 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -34,11 +34,11 @@ const actions: ActionTree = { }) return chosenFilter }, - async searchProducts ({ commit, dispatch }, { category, filters } = {}) { + async searchProducts ({ commit, getters, dispatch }, { category, filters } = {}) { await dispatch('initCategoryModule') // const category = await store.dispatch('category/single', { key: store.state.config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: route.params.slug }) const currentFilters = await dispatch('getCurrentFilters', filters) - const searchCategory = category ? category : await dispatch('getCurrentCategory') + const searchCategory = category ? category : getters.getCurrentCategory // await dispatch('getCurrentCategory') let filterQr = buildFilterProductsQuery(searchCategory, currentFilters) const searchResult = await quickSearchByQuery({ query: filterQr }) commit(types.CATEGORY_SET_PRODUCTS, searchResult.items) @@ -60,9 +60,9 @@ const actions: ActionTree = { /** * Fetch and process filters from current category and sets them in available filters. */ - async getAvailableFilters ({ commit, dispatch, rootState }) { + async getAvailableFilters ({ commit, getters, rootState }) { const filters = {} - const searchCategory = await dispatch('getCurrentCategory') + const searchCategory = getters.getCurrentCategory let filterQr = buildFilterProductsQuery(searchCategory) const searchResult = await quickSearchByQuery({ query: filterQr }) if (searchResult && searchResult.aggregations) { // populate filter aggregates diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index b50602e8d..6197bdcd6 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -5,7 +5,10 @@ import CategoryState from './CategoryState' const getters: GetterTree = { getCategories: (state) => state.categories, getCategoryProducts: (state) => state.products, - getAvailableFilters: state => state.availableFilters + getAvailableFilters: state => state.availableFilters, + getCurrentCategory: (state, getters) => { + return getters.getCategories[0] + } } export default getters From d3726965f9f5e07b9d277ca8880e4eb9aa9a4fc4 Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 17:19:08 +0200 Subject: [PATCH 0008/1227] default value as string --- core/modules/catalog/components/ProductCustomOption.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modules/catalog/components/ProductCustomOption.ts b/core/modules/catalog/components/ProductCustomOption.ts index 898fd6a93..c413d04bf 100644 --- a/core/modules/catalog/components/ProductCustomOption.ts +++ b/core/modules/catalog/components/ProductCustomOption.ts @@ -4,7 +4,7 @@ export const ProductCustomOption = { label: { type: String, required: false, - default: () => false + default: '' }, id: { type: null, From 59f2130d1fba962fa2b6aaa420e33a48ab53238a Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 17:19:27 +0200 Subject: [PATCH 0009/1227] add todo for multiple filters --- core/modules/catalog-magento/store/category/actions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 88e128031..54c9a9838 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -29,6 +29,7 @@ const actions: ActionTree = { Object.keys(currentQuery).map(filterKey => { const filter = getters.getAvailableFilters[filterKey] const queryValue = currentQuery[filterKey] + // TODO if query value is an array then we have multifilter const variant = filter.find(filterVariant => filterVariant.id === queryValue) chosenFilter[filterKey] = {...variant, attribute_code: filterKey} }) From 8a9d28df5579260b20f39b95adbbfb0640c0495a Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 18:25:42 +0200 Subject: [PATCH 0010/1227] switching search filters --- core/modules/catalog-magento/store/category/actions.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 54c9a9838..dbe52f344 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -10,6 +10,7 @@ import trim from 'lodash-es/trim' import toString from 'lodash-es/toString' import { currentStoreView } from '@vue-storefront/core/lib/multistore' import { optionLabel } from '../../helpers/optionLabel' +import { router } from '@vue-storefront/core/app' const actions: ActionTree = { /** @@ -113,6 +114,15 @@ const actions: ActionTree = { } } commit(types.CATEGORY_SET_AVAILABLE_FILTERS, filters) + }, + async switchSearchFilter({ dispatch }, filterVariant) { + const xx = Object.assign({}, router.currentRoute.query) // await dispatch('getCurrentFilters') + if(xx[filterVariant.name] && xx[filterVariant.name] === filterVariant.value.id) { + delete xx[filterVariant.name] + } else { + xx[filterVariant.name] = filterVariant.value.id + } + router.push({query: xx}) } } From d2b4664f72863032053038b1889a337e7190c9f6 Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 18:28:30 +0200 Subject: [PATCH 0011/1227] switching filters query --- core/modules/catalog-magento/store/category/actions.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index dbe52f344..4368ff188 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -116,13 +116,13 @@ const actions: ActionTree = { commit(types.CATEGORY_SET_AVAILABLE_FILTERS, filters) }, async switchSearchFilter({ dispatch }, filterVariant) { - const xx = Object.assign({}, router.currentRoute.query) // await dispatch('getCurrentFilters') - if(xx[filterVariant.name] && xx[filterVariant.name] === filterVariant.value.id) { - delete xx[filterVariant.name] + const query = Object.assign({}, router.currentRoute.query) // await dispatch('getCurrentFilters') + if(query[filterVariant.name] && query[filterVariant.name] === filterVariant.value.id) { + delete query[filterVariant.name] } else { - xx[filterVariant.name] = filterVariant.value.id + query[filterVariant.name] = filterVariant.value.id } - router.push({query: xx}) + router.push({query}) } } From 23e70d73959b1d032f991b57a352d3ca3552205a Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 21:34:57 +0200 Subject: [PATCH 0012/1227] multiple dilters draft and reseting filters --- .../catalog-magento/store/category/actions.ts | 17 ++++++++++++++--- .../catalog-magento/store/category/getters.ts | 4 ++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 4368ff188..36d635bdb 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -30,14 +30,22 @@ const actions: ActionTree = { Object.keys(currentQuery).map(filterKey => { const filter = getters.getAvailableFilters[filterKey] const queryValue = currentQuery[filterKey] - // TODO if query value is an array then we have multifilter - const variant = filter.find(filterVariant => filterVariant.id === queryValue) - chosenFilter[filterKey] = {...variant, attribute_code: filterKey} + if (Array.isArray(queryValue)) { + queryValue.map(singleValue => { + const variant = filter.find(filterVariant => filterVariant.id === singleValue) + if (!chosenFilter[filterKey] || !Array.isArray(chosenFilter[filterKey])) chosenFilter[filterKey] = [] + chosenFilter[filterKey].push({...variant, attribute_code: filterKey}) + }) + } else { + const variant = filter.find(filterVariant => filterVariant.id === queryValue) + chosenFilter[filterKey] = {...variant, attribute_code: filterKey} + } }) return chosenFilter }, async searchProducts ({ commit, getters, dispatch }, { category, filters } = {}) { await dispatch('initCategoryModule') + console.error("SEARCH IN: " + router.currentRoute.fullPath) // const category = await store.dispatch('category/single', { key: store.state.config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: route.params.slug }) const currentFilters = await dispatch('getCurrentFilters', filters) const searchCategory = category ? category : getters.getCurrentCategory // await dispatch('getCurrentCategory') @@ -123,6 +131,9 @@ const actions: ActionTree = { query[filterVariant.name] = filterVariant.value.id } router.push({query}) + }, + async resetFilters() { + router.push({query: {}}) } } diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index 6197bdcd6..a5bf0c4cd 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -6,8 +6,8 @@ const getters: GetterTree = { getCategories: (state) => state.categories, getCategoryProducts: (state) => state.products, getAvailableFilters: state => state.availableFilters, - getCurrentCategory: (state, getters) => { - return getters.getCategories[0] + getCurrentCategory: (state, getters, routeState) => { + return getters.getCategories.find(category => routeState.route.path.includes(category.url_path)) || {} } } From c60508db3bf06159cad540d0c29e16530f4bf951 Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 21:39:57 +0200 Subject: [PATCH 0013/1227] migrate filter components --- .../default/components/core/ColorSelector.vue | 29 ++++++++++++------- .../components/core/GenericSelector.vue | 20 +++++++++---- .../default/components/core/PriceSelector.vue | 21 +++++++++----- .../default/components/core/SizeSelector.vue | 21 +++++++++----- .../core/blocks/Category/Sidebar.vue | 26 ++++++++++++----- 5 files changed, 80 insertions(+), 37 deletions(-) diff --git a/src/themes/default/components/core/ColorSelector.vue b/src/themes/default/components/core/ColorSelector.vue index 4bd1a5a31..f7713ee4b 100644 --- a/src/themes/default/components/core/ColorSelector.vue +++ b/src/themes/default/components/core/ColorSelector.vue @@ -1,26 +1,35 @@ diff --git a/src/themes/default/components/core/PriceSelector.vue b/src/themes/default/components/core/PriceSelector.vue index f47b76659..7f8106920 100644 --- a/src/themes/default/components/core/PriceSelector.vue +++ b/src/themes/default/components/core/PriceSelector.vue @@ -1,21 +1,28 @@ diff --git a/src/themes/default/components/core/SizeSelector.vue b/src/themes/default/components/core/SizeSelector.vue index 28e4d0a8a..ae37d9500 100644 --- a/src/themes/default/components/core/SizeSelector.vue +++ b/src/themes/default/components/core/SizeSelector.vue @@ -4,19 +4,26 @@ p0 bg-cl-primary brdr-1 brdr-cl-primary brdr-square h5 cl-tertiary size-selector " - :class="{ active: active }" - @click="switchFilter(id, label)" - :aria-label="$t('Select size ') + label" + :class="{ active: isActive }" + @click="$emit('change', variant)" + :aria-label="$t('Select size ') + variant.label" > - {{ label }} + {{ variant.label }} diff --git a/src/themes/default/components/core/blocks/Category/Sidebar.vue b/src/themes/default/components/core/blocks/Category/Sidebar.vue index ba885889e..21f46e335 100644 --- a/src/themes/default/components/core/blocks/Category/Sidebar.vue +++ b/src/themes/default/components/core/blocks/Category/Sidebar.vue @@ -24,8 +24,8 @@ code="color" v-for="(color, index) in filter" :key="index" - :id="color.id" - :label="color.label" + :variant="color" + @change="$emit('changeFilter', {name: filterIndex, value: $event})" />
@@ -35,8 +35,8 @@ class="size-select mr10 mb10" v-for="(size, index) in sortById(filter)" :key="index" - :id="size.id" - :label="size.label" + :variant="size" + @change="$emit('changeFilter', {name: filterIndex, value: $event})" />
@@ -50,6 +50,8 @@ :from="price.from" :to="price.to" :content="price.label" + :variant="price" + @change="$emit('changeFilter', {name: filterIndex, value: $event})" />
@@ -96,7 +98,17 @@ export default { PriceSelector, GenericSelector }, - mixins: [Sidebar] + mixins: [Sidebar], + computed: { + hasActiveFilters () { + return true + } + }, + methods: { + resetAllFilters () { + this.$store.dispatch('category-magento/resetFilters') + } + } } From 54a231be6c7e8203bd99987a2ac1ee684d80d186 Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 9 May 2019 21:43:29 +0200 Subject: [PATCH 0014/1227] migrate category page --- src/themes/default/pages/Category.vue | 57 +++++++++++++++++++++------ 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/src/themes/default/pages/Category.vue b/src/themes/default/pages/Category.vue index 1d59f2caf..b4efcb363 100644 --- a/src/themes/default/pages/Category.vue +++ b/src/themes/default/pages/Category.vue @@ -23,13 +23,16 @@
- +
close
- +

{{ productsTotal }} {{ $t('items') }}

@@ -45,12 +48,12 @@ From f45fe5b579e7580b27ab2a8bd43eded7d705ce6c Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Fri, 10 May 2019 10:17:59 +0200 Subject: [PATCH 0015/1227] filters and currentCategory as getters --- .../catalog-magento/store/category/actions.ts | 27 ++---------------- .../catalog-magento/store/category/getters.ts | 28 +++++++++++++++++-- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 36d635bdb..1f27edfd2 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -24,31 +24,10 @@ const actions: ActionTree = { await dispatch('getAvailableFilters') } }, - async getCurrentFilters ({ getters, rootState }, filters) { - const currentQuery = filters ? filters : rootState.route.query - const chosenFilter = {} - Object.keys(currentQuery).map(filterKey => { - const filter = getters.getAvailableFilters[filterKey] - const queryValue = currentQuery[filterKey] - if (Array.isArray(queryValue)) { - queryValue.map(singleValue => { - const variant = filter.find(filterVariant => filterVariant.id === singleValue) - if (!chosenFilter[filterKey] || !Array.isArray(chosenFilter[filterKey])) chosenFilter[filterKey] = [] - chosenFilter[filterKey].push({...variant, attribute_code: filterKey}) - }) - } else { - const variant = filter.find(filterVariant => filterVariant.id === queryValue) - chosenFilter[filterKey] = {...variant, attribute_code: filterKey} - } - }) - return chosenFilter - }, - async searchProducts ({ commit, getters, dispatch }, { category, filters } = {}) { + async searchProducts ({ commit, getters, dispatch }, { filters, route } = {}) { await dispatch('initCategoryModule') - console.error("SEARCH IN: " + router.currentRoute.fullPath) - // const category = await store.dispatch('category/single', { key: store.state.config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: route.params.slug }) - const currentFilters = await dispatch('getCurrentFilters', filters) - const searchCategory = category ? category : getters.getCurrentCategory // await dispatch('getCurrentCategory') + const currentFilters = getters.calculateFilters(filters) + const searchCategory = getters.calculateCurrentCategory(route) let filterQr = buildFilterProductsQuery(searchCategory, currentFilters) const searchResult = await quickSearchByQuery({ query: filterQr }) commit(types.CATEGORY_SET_PRODUCTS, searchResult.items) diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index a5bf0c4cd..12e9fa855 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -6,8 +6,32 @@ const getters: GetterTree = { getCategories: (state) => state.categories, getCategoryProducts: (state) => state.products, getAvailableFilters: state => state.availableFilters, - getCurrentCategory: (state, getters, routeState) => { - return getters.getCategories.find(category => routeState.route.path.includes(category.url_path)) || {} + calculateCurrentCategory: (state, getters, rootState) => (route) => { + const currentRoute = route ? route : rootState.route + return getters.getCategories.find(category => currentRoute.path.includes(category.url_path)) || {} + }, + getCurrentCategory: (state, getters) => getters.calculateCurrentCategory(), + calculateFilters: (state, getters, rootState) => (filters) => { + const currentQuery = filters ? filters : rootState.route.query + const chosenFilter = {} + Object.keys(currentQuery).map(filterKey => { + const filter = getters.getAvailableFilters[filterKey] + const queryValue = currentQuery[filterKey] + if (Array.isArray(queryValue)) { + queryValue.map(singleValue => { + const variant = filter.find(filterVariant => filterVariant.id === singleValue) + if (!chosenFilter[filterKey] || !Array.isArray(chosenFilter[filterKey])) chosenFilter[filterKey] = [] + chosenFilter[filterKey].push({...variant, attribute_code: filterKey}) + }) + } else { + const variant = filter.find(filterVariant => filterVariant.id === queryValue) + chosenFilter[filterKey] = {...variant, attribute_code: filterKey} + } + }) + return chosenFilter + }, + getCurrentFilters: (state, getters) => { + return getters.calculateFilters() } } From d027a4c08d72c471b6924ffe9c22bb372290de46 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Fri, 10 May 2019 10:22:00 +0200 Subject: [PATCH 0016/1227] active filters --- core/modules/catalog-magento/store/category/getters.ts | 3 ++- src/themes/default/components/core/blocks/Category/Sidebar.vue | 2 +- src/themes/default/pages/Category.vue | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index 12e9fa855..173d45fc3 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -32,7 +32,8 @@ const getters: GetterTree = { }, getCurrentFilters: (state, getters) => { return getters.calculateFilters() - } + }, + hasActiveFilters: (state, getters) => !!Object.keys(getters.getCurrentFilters).length } export default getters diff --git a/src/themes/default/components/core/blocks/Category/Sidebar.vue b/src/themes/default/components/core/blocks/Category/Sidebar.vue index 21f46e335..66f7fceba 100644 --- a/src/themes/default/components/core/blocks/Category/Sidebar.vue +++ b/src/themes/default/components/core/blocks/Category/Sidebar.vue @@ -101,7 +101,7 @@ export default { mixins: [Sidebar], computed: { hasActiveFilters () { - return true + return this.$store.getters['category-magento/hasActiveFilters'] } }, methods: { diff --git a/src/themes/default/pages/Category.vue b/src/themes/default/pages/Category.vue index b4efcb363..6e92dc3d4 100644 --- a/src/themes/default/pages/Category.vue +++ b/src/themes/default/pages/Category.vue @@ -97,7 +97,7 @@ export default { includeFields: config.entities.optimize && isServer ? config.entities.attribute.includeFields : null }) // // const category = await store.dispatch('category/single', { key: store.state.config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: route.params.slug }) - await store.dispatch('category-magento/searchProducts', {filters: route.query}) + await store.dispatch('category-magento/searchProducts', {filters: route.query, route}) } catch (e) { console.error('Problem with Category asyncData', e) } From 8e71fdf6c4b1852852bb84a2b1cc73bab48cea13 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Fri, 10 May 2019 11:54:52 +0200 Subject: [PATCH 0017/1227] recomputing getters --- core/modules/catalog-magento/store/category/getters.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index 173d45fc3..0a6f5f292 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -10,7 +10,7 @@ const getters: GetterTree = { const currentRoute = route ? route : rootState.route return getters.getCategories.find(category => currentRoute.path.includes(category.url_path)) || {} }, - getCurrentCategory: (state, getters) => getters.calculateCurrentCategory(), + getCurrentCategory: (state, getters, rootState) => getters.calculateCurrentCategory(rootState.route), calculateFilters: (state, getters, rootState) => (filters) => { const currentQuery = filters ? filters : rootState.route.query const chosenFilter = {} @@ -30,9 +30,7 @@ const getters: GetterTree = { }) return chosenFilter }, - getCurrentFilters: (state, getters) => { - return getters.calculateFilters() - }, + getCurrentFilters: (state, getters, rootState) => getters.calculateFilters(rootState.route.query), hasActiveFilters: (state, getters) => !!Object.keys(getters.getCurrentFilters).length } From 8f9e79553b8bab185c559f82585a8ceb7bceec59 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Fri, 10 May 2019 11:56:17 +0200 Subject: [PATCH 0018/1227] ui active filters --- .../default/components/core/blocks/Category/Sidebar.vue | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/themes/default/components/core/blocks/Category/Sidebar.vue b/src/themes/default/components/core/blocks/Category/Sidebar.vue index 66f7fceba..a690313e5 100644 --- a/src/themes/default/components/core/blocks/Category/Sidebar.vue +++ b/src/themes/default/components/core/blocks/Category/Sidebar.vue @@ -25,6 +25,7 @@ v-for="(color, index) in filter" :key="index" :variant="color" + :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === color.id" @change="$emit('changeFilter', {name: filterIndex, value: $event})" />
@@ -36,6 +37,7 @@ v-for="(size, index) in sortById(filter)" :key="index" :variant="size" + :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === size.id" @change="$emit('changeFilter', {name: filterIndex, value: $event})" />
@@ -51,6 +53,7 @@ :to="price.to" :content="price.label" :variant="price" + :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === price.id" @change="$emit('changeFilter', {name: filterIndex, value: $event})" />
@@ -62,6 +65,7 @@ v-for="(option, index) in filter" :key="index" :variant="option" + :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === option.id" @change="$emit('changeFilter', {name: filterIndex, value: $event})" /> @@ -102,6 +106,9 @@ export default { computed: { hasActiveFilters () { return this.$store.getters['category-magento/hasActiveFilters'] + }, + getCurrentFilters () { + return this.$store.getters['category-magento/getCurrentFilters'] } }, methods: { From f5cdd82f31832b9ec1e613db0bc60cfd7d1ada8a Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Fri, 10 May 2019 16:09:16 +0200 Subject: [PATCH 0019/1227] add sorty by property --- .../catalog-magento/store/category/actions.ts | 31 +++++++++++++------ .../catalog-magento/store/category/getters.ts | 23 +++++++++----- .../catalog-magento/types/FilterVariant.ts | 7 +++++ .../catalog/components/CategorySort.ts | 14 ++++++++- src/themes/default/components/core/SortBy.vue | 2 +- .../core/blocks/Category/Sidebar.vue | 8 ++--- src/themes/default/pages/Category.vue | 4 +-- 7 files changed, 64 insertions(+), 25 deletions(-) create mode 100644 core/modules/catalog-magento/types/FilterVariant.ts diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 1f27edfd2..3ef036747 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -11,6 +11,7 @@ import toString from 'lodash-es/toString' import { currentStoreView } from '@vue-storefront/core/lib/multistore' import { optionLabel } from '../../helpers/optionLabel' import { router } from '@vue-storefront/core/app' +import FilterVariant from '../../types/FilterVariant'; const actions: ActionTree = { /** @@ -26,10 +27,10 @@ const actions: ActionTree = { }, async searchProducts ({ commit, getters, dispatch }, { filters, route } = {}) { await dispatch('initCategoryModule') - const currentFilters = getters.calculateFilters(filters) + const searchQuery = getters.calculateFilters(filters) const searchCategory = getters.calculateCurrentCategory(route) - let filterQr = buildFilterProductsQuery(searchCategory, currentFilters) - const searchResult = await quickSearchByQuery({ query: filterQr }) + let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters) + const searchResult = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort }) commit(types.CATEGORY_SET_PRODUCTS, searchResult.items) return searchResult.items @@ -56,7 +57,7 @@ const actions: ActionTree = { const searchResult = await quickSearchByQuery({ query: filterQr }) if (searchResult && searchResult.aggregations) { // populate filter aggregates for (let attrToFilter of config.products.defaultFilters) { // fill out the filter options - let filterOptions = [] + let filterOptions:Array = [] let uniqueFilterValues = new Set() if (attrToFilter !== 'price') { @@ -76,7 +77,8 @@ const actions: ActionTree = { if (trim(label) !== '') { // is there any situation when label could be empty and we should still support it? filterOptions.push({ id: key, - label: label + label: label, + type: attrToFilter }) } }); @@ -89,6 +91,7 @@ const actions: ActionTree = { for (let option of searchResult.aggregations['agg_range_' + attrToFilter].buckets) { filterOptions.push({ id: option.key, + type: attrToFilter, from: option.from, to: option.to, label: (index === 0 || (index === count - 1)) ? (option.to ? '< ' + currencySign + option.to : '> ' + currencySign + option.from) : currencySign + option.from + (option.to ? ' - ' + option.to : '')// TODO: add better way for formatting, extract currency sign @@ -99,15 +102,25 @@ const actions: ActionTree = { } filters[attrToFilter] = filterOptions } + // Add sort to available filters + let variants = [] + Object.keys(config.products.sortByAttributes).map(label => { + variants.push({ + label: label, + id: config.products.sortByAttributes[label], + type: 'sort' + }) + }) + filters['sort'] = variants } commit(types.CATEGORY_SET_AVAILABLE_FILTERS, filters) }, - async switchSearchFilter({ dispatch }, filterVariant) { + async switchSearchFilter({ dispatch }, filterVariant:FilterVariant) { const query = Object.assign({}, router.currentRoute.query) // await dispatch('getCurrentFilters') - if(query[filterVariant.name] && query[filterVariant.name] === filterVariant.value.id) { - delete query[filterVariant.name] + if(query[filterVariant.type] && query[filterVariant.type] === filterVariant.id) { + delete query[filterVariant.type] } else { - query[filterVariant.name] = filterVariant.value.id + query[filterVariant.type] = filterVariant.id } router.push({query}) }, diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index 0a6f5f292..ce4560101 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -2,6 +2,8 @@ import { GetterTree } from 'vuex' import RootState from '@vue-storefront/core/types/RootState' import CategoryState from './CategoryState' +const specialFields = ['sort'] + const getters: GetterTree = { getCategories: (state) => state.categories, getCategoryProducts: (state) => state.products, @@ -13,24 +15,29 @@ const getters: GetterTree = { getCurrentCategory: (state, getters, rootState) => getters.calculateCurrentCategory(rootState.route), calculateFilters: (state, getters, rootState) => (filters) => { const currentQuery = filters ? filters : rootState.route.query - const chosenFilter = {} - Object.keys(currentQuery).map(filterKey => { + const searchQuery = { + filters: {} + } + Object.keys(currentQuery).forEach(filterKey => { const filter = getters.getAvailableFilters[filterKey] const queryValue = currentQuery[filterKey] - if (Array.isArray(queryValue)) { + if (!filter) return + if (specialFields.includes(filterKey)) { + searchQuery[filterKey] = queryValue + } else if (Array.isArray(queryValue)) { queryValue.map(singleValue => { const variant = filter.find(filterVariant => filterVariant.id === singleValue) - if (!chosenFilter[filterKey] || !Array.isArray(chosenFilter[filterKey])) chosenFilter[filterKey] = [] - chosenFilter[filterKey].push({...variant, attribute_code: filterKey}) + if (!searchQuery.filters[filterKey] || !Array.isArray(searchQuery.filters[filterKey])) searchQuery.filters[filterKey] = [] + searchQuery.filters[filterKey].push({...variant, attribute_code: filterKey}) }) } else { const variant = filter.find(filterVariant => filterVariant.id === queryValue) - chosenFilter[filterKey] = {...variant, attribute_code: filterKey} + searchQuery.filters[filterKey] = {...variant, attribute_code: filterKey} } }) - return chosenFilter + return searchQuery }, - getCurrentFilters: (state, getters, rootState) => getters.calculateFilters(rootState.route.query), + getCurrentFilters: (state, getters, rootState) => getters.calculateFilters(rootState.route.query).filters, hasActiveFilters: (state, getters) => !!Object.keys(getters.getCurrentFilters).length } diff --git a/core/modules/catalog-magento/types/FilterVariant.ts b/core/modules/catalog-magento/types/FilterVariant.ts new file mode 100644 index 000000000..e85e1c903 --- /dev/null +++ b/core/modules/catalog-magento/types/FilterVariant.ts @@ -0,0 +1,7 @@ +export default interface FilterVariant { + id: string, + label: string, + type: string, + from?: string, + to?: string +} diff --git a/core/modules/catalog/components/CategorySort.ts b/core/modules/catalog/components/CategorySort.ts index 9c867979d..92da01e9c 100644 --- a/core/modules/catalog/components/CategorySort.ts +++ b/core/modules/catalog/components/CategorySort.ts @@ -8,12 +8,24 @@ export const CategorySort = { methods: { // emit to category, todo: move all logic inside sort () { - this.$bus.$emit('list-change-sort', { attribute: this.sortby }) + this.$emit('sortChange', this.sortby) + // this.$bus.$emit('list-change-sort', { attribute: this.sortby }) } }, computed: { sortingOptions () { return this.$store.state.config.products.sortByAttributes + }, + sortingVariants () { + let variants = [] + Object.keys(this.sortingOptions).map(label => { + variants.push({ + label: label, + id: this.sortingOptions[label], + type: 'sort' + }) + }) + return variants } } } diff --git a/src/themes/default/components/core/SortBy.vue b/src/themes/default/components/core/SortBy.vue index 5a438bcc0..aae87a48c 100644 --- a/src/themes/default/components/core/SortBy.vue +++ b/src/themes/default/components/core/SortBy.vue @@ -6,7 +6,7 @@ v-model="sortby" @change="changeOrder"> - + diff --git a/src/themes/default/components/core/blocks/Category/Sidebar.vue b/src/themes/default/components/core/blocks/Category/Sidebar.vue index a690313e5..a1d7c65a7 100644 --- a/src/themes/default/components/core/blocks/Category/Sidebar.vue +++ b/src/themes/default/components/core/blocks/Category/Sidebar.vue @@ -26,7 +26,7 @@ :key="index" :variant="color" :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === color.id" - @change="$emit('changeFilter', {name: filterIndex, value: $event})" + @change="$emit('changeFilter', $event)" />
@@ -38,7 +38,7 @@ :key="index" :variant="size" :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === size.id" - @change="$emit('changeFilter', {name: filterIndex, value: $event})" + @change="$emit('changeFilter', $event)" />
@@ -54,7 +54,7 @@ :content="price.label" :variant="price" :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === price.id" - @change="$emit('changeFilter', {name: filterIndex, value: $event})" + @change="$emit('changeFilter', $event)" />
diff --git a/src/themes/default/pages/Category.vue b/src/themes/default/pages/Category.vue index 6e92dc3d4..f05d26b3a 100644 --- a/src/themes/default/pages/Category.vue +++ b/src/themes/default/pages/Category.vue @@ -5,7 +5,7 @@

{{ category.name }}

-
+
@@ -16,7 +16,7 @@ > {{ $t('Filters') }} -
+
From 0a9f7d5eb898e17711001029ed68e1144cd38bb6 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Mon, 13 May 2019 13:51:44 +0200 Subject: [PATCH 0020/1227] system filters not visible on search filters --- core/compatibility/components/blocks/Category/Sidebar.js | 2 +- core/modules/catalog-magento/store/category/getters.ts | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/compatibility/components/blocks/Category/Sidebar.js b/core/compatibility/components/blocks/Category/Sidebar.js index 71cc2699e..02dffaa6d 100644 --- a/core/compatibility/components/blocks/Category/Sidebar.js +++ b/core/compatibility/components/blocks/Category/Sidebar.js @@ -19,7 +19,7 @@ export default { return this.getActiveCategoryFilters }, availableFilters () { - return pickBy(this.filters, (filter) => { return (filter.length) }) + return pickBy(this.filters, (filter, filterType) => { return (filter.length && !this.$store.getters['category-magento/getSystemFilterNames'].includes(filterType)) }) }, hasActiveFilters () { return Object.keys(this.activeFilters).length !== 0 diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index ce4560101..c77458555 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -2,8 +2,6 @@ import { GetterTree } from 'vuex' import RootState from '@vue-storefront/core/types/RootState' import CategoryState from './CategoryState' -const specialFields = ['sort'] - const getters: GetterTree = { getCategories: (state) => state.categories, getCategoryProducts: (state) => state.products, @@ -22,7 +20,7 @@ const getters: GetterTree = { const filter = getters.getAvailableFilters[filterKey] const queryValue = currentQuery[filterKey] if (!filter) return - if (specialFields.includes(filterKey)) { + if (getters.getSystemFilterNames.includes(filterKey)) { searchQuery[filterKey] = queryValue } else if (Array.isArray(queryValue)) { queryValue.map(singleValue => { @@ -38,7 +36,8 @@ const getters: GetterTree = { return searchQuery }, getCurrentFilters: (state, getters, rootState) => getters.calculateFilters(rootState.route.query).filters, - hasActiveFilters: (state, getters) => !!Object.keys(getters.getCurrentFilters).length + hasActiveFilters: (state, getters) => !!Object.keys(getters.getCurrentFilters).length, + getSystemFilterNames: () => ['sort'] } export default getters From f979051d14e46ada9e2284cf11625f02e684d06f Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Mon, 13 May 2019 13:51:58 +0200 Subject: [PATCH 0021/1227] get turned off by default --- src/modules/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/index.ts b/src/modules/index.ts index c5ee936dd..baa823400 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -18,7 +18,7 @@ import { PromotedOffers } from './promoted-offers' import { Ui } from './ui-store' // import { GoogleAnalytics } from './google-analytics'; // import { Hotjar } from './hotjar'; -import { googleTagManager } from './google-tag-manager'; +// import { googleTagManager } from './google-tag-manager'; import { AmpRenderer } from './amp-renderer'; import { PaymentBackendMethods } from './payment-backend-methods'; import { PaymentCashOnDelivery } from './payment-cash-on-delivery'; @@ -69,7 +69,7 @@ export const registerModules: VueStorefrontModule[] = [ Claims, PromotedOffers, Magento2CMS, - googleTagManager, + // googleTagManager, // GoogleAnalytics, // Hotjar, PaymentBackendMethods, From fece9d5873055479e3a7c0a236541663c08599c0 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Mon, 13 May 2019 17:17:33 +0200 Subject: [PATCH 0022/1227] add category breadcrumbs --- .../catalog-magento/helpers/categoryHelpers.ts | 12 ++++++++++++ .../catalog-magento/store/category/actions.ts | 3 --- .../catalog-magento/store/category/getters.ts | 7 ++++++- src/themes/default/pages/Category.vue | 8 +++----- 4 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 core/modules/catalog-magento/helpers/categoryHelpers.ts diff --git a/core/modules/catalog-magento/helpers/categoryHelpers.ts b/core/modules/catalog-magento/helpers/categoryHelpers.ts new file mode 100644 index 000000000..804466ca1 --- /dev/null +++ b/core/modules/catalog-magento/helpers/categoryHelpers.ts @@ -0,0 +1,12 @@ +import { parseCategoryPath } from '@vue-storefront/core/modules/breadcrumbs/helpers' + +export const calculateBreadcrumbs = (categories, id, list = []) => { + const category = categories.find(category => category.id === id) + if (!category) return parseCategoryPath(list).reverse() + const result = [...list, category] + + if(category.level > 1 && category.parent_id) { + return calculateBreadcrumbs(categories, category.parent_id, result) + } + return parseCategoryPath(result).reverse() +} diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 3ef036747..a5f8ade43 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -35,9 +35,6 @@ const actions: ActionTree = { return searchResult.items }, - async getCurrentCategory ({ dispatch, rootState }) { - return await dispatch('category/single', { key: config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: rootState.route.params.slug }, {root: true}) - }, async fetchCategories ({ dispatch }) { const res = await dispatch('category/list', {}, {root: true}) return res.items diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index c77458555..d711fd388 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -1,6 +1,7 @@ import { GetterTree } from 'vuex' import RootState from '@vue-storefront/core/types/RootState' import CategoryState from './CategoryState' +import { calculateBreadcrumbs } from '../../helpers/categoryHelpers' const getters: GetterTree = { getCategories: (state) => state.categories, @@ -37,7 +38,11 @@ const getters: GetterTree = { }, getCurrentFilters: (state, getters, rootState) => getters.calculateFilters(rootState.route.query).filters, hasActiveFilters: (state, getters) => !!Object.keys(getters.getCurrentFilters).length, - getSystemFilterNames: () => ['sort'] + getSystemFilterNames: () => ['sort'], + getBreadcrumbs: (state, getters) => { + if (!getters.getCurrentCategory) return [] + return calculateBreadcrumbs(getters.getCategories, getters.getCurrentCategory.id) + } } export default getters diff --git a/src/themes/default/pages/Category.vue b/src/themes/default/pages/Category.vue index f05d26b3a..a37b651e1 100644 --- a/src/themes/default/pages/Category.vue +++ b/src/themes/default/pages/Category.vue @@ -2,7 +2,7 @@
- +

{{ category.name }}

@@ -80,10 +80,8 @@ export default { isCategoryEmpty () { return this.productsTotal === 0 }, - breadcrumbs () { - return { - routes: [] - } + getBreadcrumbs () { + return this.$store.getters['category-magento/getBreadcrumbs'].filter(breadcrumb => breadcrumb.name !== this.category.name) }, getAvailableFilters () { return this.$store.getters['category-magento/getAvailableFilters'] From fb380e71d43867823217bae62a9c3f831ed62ed9 Mon Sep 17 00:00:00 2001 From: patzick Date: Mon, 13 May 2019 22:15:47 +0200 Subject: [PATCH 0023/1227] stop using of sidebar mixin --- .../components/core/blocks/Category/Sidebar.vue | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/themes/default/components/core/blocks/Category/Sidebar.vue b/src/themes/default/components/core/blocks/Category/Sidebar.vue index a1d7c65a7..2401a4cf0 100644 --- a/src/themes/default/components/core/blocks/Category/Sidebar.vue +++ b/src/themes/default/components/core/blocks/Category/Sidebar.vue @@ -88,12 +88,11 @@ diff --git a/src/themes/default/components/core/PriceSelector.vue b/src/themes/default/components/core/PriceSelector.vue index 7f8106920..b7800548d 100644 --- a/src/themes/default/components/core/PriceSelector.vue +++ b/src/themes/default/components/core/PriceSelector.vue @@ -12,17 +12,10 @@ diff --git a/src/themes/default/components/core/SizeSelector.vue b/src/themes/default/components/core/SizeSelector.vue index ae37d9500..dee7e628d 100644 --- a/src/themes/default/components/core/SizeSelector.vue +++ b/src/themes/default/components/core/SizeSelector.vue @@ -13,17 +13,10 @@ diff --git a/src/themes/default/components/core/blocks/Category/Sidebar.vue b/src/themes/default/components/core/blocks/Category/Sidebar.vue index 2401a4cf0..7cd4edb9a 100644 --- a/src/themes/default/components/core/blocks/Category/Sidebar.vue +++ b/src/themes/default/components/core/blocks/Category/Sidebar.vue @@ -25,7 +25,7 @@ v-for="(color, index) in filter" :key="index" :variant="color" - :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === color.id" + :selected-filters="getCurrentFilters" @change="$emit('changeFilter', $event)" />
@@ -37,7 +37,7 @@ v-for="(size, index) in sortById(filter)" :key="index" :variant="size" - :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === size.id" + :selected-filters="getCurrentFilters" @change="$emit('changeFilter', $event)" />
@@ -53,7 +53,7 @@ :to="price.to" :content="price.label" :variant="price" - :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === price.id" + :selected-filters="getCurrentFilters" @change="$emit('changeFilter', $event)" />
@@ -65,7 +65,7 @@ v-for="(option, index) in filter" :key="index" :variant="option" - :is-active="getCurrentFilters[filterIndex] && getCurrentFilters[filterIndex].id === option.id" + :selected-filters="getCurrentFilters" @change="$emit('changeFilter', $event)" /> diff --git a/src/themes/default/mixins/filterMixin.ts b/src/themes/default/mixins/filterMixin.ts new file mode 100644 index 000000000..3778ccb55 --- /dev/null +++ b/src/themes/default/mixins/filterMixin.ts @@ -0,0 +1,20 @@ +export default { + props: { + variant: { + type: Object, + default: () => ({}) + }, + selectedFilters: { + type: Object, + default: () => ({}) + } + }, + computed: { + isActive () { + const selectedVariantFilter = this.selectedFilters[this.variant.type] + if (!selectedVariantFilter) return false + if (Array.isArray(selectedVariantFilter)) return !!selectedVariantFilter.find(variant => variant.id === this.variant.id) + return selectedVariantFilter.id === this.variant.id + } + } +} From a819f6f28e982e3f8c19d4a04067f567eb00f75c Mon Sep 17 00:00:00 2001 From: patzick Date: Wed, 15 May 2019 11:37:20 +0200 Subject: [PATCH 0026/1227] refactor calculate getters --- core/modules/catalog-magento/store/category/actions.ts | 4 ++-- core/modules/catalog-magento/store/category/getters.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 4f8e12a97..bc1f6dc3b 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -27,8 +27,8 @@ const actions: ActionTree = { }, async searchProducts ({ commit, getters, dispatch }, { filters, route } = {}) { await dispatch('initCategoryModule') - const searchQuery = getters.calculateFilters(filters) - const searchCategory = getters.calculateCurrentCategory(route) + const searchQuery = getters.getCurrentFiltersFrom(filters) + const searchCategory = getters.getCurrentCategoryFrom(route) let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters) const searchResult = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort }) commit(types.CATEGORY_SET_PRODUCTS, searchResult.items) diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index d711fd388..4bb3fb187 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -7,12 +7,12 @@ const getters: GetterTree = { getCategories: (state) => state.categories, getCategoryProducts: (state) => state.products, getAvailableFilters: state => state.availableFilters, - calculateCurrentCategory: (state, getters, rootState) => (route) => { + getCurrentCategoryFrom: (state, getters, rootState) => (route = this.$route) => { const currentRoute = route ? route : rootState.route return getters.getCategories.find(category => currentRoute.path.includes(category.url_path)) || {} }, - getCurrentCategory: (state, getters, rootState) => getters.calculateCurrentCategory(rootState.route), - calculateFilters: (state, getters, rootState) => (filters) => { + getCurrentCategory: (state, getters, rootState) => getters.getCurrentCategoryFrom(rootState.route), + getCurrentFiltersFrom: (state, getters, rootState) => (filters) => { const currentQuery = filters ? filters : rootState.route.query const searchQuery = { filters: {} @@ -36,7 +36,7 @@ const getters: GetterTree = { }) return searchQuery }, - getCurrentFilters: (state, getters, rootState) => getters.calculateFilters(rootState.route.query).filters, + getCurrentFilters: (state, getters, rootState) => getters.getCurrentFiltersFrom(rootState.route.query).filters, hasActiveFilters: (state, getters) => !!Object.keys(getters.getCurrentFilters).length, getSystemFilterNames: () => ['sort'], getBreadcrumbs: (state, getters) => { From 25eabd735c154544787248f178fb2e73303fcee3 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Thu, 16 May 2019 10:49:46 +0200 Subject: [PATCH 0027/1227] move logic to getters --- .../catalog-magento/store/category/actions.ts | 89 ++++--------------- .../store/category/categoryLogic.ts | 10 +++ .../catalog-magento/store/category/getters.ts | 80 +++++++++++++++-- src/themes/default/pages/Category.vue | 2 +- 4 files changed, 100 insertions(+), 81 deletions(-) create mode 100644 core/modules/catalog-magento/store/category/categoryLogic.ts diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index bc1f6dc3b..8e16cc5a1 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -5,13 +5,8 @@ import RootState from '@vue-storefront/core/types/RootState' import CategoryState from './CategoryState' import { quickSearchByQuery } from '@vue-storefront/core/lib/search' import { buildFilterProductsQuery } from '@vue-storefront/core/helpers' -import config from 'config' -import trim from 'lodash-es/trim' -import toString from 'lodash-es/toString' -import { currentStoreView } from '@vue-storefront/core/lib/multistore' -import { optionLabel } from '../../helpers/optionLabel' import { router } from '@vue-storefront/core/app' -import FilterVariant from '../../types/FilterVariant'; +import FilterVariant from '../../types/FilterVariant' const actions: ActionTree = { /** @@ -21,95 +16,41 @@ const actions: ActionTree = { */ async initCategoryModule ({ getters, dispatch }) { if (!getters.getCategories.length) { - await dispatch('getCategories') - await dispatch('getAvailableFilters') + await dispatch('loadCategories') + await dispatch('loadCategoryFilters') } }, - async searchProducts ({ commit, getters, dispatch }, { filters, route } = {}) { + async loadCategoryProducts ({ commit, getters, dispatch }, { filters, route } = {}) { await dispatch('initCategoryModule') const searchQuery = getters.getCurrentFiltersFrom(filters) - const searchCategory = getters.getCurrentCategoryFrom(route) + const searchCategory = getters.getCategoryFrom(route.path) let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters) const searchResult = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort }) commit(types.CATEGORY_SET_PRODUCTS, searchResult.items) + // await dispatch('loadAvailableFiltersFrom', searchResult) return searchResult.items }, - async fetchCategories ({ dispatch }) { + async findCategories ({ dispatch }) { const res = await dispatch('category/list', {}, {root: true}) return res.items }, - async getCategories ({ commit, dispatch }) { - const categories = await dispatch('fetchCategories') + async loadCategories ({ commit, dispatch }) { + const categories = await dispatch('findCategories') commit(types.CATEGORY_SET_CATEGORIES, categories) return categories }, /** * Fetch and process filters from current category and sets them in available filters. */ - async getAvailableFilters ({ commit, getters, rootState }) { - const filters = {} - const searchCategory = getters.getCurrentCategory + async loadCategoryFilters ({ dispatch, getters }, category) { + const searchCategory = category ? category : getters.getCurrentCategory let filterQr = buildFilterProductsQuery(searchCategory) const searchResult = await quickSearchByQuery({ query: filterQr }) - if (searchResult && searchResult.aggregations) { // populate filter aggregates - for (let attrToFilter of config.products.defaultFilters) { // fill out the filter options - let filterOptions:Array = [] - - let uniqueFilterValues = new Set() - if (attrToFilter !== 'price') { - if (searchResult.aggregations['agg_terms_' + attrToFilter]) { - let buckets = searchResult.aggregations['agg_terms_' + attrToFilter].buckets - if (searchResult.aggregations['agg_terms_' + attrToFilter + '_options']) { - buckets = buckets.concat(searchResult.aggregations['agg_terms_' + attrToFilter + '_options'].buckets) - } - - for (let option of buckets) { - uniqueFilterValues.add(toString(option.key)) - } - } - - uniqueFilterValues.forEach(key => { - const label = optionLabel(rootState.attribute, { attributeKey: attrToFilter, optionId: key }) - if (trim(label) !== '') { // is there any situation when label could be empty and we should still support it? - filterOptions.push({ - id: key, - label: label, - type: attrToFilter - }) - } - }); - } else { // special case is range filter for prices - const storeView = currentStoreView() - const currencySign = storeView.i18n.currencySign - if (searchResult.aggregations['agg_range_' + attrToFilter]) { - let index = 0 - let count = searchResult.aggregations['agg_range_' + attrToFilter].buckets.length - for (let option of searchResult.aggregations['agg_range_' + attrToFilter].buckets) { - filterOptions.push({ - id: option.key, - type: attrToFilter, - from: option.from, - to: option.to, - label: (index === 0 || (index === count - 1)) ? (option.to ? '< ' + currencySign + option.to : '> ' + currencySign + option.from) : currencySign + option.from + (option.to ? ' - ' + option.to : '')// TODO: add better way for formatting, extract currency sign - }) - index++ - } - } - } - filters[attrToFilter] = filterOptions - } - // Add sort to available filters - let variants = [] - Object.keys(config.products.sortByAttributes).map(label => { - variants.push({ - label: label, - id: config.products.sortByAttributes[label], - type: 'sort' - }) - }) - filters['sort'] = variants - } + await dispatch('loadAvailableFiltersFrom', searchResult) + }, + async loadAvailableFiltersFrom ({ commit, getters }, {aggregations}) { + const filters = getters.getAvailableFiltersFrom(aggregations) commit(types.CATEGORY_SET_AVAILABLE_FILTERS, filters) }, async switchSearchFilter({ dispatch }, filterVariant:FilterVariant) { diff --git a/core/modules/catalog-magento/store/category/categoryLogic.ts b/core/modules/catalog-magento/store/category/categoryLogic.ts new file mode 100644 index 000000000..d16733393 --- /dev/null +++ b/core/modules/catalog-magento/store/category/categoryLogic.ts @@ -0,0 +1,10 @@ + +export const compareByLabel = ( a, b ) => { + if ( a.label < b.label ){ + return -1 + } + if ( a.label > b.label ){ + return 1 + } + return 0 +} diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index 4bb3fb187..2f1de3c36 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -2,16 +2,84 @@ import { GetterTree } from 'vuex' import RootState from '@vue-storefront/core/types/RootState' import CategoryState from './CategoryState' import { calculateBreadcrumbs } from '../../helpers/categoryHelpers' +import { products } from 'config' +import FilterVariant from '../../types/FilterVariant' +import { optionLabel } from '../../helpers/optionLabel' +import trim from 'lodash-es/trim' +import toString from 'lodash-es/toString' +import { compareByLabel } from './categoryLogic' const getters: GetterTree = { - getCategories: (state) => state.categories, + getCategories: (state) => state.categories || [], getCategoryProducts: (state) => state.products, - getAvailableFilters: state => state.availableFilters, - getCurrentCategoryFrom: (state, getters, rootState) => (route = this.$route) => { - const currentRoute = route ? route : rootState.route - return getters.getCategories.find(category => currentRoute.path.includes(category.url_path)) || {} + getCategoryFrom: (state, getters) => (path:string = '') => { + return getters.getCategories.find(category => path.includes(category.url_path)) || {} }, - getCurrentCategory: (state, getters, rootState) => getters.getCurrentCategoryFrom(rootState.route), + getCurrentCategory: (state, getters, rootState) => getters.getCategoryFrom(rootState.route.path), + getAvailableFiltersFrom: (state, getters, rootState) => (aggregations) => { + const filters = {} + if (aggregations) { // populate filter aggregates + for (let attrToFilter of products.defaultFilters) { // fill out the filter options + let filterOptions:Array = [] + + let uniqueFilterValues = new Set() + if (attrToFilter !== 'price') { + if (aggregations['agg_terms_' + attrToFilter]) { + let buckets = aggregations['agg_terms_' + attrToFilter].buckets + if (aggregations['agg_terms_' + attrToFilter + '_options']) { + buckets = buckets.concat(aggregations['agg_terms_' + attrToFilter + '_options'].buckets) + } + + for (let option of buckets) { + uniqueFilterValues.add(toString(option.key)) + } + } + + uniqueFilterValues.forEach(key => { + const label = optionLabel(rootState.attribute, { attributeKey: attrToFilter, optionId: key }) + if (trim(label) !== '') { // is there any situation when label could be empty and we should still support it? + filterOptions.push({ + id: key, + label: label, + type: attrToFilter + }) + } + }); + filters[attrToFilter] = filterOptions.sort(compareByLabel) + } else { // special case is range filter for prices + const storeView = rootState.storeView + const currencySign = storeView.i18n.currencySign + if (aggregations['agg_range_' + attrToFilter]) { + let index = 0 + let count = aggregations['agg_range_' + attrToFilter].buckets.length + for (let option of aggregations['agg_range_' + attrToFilter].buckets) { + filterOptions.push({ + id: option.key, + type: attrToFilter, + from: option.from, + to: option.to, + label: (index === 0 || (index === count - 1)) ? (option.to ? '< ' + currencySign + option.to : '> ' + currencySign + option.from) : currencySign + option.from + (option.to ? ' - ' + option.to : '')// TODO: add better way for formatting, extract currency sign + }) + index++ + } + filters[attrToFilter] = filterOptions + } + } + } + // Add sort to available filters + let variants = [] + Object.keys(products.sortByAttributes).map(label => { + variants.push({ + label: label, + id: products.sortByAttributes[label], + type: 'sort' + }) + }) + filters['sort'] = variants + } + return filters + }, + getAvailableFilters: state => state.availableFilters, getCurrentFiltersFrom: (state, getters, rootState) => (filters) => { const currentQuery = filters ? filters : rootState.route.query const searchQuery = { diff --git a/src/themes/default/pages/Category.vue b/src/themes/default/pages/Category.vue index a37b651e1..6a149544c 100644 --- a/src/themes/default/pages/Category.vue +++ b/src/themes/default/pages/Category.vue @@ -95,7 +95,7 @@ export default { includeFields: config.entities.optimize && isServer ? config.entities.attribute.includeFields : null }) // // const category = await store.dispatch('category/single', { key: store.state.config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: route.params.slug }) - await store.dispatch('category-magento/searchProducts', {filters: route.query, route}) + await store.dispatch('category-magento/loadCategoryProducts', {filters: route.query, route}) } catch (e) { console.error('Problem with Category asyncData', e) } From 652afe0ce519858025d4482023ffa4c03ec60414 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Thu, 16 May 2019 10:55:17 +0200 Subject: [PATCH 0028/1227] move logic to directory --- core/modules/catalog-magento/store/category/getters.ts | 2 +- .../catalog-magento/store/category/{ => logic}/categoryLogic.ts | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename core/modules/catalog-magento/store/category/{ => logic}/categoryLogic.ts (100%) diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index 2f1de3c36..9c34e6947 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -7,7 +7,7 @@ import FilterVariant from '../../types/FilterVariant' import { optionLabel } from '../../helpers/optionLabel' import trim from 'lodash-es/trim' import toString from 'lodash-es/toString' -import { compareByLabel } from './categoryLogic' +import { compareByLabel } from './logic/categoryLogic' const getters: GetterTree = { getCategories: (state) => state.categories || [], diff --git a/core/modules/catalog-magento/store/category/categoryLogic.ts b/core/modules/catalog-magento/store/category/logic/categoryLogic.ts similarity index 100% rename from core/modules/catalog-magento/store/category/categoryLogic.ts rename to core/modules/catalog-magento/store/category/logic/categoryLogic.ts From 767aa6d1d9b7b7f7cc95e1844a8cd5f8aaa11854 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Thu, 16 May 2019 12:55:47 +0200 Subject: [PATCH 0029/1227] change loadCategory invocation --- core/modules/catalog-magento/store/category/actions.ts | 4 ++-- src/themes/default/pages/Category.vue | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 8e16cc5a1..7716c887a 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -20,9 +20,9 @@ const actions: ActionTree = { await dispatch('loadCategoryFilters') } }, - async loadCategoryProducts ({ commit, getters, dispatch }, { filters, route } = {}) { + async loadCategoryProducts ({ commit, getters, dispatch }, { route } = {}) { await dispatch('initCategoryModule') - const searchQuery = getters.getCurrentFiltersFrom(filters) + const searchQuery = getters.getCurrentFiltersFrom(route.query) const searchCategory = getters.getCategoryFrom(route.path) let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters) const searchResult = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort }) diff --git a/src/themes/default/pages/Category.vue b/src/themes/default/pages/Category.vue index 6a149544c..7951fda34 100644 --- a/src/themes/default/pages/Category.vue +++ b/src/themes/default/pages/Category.vue @@ -95,7 +95,7 @@ export default { includeFields: config.entities.optimize && isServer ? config.entities.attribute.includeFields : null }) // // const category = await store.dispatch('category/single', { key: store.state.config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: route.params.slug }) - await store.dispatch('category-magento/loadCategoryProducts', {filters: route.query, route}) + await store.dispatch('category-magento/loadCategoryProducts', {route}) } catch (e) { console.error('Problem with Category asyncData', e) } From bb6d9d9bbafb9bf3da8f06b7ebabecd9ab23c135 Mon Sep 17 00:00:00 2001 From: Vishal Sutariya Date: Fri, 17 May 2019 10:36:55 +0530 Subject: [PATCH 0030/1227] Added badges to the icon to display item count --- .../components/blocks/Header/CompareIcon.js | 3 +++ .../components/blocks/Header/WishlistIcon.js | 3 +++ .../compare/components/CompareButton.ts | 3 +++ core/modules/compare/store/getters.ts | 3 ++- .../wishlist/components/WishlistButton.ts | 5 +++++ core/modules/wishlist/store/index.ts | 3 ++- .../core/blocks/Header/CompareIcon.vue | 17 +++++++++++++++++ .../core/blocks/Header/WishlistIcon.vue | 19 ++++++++++++++++++- 8 files changed, 53 insertions(+), 3 deletions(-) diff --git a/core/compatibility/components/blocks/Header/CompareIcon.js b/core/compatibility/components/blocks/Header/CompareIcon.js index 5b12a1638..26922ae0a 100644 --- a/core/compatibility/components/blocks/Header/CompareIcon.js +++ b/core/compatibility/components/blocks/Header/CompareIcon.js @@ -7,6 +7,9 @@ export default { isActive () { // Computed Property renamed to 'isEmpty' return !this.isEmpty + }, + getTotalProducts () { + return this.totalProducts } } } diff --git a/core/compatibility/components/blocks/Header/WishlistIcon.js b/core/compatibility/components/blocks/Header/WishlistIcon.js index 8cc9d63af..76d967961 100644 --- a/core/compatibility/components/blocks/Header/WishlistIcon.js +++ b/core/compatibility/components/blocks/Header/WishlistIcon.js @@ -13,6 +13,9 @@ export default { // deprecated in this component isWishlistOpen () { return this.$store.state.ui.wishlist + }, + getwishlistItemsCount () { + return this.$store.getters['wishlist/wishlistItemCount'] } }, methods: { diff --git a/core/modules/compare/components/CompareButton.ts b/core/modules/compare/components/CompareButton.ts index 704aef9fd..bbe89168a 100644 --- a/core/modules/compare/components/CompareButton.ts +++ b/core/modules/compare/components/CompareButton.ts @@ -6,6 +6,9 @@ export const CompareButton = { computed: { isEmpty () : boolean { return this.$store.getters['compare/isEmpty'] + }, + totalProducts () { + return this.$store.getters['compare/totalProducts'] } } } diff --git a/core/modules/compare/store/getters.ts b/core/modules/compare/store/getters.ts index c5aeb19d8..e693c3c06 100644 --- a/core/modules/compare/store/getters.ts +++ b/core/modules/compare/store/getters.ts @@ -5,7 +5,8 @@ import CompareState from '../types/CompareState' const getters: GetterTree = { isEmpty: (state) => state.items.length === 0, isOnCompare: (state) => (product) => state.items.find(p => p.sku === product.sku), - isCompareLoaded: state => state.loaded + isCompareLoaded: state => state.loaded, + totalProducts: (state) => state.items.length } export default getters diff --git a/core/modules/wishlist/components/WishlistButton.ts b/core/modules/wishlist/components/WishlistButton.ts index d3555c3aa..f50db465c 100644 --- a/core/modules/wishlist/components/WishlistButton.ts +++ b/core/modules/wishlist/components/WishlistButton.ts @@ -3,5 +3,10 @@ export const WishlistButton = { toggleWishlist () { this.$store.dispatch('ui/toggleWishlist') } + }, + computed: { + wishlistItemsCount () { + return this.$store.getters['wishlist/wishlistItemCount'] + } } } \ No newline at end of file diff --git a/core/modules/wishlist/store/index.ts b/core/modules/wishlist/store/index.ts index c770df0e7..62f9bd6db 100644 --- a/core/modules/wishlist/store/index.ts +++ b/core/modules/wishlist/store/index.ts @@ -13,7 +13,8 @@ export const module:Module = { actions, mutations, getters: { - isWishlistLoaded: state => state.loaded + isWishlistLoaded: state => state.loaded, + wishlistItemCount: (state) => state.items.length } } diff --git a/src/themes/default/components/core/blocks/Header/CompareIcon.vue b/src/themes/default/components/core/blocks/Header/CompareIcon.vue index 067b762e6..21c66db9c 100644 --- a/src/themes/default/components/core/blocks/Header/CompareIcon.vue +++ b/src/themes/default/components/core/blocks/Header/CompareIcon.vue @@ -1,6 +1,13 @@ @@ -11,3 +18,13 @@ export default { mixins: [CompareIcon] } + + diff --git a/src/themes/default/components/core/blocks/Header/WishlistIcon.vue b/src/themes/default/components/core/blocks/Header/WishlistIcon.vue index df5c2bc4c..8d7dd450c 100644 --- a/src/themes/default/components/core/blocks/Header/WishlistIcon.vue +++ b/src/themes/default/components/core/blocks/Header/WishlistIcon.vue @@ -1,11 +1,18 @@ @@ -16,3 +23,13 @@ export default { mixins: [WishlistIcon] } + + From 4ee0279fd5632acfb3488ff377784ad1e2522078 Mon Sep 17 00:00:00 2001 From: patzick Date: Sun, 19 May 2019 21:29:46 +0200 Subject: [PATCH 0031/1227] change router as separate action --- core/modules/catalog-magento/store/category/actions.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 7716c887a..2108ca362 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -64,10 +64,13 @@ const actions: ActionTree = { queryFilter.push(filterVariant.id) } currentQuery[filterVariant.type] = queryFilter - router.push({query: currentQuery}) + await dispatch('changeRouterFilterParameters', currentQuery) }, - async resetFilters() { - router.push({query: {}}) + async resetFilters({dispatch}) { + await dispatch('changeRouterFilterParameters', {}) + }, + async changeRouterFilterParameters(context, query) { + router.push({query}) } } From 97e098195dc3ee83542b927c95b44ea971d72eb1 Mon Sep 17 00:00:00 2001 From: patzick Date: Sun, 19 May 2019 21:31:06 +0200 Subject: [PATCH 0032/1227] add category service --- core/data-resolver/index.ts | 73 +++++++++++++++++++ .../catalog-magento/store/category/actions.ts | 5 +- 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 core/data-resolver/index.ts diff --git a/core/data-resolver/index.ts b/core/data-resolver/index.ts new file mode 100644 index 000000000..0ee1b9156 --- /dev/null +++ b/core/data-resolver/index.ts @@ -0,0 +1,73 @@ +import { SearchRequest } from '@vue-storefront/core/types/search/SearchRequest'; +import { quickSearchByQuery } from '@vue-storefront/core/lib/search'; +import SearchQuery from '@vue-storefront/core/lib/search/searchQuery'; +import config from 'config'; + +export interface Product { + id: number, + name: any +} + +const getProduct = async ():Promise => { + const product:Product = { + id: 1, + name: 'sample' + } + return product +} + +function getProducts(): Product[] { + return [{ + id: 1, + name: 'sample1' + }, { + id: 2, + name: 'sample2' + } + ] +} + +const getCategories = async ({ parent = null, key = null, value = null, level = null, onlyActive = true, onlyNotEmpty = false, size = 4000, start = 0, sort = 'position:asc', includeFields = config.entities.optimize ? config.entities.category.includeFields : null, excludeFields = config.entities.optimize ? config.entities.category.excludeFields : null} = {}) => { + let searchQuery = new SearchQuery() + if (parent) { + searchQuery = searchQuery.applyFilter({key: 'parent_id', value: {'eq': parent.id ? parent.id : parent }}) + } + if (level) { + searchQuery = searchQuery.applyFilter({key: 'level', value: {'eq': level}}) + } + + if (key) { + if (Array.isArray(value)) { + searchQuery = searchQuery.applyFilter({key: key, value: {'in': value}}) + } else { + searchQuery = searchQuery.applyFilter({key: key, value: {'eq': value}}) + } + } + + if (onlyActive === true) { + searchQuery = searchQuery.applyFilter({key: 'is_active', value: {'eq': true}}) + } + + if (onlyNotEmpty === true) { + searchQuery = searchQuery.applyFilter({key: 'product_count', value: {'gt': 0}}) + } + return await quickSearchByQuery({ entityType: 'category', query: searchQuery, sort: sort, size: size, start: start, includeFields: includeFields, excludeFields: excludeFields }) +} + +interface ProductResolver { + getProduct: (searchRequest:SearchRequest) => Promise, + getProducts: () => Product[] +} + +interface CategoryService { + getCategories: (searchRequest?:any) => Promise +} + +export const ProductResolver: ProductResolver = { + getProduct, + getProducts +} + +export const CategoryService: CategoryService = { + getCategories +} diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 2108ca362..d14a48454 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -7,6 +7,7 @@ import { quickSearchByQuery } from '@vue-storefront/core/lib/search' import { buildFilterProductsQuery } from '@vue-storefront/core/helpers' import { router } from '@vue-storefront/core/app' import FilterVariant from '../../types/FilterVariant' +import { CategoryService } from '@vue-storefront/core/data-resolver' const actions: ActionTree = { /** @@ -31,8 +32,8 @@ const actions: ActionTree = { return searchResult.items }, - async findCategories ({ dispatch }) { - const res = await dispatch('category/list', {}, {root: true}) + async findCategories () { + const res = await CategoryService.getCategories() return res.items }, async loadCategories ({ commit, dispatch }) { From adc60add1dd0d94abca641a95998d7ba7d6c6885 Mon Sep 17 00:00:00 2001 From: patzick Date: Sun, 19 May 2019 21:41:59 +0200 Subject: [PATCH 0033/1227] loading categories --- core/data-resolver/index.ts | 3 ++- core/modules/catalog-magento/store/category/actions.ts | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/data-resolver/index.ts b/core/data-resolver/index.ts index 0ee1b9156..f2f2a230b 100644 --- a/core/data-resolver/index.ts +++ b/core/data-resolver/index.ts @@ -51,7 +51,8 @@ const getCategories = async ({ parent = null, key = null, value = null, level = if (onlyNotEmpty === true) { searchQuery = searchQuery.applyFilter({key: 'product_count', value: {'gt': 0}}) } - return await quickSearchByQuery({ entityType: 'category', query: searchQuery, sort: sort, size: size, start: start, includeFields: includeFields, excludeFields: excludeFields }) + const response = await quickSearchByQuery({ entityType: 'category', query: searchQuery, sort: sort, size: size, start: start, includeFields: includeFields, excludeFields: excludeFields }) + return response.items } interface ProductResolver { diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index d14a48454..9698acd8f 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -33,11 +33,10 @@ const actions: ActionTree = { return searchResult.items }, async findCategories () { - const res = await CategoryService.getCategories() - return res.items + return await CategoryService.getCategories() }, - async loadCategories ({ commit, dispatch }) { - const categories = await dispatch('findCategories') + async loadCategories ({ commit }) { + const categories = await CategoryService.getCategories() commit(types.CATEGORY_SET_CATEGORIES, categories) return categories }, From d97b2a11ea6f3cb409124bd3f48a406177e818c5 Mon Sep 17 00:00:00 2001 From: patzick Date: Sun, 19 May 2019 22:40:32 +0200 Subject: [PATCH 0034/1227] change filter method with tests --- .../catalog-magento/store/category/actions.ts | 14 +--- .../store/category/logic/categoryLogic.ts | 25 ++++++ .../test/unit/changeFilterQuery.spec.ts | 77 +++++++++++++++++++ 3 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 core/modules/catalog-magento/test/unit/changeFilterQuery.spec.ts diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 9698acd8f..2bfcda476 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -8,6 +8,7 @@ import { buildFilterProductsQuery } from '@vue-storefront/core/helpers' import { router } from '@vue-storefront/core/app' import FilterVariant from '../../types/FilterVariant' import { CategoryService } from '@vue-storefront/core/data-resolver' +import { changeFilterQuery } from './logic/categoryLogic'; const actions: ActionTree = { /** @@ -54,17 +55,8 @@ const actions: ActionTree = { commit(types.CATEGORY_SET_AVAILABLE_FILTERS, filters) }, async switchSearchFilter({ dispatch }, filterVariant:FilterVariant) { - // TODO: not duplicate system filters like sort - const currentQuery = JSON.parse(JSON.stringify(router.currentRoute.query)) - let queryFilter = currentQuery[filterVariant.type] || [] - if (!Array.isArray(queryFilter)) queryFilter = [queryFilter] - if(queryFilter.includes(filterVariant.id)) { - queryFilter = queryFilter.filter(value => value !== filterVariant.id) - } else { - queryFilter.push(filterVariant.id) - } - currentQuery[filterVariant.type] = queryFilter - await dispatch('changeRouterFilterParameters', currentQuery) + const newQuery = changeFilterQuery({currentQuery: router.currentRoute.query, filterVariant}) + await dispatch('changeRouterFilterParameters', newQuery) }, async resetFilters({dispatch}) { await dispatch('changeRouterFilterParameters', {}) diff --git a/core/modules/catalog-magento/store/category/logic/categoryLogic.ts b/core/modules/catalog-magento/store/category/logic/categoryLogic.ts index d16733393..bf44682ed 100644 --- a/core/modules/catalog-magento/store/category/logic/categoryLogic.ts +++ b/core/modules/catalog-magento/store/category/logic/categoryLogic.ts @@ -1,3 +1,4 @@ +import FilterVariant from 'core/modules/catalog-magento/types/FilterVariant'; export const compareByLabel = ( a, b ) => { if ( a.label < b.label ){ @@ -8,3 +9,27 @@ export const compareByLabel = ( a, b ) => { } return 0 } + +export const getSystemFilterNames:Array = ['sort'] + +export const changeFilterQuery = ({currentQuery = {}, filterVariant}:{currentQuery?:any, filterVariant?:FilterVariant} = {}) => { + const newQuery = JSON.parse(JSON.stringify(currentQuery)) + if (!filterVariant) return newQuery + if (getSystemFilterNames.includes(filterVariant.type)) { + if (newQuery[filterVariant.type] && newQuery[filterVariant.type] === filterVariant.id) { + delete newQuery[filterVariant.type] + } else { + newQuery[filterVariant.type] = filterVariant.id + } + } else { + let queryFilter = newQuery[filterVariant.type] || [] + if (!Array.isArray(queryFilter)) queryFilter = [queryFilter] + if(queryFilter.includes(filterVariant.id)) { + queryFilter = queryFilter.filter(value => value !== filterVariant.id) + } else { + queryFilter.push(filterVariant.id) + } + newQuery[filterVariant.type] = queryFilter + } + return newQuery +} \ No newline at end of file diff --git a/core/modules/catalog-magento/test/unit/changeFilterQuery.spec.ts b/core/modules/catalog-magento/test/unit/changeFilterQuery.spec.ts new file mode 100644 index 000000000..1ec8d55f4 --- /dev/null +++ b/core/modules/catalog-magento/test/unit/changeFilterQuery.spec.ts @@ -0,0 +1,77 @@ +import { changeFilterQuery } from '@vue-storefront/core/modules/catalog-magento/store/category/logic/categoryLogic'; +import FilterVariant from '@vue-storefront/core/modules/catalog-magento/types/FilterVariant'; + +describe('changeFilterQuery method', () => { + it('should not change query when no filter variant provided', () => { + const currentQuery = { + color: 1 + } + const result = changeFilterQuery({currentQuery}) + expect(result).toEqual(currentQuery) + }) + + it('should not return same query object instance', () => { + const currentQuery = { + color: 1 + } + const result = changeFilterQuery({currentQuery}) + expect(result).not.toBe(currentQuery) + }); + + it('should add filter to array', () => { + const currentQuery = {} + const filterVariant:FilterVariant = { + id: '33', + label: 'Red', + type: 'color' + } + const result = changeFilterQuery({currentQuery, filterVariant}) + expect(result).toEqual({color: ['33']}) + }); + + it('should remove filter if exist in query', () => { + const currentQuery = { + color: ['23', '33'] + } + const filterVariant:FilterVariant = { + id: '33', + label: 'Red', + type: 'color' + } + const result = changeFilterQuery({currentQuery, filterVariant}) + expect(result).toEqual({color: ['23']}) + }); + + it('should add sort filter', () => { + const currentQuery = {} + const filterVariant:FilterVariant = { + id: 'final_price', + label: 'Price: Low to high', + type: 'sort' + } + const result = changeFilterQuery({currentQuery, filterVariant}) + expect(result).toEqual({sort: 'final_price'}) + }); + + it('should remove sort filter', () => { + const currentQuery = {sort: 'final_price'} + const filterVariant:FilterVariant = { + id: 'final_price', + label: 'Price: Low to high', + type: 'sort' + } + const result = changeFilterQuery({currentQuery, filterVariant}) + expect(result).toEqual({}) + }); + + it('should change sort filter', () => { + const currentQuery = {sort: 'final_price'} + const filterVariant:FilterVariant = { + id: 'updated_at', + label: 'Latest', + type: 'sort' + } + const result = changeFilterQuery({currentQuery, filterVariant}) + expect(result).toEqual({sort: 'updated_at'}) + }); +}) From eab22437aea55f398a969caaa59b001cf2914e5a Mon Sep 17 00:00:00 2001 From: patzick Date: Sun, 19 May 2019 23:19:22 +0200 Subject: [PATCH 0035/1227] extract getFiltersFromQuery with tests --- .../catalog-magento/store/category/getters.ts | 24 +-- .../store/category/logic/categoryLogic.ts | 26 +++ .../test/unit/getFiltersFromQuery.spec.ts | 152 ++++++++++++++++++ 3 files changed, 180 insertions(+), 22 deletions(-) create mode 100644 core/modules/catalog-magento/test/unit/getFiltersFromQuery.spec.ts diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index 9c34e6947..b58a02ed6 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -7,7 +7,7 @@ import FilterVariant from '../../types/FilterVariant' import { optionLabel } from '../../helpers/optionLabel' import trim from 'lodash-es/trim' import toString from 'lodash-es/toString' -import { compareByLabel } from './logic/categoryLogic' +import { compareByLabel, getFiltersFromQuery } from './logic/categoryLogic' const getters: GetterTree = { getCategories: (state) => state.categories || [], @@ -82,27 +82,7 @@ const getters: GetterTree = { getAvailableFilters: state => state.availableFilters, getCurrentFiltersFrom: (state, getters, rootState) => (filters) => { const currentQuery = filters ? filters : rootState.route.query - const searchQuery = { - filters: {} - } - Object.keys(currentQuery).forEach(filterKey => { - const filter = getters.getAvailableFilters[filterKey] - const queryValue = currentQuery[filterKey] - if (!filter) return - if (getters.getSystemFilterNames.includes(filterKey)) { - searchQuery[filterKey] = queryValue - } else if (Array.isArray(queryValue)) { - queryValue.map(singleValue => { - const variant = filter.find(filterVariant => filterVariant.id === singleValue) - if (!searchQuery.filters[filterKey] || !Array.isArray(searchQuery.filters[filterKey])) searchQuery.filters[filterKey] = [] - searchQuery.filters[filterKey].push({...variant, attribute_code: filterKey}) - }) - } else { - const variant = filter.find(filterVariant => filterVariant.id === queryValue) - searchQuery.filters[filterKey] = {...variant, attribute_code: filterKey} - } - }) - return searchQuery + return getFiltersFromQuery({availableFilters: getters.getAvailableFilters, filtersQuery: currentQuery}) }, getCurrentFilters: (state, getters, rootState) => getters.getCurrentFiltersFrom(rootState.route.query).filters, hasActiveFilters: (state, getters) => !!Object.keys(getters.getCurrentFilters).length, diff --git a/core/modules/catalog-magento/store/category/logic/categoryLogic.ts b/core/modules/catalog-magento/store/category/logic/categoryLogic.ts index bf44682ed..fd37f50d2 100644 --- a/core/modules/catalog-magento/store/category/logic/categoryLogic.ts +++ b/core/modules/catalog-magento/store/category/logic/categoryLogic.ts @@ -32,4 +32,30 @@ export const changeFilterQuery = ({currentQuery = {}, filterVariant}:{currentQue newQuery[filterVariant.type] = queryFilter } return newQuery +} + +export const getFiltersFromQuery = ({filtersQuery = {}, availableFilters = {}} = {}) => { + const searchQuery = { + filters: {} + } + Object.keys(filtersQuery).forEach(filterKey => { + const filter = availableFilters[filterKey] + const queryValue = filtersQuery[filterKey] + if (!filter) return + if (getSystemFilterNames.includes(filterKey)) { + searchQuery[filterKey] = queryValue + } else if (Array.isArray(queryValue)) { + queryValue.map(singleValue => { + const variant = filter.find(filterVariant => filterVariant.id === singleValue) + if (!variant) return + if (!searchQuery.filters[filterKey] || !Array.isArray(searchQuery.filters[filterKey])) searchQuery.filters[filterKey] = [] + searchQuery.filters[filterKey].push({...variant, attribute_code: filterKey}) + }) + } else { + const variant = filter.find(filterVariant => filterVariant.id === queryValue) + if (!variant) return + searchQuery.filters[filterKey] = {...variant, attribute_code: filterKey} + } + }) + return searchQuery } \ No newline at end of file diff --git a/core/modules/catalog-magento/test/unit/getFiltersFromQuery.spec.ts b/core/modules/catalog-magento/test/unit/getFiltersFromQuery.spec.ts new file mode 100644 index 000000000..f5b4af67f --- /dev/null +++ b/core/modules/catalog-magento/test/unit/getFiltersFromQuery.spec.ts @@ -0,0 +1,152 @@ +import { getFiltersFromQuery } from "@vue-storefront/core/modules/catalog-magento/store/category/logic/categoryLogic"; + +describe('getFiltersFromQuery method', () => { + let availableFilters + beforeEach(() => { + availableFilters = { + "color":[ + { + "id":"49", + "label":"Black", + "type":"color" + }, + { + "id":"50", + "label":"Blue", + "type":"color" + } + ], + "size":[ + { + "id":"172", + "label":"28", + "type":"size" + }, + { + "id":"170", + "label":"L", + "type":"size" + }, + { + "id":"169", + "label":"M", + "type":"size" + } + ], + "price":[ + { + "id":"0.0-50.0", + "type":"price", + "from":0, + "to":50, + "label":"< $50" + }, + { + "id":"50.0-100.0", + "type":"price", + "from":50, + "to":100, + "label":"$50 - 100" + }, + { + "id":"150.0-*", + "type":"price", + "from":150, + "label":"> $150" + } + ], + "erin_recommends":[ + { + "id":"0", + "label":"No", + "type":"erin_recommends" + }, + { + "id":"1", + "label":"Yes", + "type":"erin_recommends" + } + ], + "sort":[ + { + "label":"Latest", + "id":"updated_at", + "type":"sort" + }, + { + "label":"Price: Low to high", + "id":"final_price", + "type":"sort" + }, + { + "label":"Price: High to low", + "id":"final_price:desc", + "type":"sort" + } + ] + } + }); + + it('should return color filter', () => { + const filtersQuery = { + color: '49' + } + const result = getFiltersFromQuery({availableFilters, filtersQuery}) + expect(result).toEqual({ + filters: { + color: { + "id":"49", + "label":"Black", + "type":"color", + "attribute_code":"color" + } + } + }) + }); + + it('should return color filters', () => { + const filtersQuery = { + color: ['49', '50'] + } + const result = getFiltersFromQuery({availableFilters, filtersQuery}) + expect(result).toEqual({ + filters: { + color: [ + { + "id":"49", + "label":"Black", + "type":"color", + "attribute_code":"color" + }, + { + "id":"50", + "label":"Blue", + "type":"color", + "attribute_code":"color" + } + ] + } + }) + }); + + it('should not return not existing filter', () => { + const filtersQuery = { + color: '111' + } + const result = getFiltersFromQuery({availableFilters, filtersQuery}) + expect(result).toEqual({ + filters: {} + }) + }); + + it('should return size filter', () => { + const filtersQuery = { + sort: 'updated_at' + } + const result = getFiltersFromQuery({availableFilters, filtersQuery}) + expect(result).toEqual({ + filters: {}, + sort: 'updated_at' + }) + }); +}); \ No newline at end of file From 8fd4f422363fe293ce097899b550982409edcab4 Mon Sep 17 00:00:00 2001 From: patzick Date: Mon, 20 May 2019 10:20:40 +0200 Subject: [PATCH 0036/1227] add support for multiple prices with tests --- core/helpers/index.ts | 24 ++- .../helpers/buildFilterProductsQuery.spec.ts | 142 ++++++++++++++++++ 2 files changed, 153 insertions(+), 13 deletions(-) create mode 100644 core/test/unit/helpers/buildFilterProductsQuery.spec.ts diff --git a/core/helpers/index.ts b/core/helpers/index.ts index 2053823ce..aadb7cca0 100644 --- a/core/helpers/index.ts +++ b/core/helpers/index.ts @@ -91,23 +91,21 @@ export function buildFilterProductsQuery (currentCategory, chosenFilters = {}, d // add choosedn filters for (let code of Object.keys(chosenFilters)) { const filter = chosenFilters[code] + const attributeCode = Array.isArray(filter) ? filter[0].attribute_code : filter.attribute_code - if (Array.isArray(filter)) { - const type = filter[0].attribute_code + if (Array.isArray(filter) && attributeCode !== 'price') { const values = filter.map(filter => filter.id) - filterQr = filterQr.applyFilter({key: type, value: {'in': values}, scope: 'catalog'}) - // TODO add support for multiple prices - } else if (filter.attribute_code !== 'price') { - filterQr = filterQr.applyFilter({key: filter.attribute_code, value: {'eq': filter.id}, scope: 'catalog'}) + filterQr = filterQr.applyFilter({key: attributeCode, value: {'in': values}, scope: 'catalog'}) + } else if (attributeCode !== 'price') { + filterQr = filterQr.applyFilter({key: attributeCode, value: {'eq': filter.id}, scope: 'catalog'}) } else { // multi should be possible filter here? const rangeqr = {} - if (filter.from) { - rangeqr['gte'] = filter.from - } - if (filter.to) { - rangeqr['lte'] = filter.to - } - filterQr = filterQr.applyFilter({key: filter.attribute_code, value: rangeqr, scope: 'catalog'}) + const filterValues = Array.isArray(filter) ? filter : [filter] + filterValues.forEach(singleFilter => { + if (singleFilter.from) rangeqr['gte'] = singleFilter.from + if (singleFilter.to) rangeqr['lte'] = singleFilter.to + }) + filterQr = filterQr.applyFilter({key: attributeCode, value: rangeqr, scope: 'catalog'}) } } diff --git a/core/test/unit/helpers/buildFilterProductsQuery.spec.ts b/core/test/unit/helpers/buildFilterProductsQuery.spec.ts new file mode 100644 index 000000000..c0941078a --- /dev/null +++ b/core/test/unit/helpers/buildFilterProductsQuery.spec.ts @@ -0,0 +1,142 @@ +import { buildFilterProductsQuery } from '@vue-storefront/core/helpers' + +jest.mock('remove-accents', () => jest.fn()); +jest.mock('@vue-storefront/core/modules/url/helpers', () => jest.fn()); +jest.mock('config', () => ({ + products: { + "defaultFilters": ["color", "size", "price", "erin_recommends"] + } +})); + +describe('buildFilterProductsQuery method', () => { + let currentCategory + + beforeEach(() => { + currentCategory = { + "path":"1/2/20", + "is_active":true, + "level":2, + "product_count":0, + "children_count":"8", + "parent_id":2, + "name":"Women", + "id":20, + "url_path":"women/women-20", + "url_key":"women-20", + "children_data":[ + { + "id":21, + "children_data":[ + { + "id":23 + }, + { + "id":24 + }, + { + "id":25 + }, + { + "id":26 + } + ] + }, + { + "id":22, + "children_data":[ + { + "id":27 + }, + { + "id":28 + } + ] + } + ], + "_score":null, + "slug":"women-20" + } + }); + + it('should build default query', () => { + const result = buildFilterProductsQuery(currentCategory) + const categoryFilter = result._appliedFilters.find(filter => filter.attribute === 'category_ids') + expect(categoryFilter).toBeDefined() + expect(categoryFilter.value.in).toEqual([20, 21, 23, 24, 25, 26, 22, 27, 28]) + }); + + it('should build query with color filters', () => { + const filters = { + color: [ + { + "id":"49", + "label":"Black", + "type":"color", + "attribute_code":"color" + }, + { + "id":"50", + "label":"Blue", + "type":"color", + "attribute_code":"color" + } + ] + } + const result = buildFilterProductsQuery(currentCategory, filters) + const categoryFilter = result._appliedFilters.find(filter => filter.attribute === 'color') + expect(categoryFilter).toBeDefined() + expect(categoryFilter.value.in).toEqual(['49', '50']) + }); + + it('should build query with single price from 0 filter', () => { + const filters = { + price: { + "id": "0.0-50.0", + "type":"price", + "from":0, + "to":50, + "label":"< $50", + "attribute_code":"price" + } + } + const result = buildFilterProductsQuery(currentCategory, filters) + const categoryFilter = result._appliedFilters.find(filter => filter.attribute === 'price') + expect(categoryFilter).toBeDefined() + expect(categoryFilter.value.lte).toEqual(50) + }); + + it('should build query with single price between 50-100 filter', () => { + const filters = { + price: { + "id": "50.0-100.0", + "type":"price", + "from":50, + "to":100, + "label":"$50 - 100", + "attribute_code":"price" + } + } + const result = buildFilterProductsQuery(currentCategory, filters) + const categoryFilter = result._appliedFilters.find(filter => filter.attribute === 'price') + expect(categoryFilter).toBeDefined() + expect(categoryFilter.value.gte).toEqual(50) + expect(categoryFilter.value.lte).toEqual(100) + }); + + it('should build query with price filters', () => { + const filters = { + price: [{ + "id": "0.0-50.0", + "type":"price", + "from":0, + "to":50, + "label":"< $50", + "attribute_code":"price" + }] + } + const result = buildFilterProductsQuery(currentCategory, filters) + const categoryFilter = result._appliedFilters.find(filter => filter.attribute === 'price') + expect(categoryFilter).toBeDefined() + expect(categoryFilter.value.lte).toEqual(50) + }); +}); From 35293e3d6f9cf7ef6c8a8c781b1e418ab95f4b24 Mon Sep 17 00:00:00 2001 From: patzick Date: Mon, 20 May 2019 10:48:23 +0200 Subject: [PATCH 0037/1227] add support for filters as query and path params --- config/default.json | 1 + core/modules/catalog-magento/store/category/actions.ts | 7 ++++--- core/modules/catalog-magento/store/category/getters.ts | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/config/default.json b/config/default.json index 31745ae90..e82f0dc5a 100644 --- a/config/default.json +++ b/config/default.json @@ -268,6 +268,7 @@ "setupVariantByAttributeCode": true, "endpoint": "http://localhost:8080/api/product", "defaultFilters": ["color", "size", "price", "erin_recommends"], + "routerFiltersSource": "query", "filterFieldMapping": { "category.name": "category.name.keyword" }, diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 2bfcda476..08f5921fa 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -9,6 +9,7 @@ import { router } from '@vue-storefront/core/app' import FilterVariant from '../../types/FilterVariant' import { CategoryService } from '@vue-storefront/core/data-resolver' import { changeFilterQuery } from './logic/categoryLogic'; +import { products } from 'config' const actions: ActionTree = { /** @@ -24,7 +25,7 @@ const actions: ActionTree = { }, async loadCategoryProducts ({ commit, getters, dispatch }, { route } = {}) { await dispatch('initCategoryModule') - const searchQuery = getters.getCurrentFiltersFrom(route.query) + const searchQuery = getters.getCurrentFiltersFrom(route[products.routerFiltersSource]) const searchCategory = getters.getCategoryFrom(route.path) let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters) const searchResult = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort }) @@ -55,14 +56,14 @@ const actions: ActionTree = { commit(types.CATEGORY_SET_AVAILABLE_FILTERS, filters) }, async switchSearchFilter({ dispatch }, filterVariant:FilterVariant) { - const newQuery = changeFilterQuery({currentQuery: router.currentRoute.query, filterVariant}) + const newQuery = changeFilterQuery({currentQuery: router.currentRoute[products.routerFiltersSource], filterVariant}) await dispatch('changeRouterFilterParameters', newQuery) }, async resetFilters({dispatch}) { await dispatch('changeRouterFilterParameters', {}) }, async changeRouterFilterParameters(context, query) { - router.push({query}) + router.push({[products.routerFiltersSource]: query}) } } diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-magento/store/category/getters.ts index b58a02ed6..00ea6558b 100644 --- a/core/modules/catalog-magento/store/category/getters.ts +++ b/core/modules/catalog-magento/store/category/getters.ts @@ -81,10 +81,10 @@ const getters: GetterTree = { }, getAvailableFilters: state => state.availableFilters, getCurrentFiltersFrom: (state, getters, rootState) => (filters) => { - const currentQuery = filters ? filters : rootState.route.query + const currentQuery = filters ? filters : rootState.route[products.routerFiltersSource] return getFiltersFromQuery({availableFilters: getters.getAvailableFilters, filtersQuery: currentQuery}) }, - getCurrentFilters: (state, getters, rootState) => getters.getCurrentFiltersFrom(rootState.route.query).filters, + getCurrentFilters: (state, getters, rootState) => getters.getCurrentFiltersFrom(rootState.route[products.routerFiltersSource]).filters, hasActiveFilters: (state, getters) => !!Object.keys(getters.getCurrentFilters).length, getSystemFilterNames: () => ['sort'], getBreadcrumbs: (state, getters) => { From b47b34b03ee7f0d61537a2e40083b227b459e44a Mon Sep 17 00:00:00 2001 From: patzick Date: Mon, 20 May 2019 11:34:00 +0200 Subject: [PATCH 0038/1227] filters per category --- core/modules/catalog-magento/store/category/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-magento/store/category/actions.ts index 08f5921fa..a0f6db8f2 100644 --- a/core/modules/catalog-magento/store/category/actions.ts +++ b/core/modules/catalog-magento/store/category/actions.ts @@ -20,13 +20,13 @@ const actions: ActionTree = { async initCategoryModule ({ getters, dispatch }) { if (!getters.getCategories.length) { await dispatch('loadCategories') - await dispatch('loadCategoryFilters') } }, async loadCategoryProducts ({ commit, getters, dispatch }, { route } = {}) { await dispatch('initCategoryModule') const searchQuery = getters.getCurrentFiltersFrom(route[products.routerFiltersSource]) const searchCategory = getters.getCategoryFrom(route.path) + await dispatch('loadCategoryFilters', searchCategory) let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters) const searchResult = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort }) commit(types.CATEGORY_SET_PRODUCTS, searchResult.items) From 7d4633b74b23f71ee180623d17248f730c7a3d8a Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Wed, 22 May 2019 14:39:16 +0200 Subject: [PATCH 0039/1227] refactor -magento to -next --- .../components/blocks/Category/Sidebar.js | 2 +- .../helpers/categoryHelpers.ts | 0 .../helpers/optionLabel.ts | 0 .../{catalog-magento => catalog-next}/index.ts | 4 ++-- .../store/category/CategoryState.ts | 0 .../store/category/actions.ts | 0 .../store/category/getters.ts | 0 .../store/category/index.ts | 0 .../store/category/logic/categoryLogic.ts | 2 +- .../store/category/mutation-types.ts | 0 .../store/category/mutations.ts | 0 .../test/unit/changeFilterQuery.spec.ts | 4 ++-- .../test/unit/getFiltersFromQuery.spec.ts | 2 +- .../types/FilterVariant.ts | 0 src/modules/index.ts | 4 ++-- .../components/core/blocks/Category/Sidebar.vue | 8 ++++---- src/themes/default/pages/Category.vue | 12 ++++++------ 17 files changed, 19 insertions(+), 19 deletions(-) rename core/modules/{catalog-magento => catalog-next}/helpers/categoryHelpers.ts (100%) rename core/modules/{catalog-magento => catalog-next}/helpers/optionLabel.ts (100%) rename core/modules/{catalog-magento => catalog-next}/index.ts (82%) rename core/modules/{catalog-magento => catalog-next}/store/category/CategoryState.ts (100%) rename core/modules/{catalog-magento => catalog-next}/store/category/actions.ts (100%) rename core/modules/{catalog-magento => catalog-next}/store/category/getters.ts (100%) rename core/modules/{catalog-magento => catalog-next}/store/category/index.ts (100%) rename core/modules/{catalog-magento => catalog-next}/store/category/logic/categoryLogic.ts (96%) rename core/modules/{catalog-magento => catalog-next}/store/category/mutation-types.ts (100%) rename core/modules/{catalog-magento => catalog-next}/store/category/mutations.ts (100%) rename core/modules/{catalog-magento => catalog-next}/test/unit/changeFilterQuery.spec.ts (96%) rename core/modules/{catalog-magento => catalog-next}/test/unit/getFiltersFromQuery.spec.ts (98%) rename core/modules/{catalog-magento => catalog-next}/types/FilterVariant.ts (100%) diff --git a/core/compatibility/components/blocks/Category/Sidebar.js b/core/compatibility/components/blocks/Category/Sidebar.js index 02dffaa6d..c422975fa 100644 --- a/core/compatibility/components/blocks/Category/Sidebar.js +++ b/core/compatibility/components/blocks/Category/Sidebar.js @@ -19,7 +19,7 @@ export default { return this.getActiveCategoryFilters }, availableFilters () { - return pickBy(this.filters, (filter, filterType) => { return (filter.length && !this.$store.getters['category-magento/getSystemFilterNames'].includes(filterType)) }) + return pickBy(this.filters, (filter, filterType) => { return (filter.length && !this.$store.getters['category-next/getSystemFilterNames'].includes(filterType)) }) }, hasActiveFilters () { return Object.keys(this.activeFilters).length !== 0 diff --git a/core/modules/catalog-magento/helpers/categoryHelpers.ts b/core/modules/catalog-next/helpers/categoryHelpers.ts similarity index 100% rename from core/modules/catalog-magento/helpers/categoryHelpers.ts rename to core/modules/catalog-next/helpers/categoryHelpers.ts diff --git a/core/modules/catalog-magento/helpers/optionLabel.ts b/core/modules/catalog-next/helpers/optionLabel.ts similarity index 100% rename from core/modules/catalog-magento/helpers/optionLabel.ts rename to core/modules/catalog-next/helpers/optionLabel.ts diff --git a/core/modules/catalog-magento/index.ts b/core/modules/catalog-next/index.ts similarity index 82% rename from core/modules/catalog-magento/index.ts rename to core/modules/catalog-next/index.ts index 627417329..7a373a700 100644 --- a/core/modules/catalog-magento/index.ts +++ b/core/modules/catalog-next/index.ts @@ -6,10 +6,10 @@ import { categoryModule } from './store/category' import { createModule } from '@vue-storefront/core/lib/module' // import { beforeRegistration } from './hooks/beforeRegistration' -export const KEY = 'catalog-magento' +export const KEY = 'catalog-next' export default createModule({ key: KEY, store: { modules: [ - { key: 'category-magento', module: categoryModule } + { key: 'category-next', module: categoryModule } ] } }) diff --git a/core/modules/catalog-magento/store/category/CategoryState.ts b/core/modules/catalog-next/store/category/CategoryState.ts similarity index 100% rename from core/modules/catalog-magento/store/category/CategoryState.ts rename to core/modules/catalog-next/store/category/CategoryState.ts diff --git a/core/modules/catalog-magento/store/category/actions.ts b/core/modules/catalog-next/store/category/actions.ts similarity index 100% rename from core/modules/catalog-magento/store/category/actions.ts rename to core/modules/catalog-next/store/category/actions.ts diff --git a/core/modules/catalog-magento/store/category/getters.ts b/core/modules/catalog-next/store/category/getters.ts similarity index 100% rename from core/modules/catalog-magento/store/category/getters.ts rename to core/modules/catalog-next/store/category/getters.ts diff --git a/core/modules/catalog-magento/store/category/index.ts b/core/modules/catalog-next/store/category/index.ts similarity index 100% rename from core/modules/catalog-magento/store/category/index.ts rename to core/modules/catalog-next/store/category/index.ts diff --git a/core/modules/catalog-magento/store/category/logic/categoryLogic.ts b/core/modules/catalog-next/store/category/logic/categoryLogic.ts similarity index 96% rename from core/modules/catalog-magento/store/category/logic/categoryLogic.ts rename to core/modules/catalog-next/store/category/logic/categoryLogic.ts index fd37f50d2..3c72c5e01 100644 --- a/core/modules/catalog-magento/store/category/logic/categoryLogic.ts +++ b/core/modules/catalog-next/store/category/logic/categoryLogic.ts @@ -1,4 +1,4 @@ -import FilterVariant from 'core/modules/catalog-magento/types/FilterVariant'; +import FilterVariant from 'core/modules/catalog-next/types/FilterVariant'; export const compareByLabel = ( a, b ) => { if ( a.label < b.label ){ diff --git a/core/modules/catalog-magento/store/category/mutation-types.ts b/core/modules/catalog-next/store/category/mutation-types.ts similarity index 100% rename from core/modules/catalog-magento/store/category/mutation-types.ts rename to core/modules/catalog-next/store/category/mutation-types.ts diff --git a/core/modules/catalog-magento/store/category/mutations.ts b/core/modules/catalog-next/store/category/mutations.ts similarity index 100% rename from core/modules/catalog-magento/store/category/mutations.ts rename to core/modules/catalog-next/store/category/mutations.ts diff --git a/core/modules/catalog-magento/test/unit/changeFilterQuery.spec.ts b/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts similarity index 96% rename from core/modules/catalog-magento/test/unit/changeFilterQuery.spec.ts rename to core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts index 1ec8d55f4..2612ef643 100644 --- a/core/modules/catalog-magento/test/unit/changeFilterQuery.spec.ts +++ b/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts @@ -1,5 +1,5 @@ -import { changeFilterQuery } from '@vue-storefront/core/modules/catalog-magento/store/category/logic/categoryLogic'; -import FilterVariant from '@vue-storefront/core/modules/catalog-magento/types/FilterVariant'; +import { changeFilterQuery } from '@vue-storefront/core/modules/catalog-next/store/category/logic/categoryLogic'; +import FilterVariant from '@vue-storefront/core/modules/catalog-next/types/FilterVariant'; describe('changeFilterQuery method', () => { it('should not change query when no filter variant provided', () => { diff --git a/core/modules/catalog-magento/test/unit/getFiltersFromQuery.spec.ts b/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts similarity index 98% rename from core/modules/catalog-magento/test/unit/getFiltersFromQuery.spec.ts rename to core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts index f5b4af67f..73f4b4654 100644 --- a/core/modules/catalog-magento/test/unit/getFiltersFromQuery.spec.ts +++ b/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts @@ -1,4 +1,4 @@ -import { getFiltersFromQuery } from "@vue-storefront/core/modules/catalog-magento/store/category/logic/categoryLogic"; +import { getFiltersFromQuery } from "@vue-storefront/core/modules/catalog-next/store/category/logic/categoryLogic"; describe('getFiltersFromQuery method', () => { let availableFilters diff --git a/core/modules/catalog-magento/types/FilterVariant.ts b/core/modules/catalog-next/types/FilterVariant.ts similarity index 100% rename from core/modules/catalog-magento/types/FilterVariant.ts rename to core/modules/catalog-next/types/FilterVariant.ts diff --git a/src/modules/index.ts b/src/modules/index.ts index baa823400..01dcb5442 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -1,7 +1,7 @@ // import { extendModule } from '@vue-storefront/core/lib/module' import { VueStorefrontModule } from '@vue-storefront/core/lib/module' import { Catalog } from "@vue-storefront/core/modules/catalog" -import CatalogMagento from "@vue-storefront/core/modules/catalog-magento" +import CatalogNext from "@vue-storefront/core/modules/catalog-next" import { Cart } from '@vue-storefront/core/modules/cart' import { Checkout } from '@vue-storefront/core/modules/checkout' import { Compare } from '@vue-storefront/core/modules/compare' @@ -78,6 +78,6 @@ export const registerModules: VueStorefrontModule[] = [ AmpRenderer, InstantCheckout, Url, - CatalogMagento + CatalogNext // Example ] diff --git a/src/themes/default/components/core/blocks/Category/Sidebar.vue b/src/themes/default/components/core/blocks/Category/Sidebar.vue index 7cd4edb9a..76e28dd8e 100644 --- a/src/themes/default/components/core/blocks/Category/Sidebar.vue +++ b/src/themes/default/components/core/blocks/Category/Sidebar.vue @@ -109,18 +109,18 @@ export default { }, computed: { hasActiveFilters () { - return this.$store.getters['category-magento/hasActiveFilters'] + return this.$store.getters['category-next/hasActiveFilters'] }, getCurrentFilters () { - return this.$store.getters['category-magento/getCurrentFilters'] + return this.$store.getters['category-next/getCurrentFilters'] }, availableFilters () { - return pickBy(this.filters, (filter, filterType) => { return (filter.length && !this.$store.getters['category-magento/getSystemFilterNames'].includes(filterType)) }) + return pickBy(this.filters, (filter, filterType) => { return (filter.length && !this.$store.getters['category-next/getSystemFilterNames'].includes(filterType)) }) } }, methods: { resetAllFilters () { - this.$store.dispatch('category-magento/resetFilters') + this.$store.dispatch('category-next/resetFilters') }, sortById (filters) { return [...filters].sort((a, b) => { return a.id - b.id }) diff --git a/src/themes/default/pages/Category.vue b/src/themes/default/pages/Category.vue index 7951fda34..934f328cb 100644 --- a/src/themes/default/pages/Category.vue +++ b/src/themes/default/pages/Category.vue @@ -69,10 +69,10 @@ export default { }, computed: { products () { - return this.$store.getters['category-magento/getCategoryProducts'] + return this.$store.getters['category-next/getCategoryProducts'] }, category () { - return this.$store.getters['category-magento/getCurrentCategory'] + return this.$store.getters['category-next/getCurrentCategory'] }, productsTotal () { return this.products.length @@ -81,10 +81,10 @@ export default { return this.productsTotal === 0 }, getBreadcrumbs () { - return this.$store.getters['category-magento/getBreadcrumbs'].filter(breadcrumb => breadcrumb.name !== this.category.name) + return this.$store.getters['category-next/getBreadcrumbs'].filter(breadcrumb => breadcrumb.name !== this.category.name) }, getAvailableFilters () { - return this.$store.getters['category-magento/getAvailableFilters'] + return this.$store.getters['category-next/getAvailableFilters'] } }, async asyncData ({ store, route }) { // this is for SSR purposes to prefetch data - and it's always executed before parent component methods @@ -95,7 +95,7 @@ export default { includeFields: config.entities.optimize && isServer ? config.entities.attribute.includeFields : null }) // // const category = await store.dispatch('category/single', { key: store.state.config.products.useMagentoUrlKeys ? 'url_key' : 'slug', value: route.params.slug }) - await store.dispatch('category-magento/loadCategoryProducts', {route}) + await store.dispatch('category-next/loadCategoryProducts', {route}) } catch (e) { console.error('Problem with Category asyncData', e) } @@ -115,7 +115,7 @@ export default { }) }, async changeFilter (filterVariant) { - this.$store.dispatch('category-magento/switchSearchFilter', filterVariant) + this.$store.dispatch('category-next/switchSearchFilter', filterVariant) } } } From 93d2588df8c575528cc875a967e2ada2c378045e Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Thu, 30 May 2019 12:01:41 +0200 Subject: [PATCH 0040/1227] support finding configurable child with multiple filters --- core/modules/catalog/helpers/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/modules/catalog/helpers/index.ts b/core/modules/catalog/helpers/index.ts index eca3f5cd0..6174b1cca 100644 --- a/core/modules/catalog/helpers/index.ts +++ b/core/modules/catalog/helpers/index.ts @@ -435,8 +435,11 @@ export function findConfigurableChildAsync ({ product, configuration = null, sel return configurableChild.sku === configuration.sku // by sku or first one } else { return Object.keys(omit(configuration, ['price'])).every((configProperty) => { - if (!configuration[configProperty] || typeof configuration[configProperty].id === 'undefined') return true // skip empty - return toString(configurableChild[configProperty]) === toString(configuration[configProperty].id) + let configurationPropertyFilters = configuration[configProperty] || [] + if (!Array.isArray(configurationPropertyFilters)) configurationPropertyFilters = [configurationPropertyFilters] + const configurationIds = configurationPropertyFilters.map(filter => filter.id).filter(filterId => !!filterId) + if (!configurationIds.length) return true // skip empty + return configurationIds.includes(configurableChild[configProperty]) }) } }) From 771d7343316d85d6c8322ae82cddc524342dc950 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Thu, 30 May 2019 12:12:24 +0200 Subject: [PATCH 0041/1227] configure fetched products --- core/modules/catalog-next/store/category/actions.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/modules/catalog-next/store/category/actions.ts b/core/modules/catalog-next/store/category/actions.ts index a0f6db8f2..744828bc5 100644 --- a/core/modules/catalog-next/store/category/actions.ts +++ b/core/modules/catalog-next/store/category/actions.ts @@ -8,8 +8,9 @@ import { buildFilterProductsQuery } from '@vue-storefront/core/helpers' import { router } from '@vue-storefront/core/app' import FilterVariant from '../../types/FilterVariant' import { CategoryService } from '@vue-storefront/core/data-resolver' -import { changeFilterQuery } from './logic/categoryLogic'; +import { changeFilterQuery } from './logic/categoryLogic' import { products } from 'config' +import { configureProductAsync } from '@vue-storefront/core/modules/catalog/helpers' const actions: ActionTree = { /** @@ -29,7 +30,11 @@ const actions: ActionTree = { await dispatch('loadCategoryFilters', searchCategory) let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters) const searchResult = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort }) - commit(types.CATEGORY_SET_PRODUCTS, searchResult.items) + let configuredProducts = searchResult.items.map(product => { + const configuredProductVariant = configureProductAsync({}, {product, configuration: searchQuery.filters, selectDefaultVariant: false, fallbackToDefaultWhenNoAvailable: true, setProductErorrs: false}) + return Object.assign(product, configuredProductVariant) + }) + commit(types.CATEGORY_SET_PRODUCTS, configuredProducts) // await dispatch('loadAvailableFiltersFrom', searchResult) return searchResult.items From fa52a842737ec03c1f34d3b3d43e0500c7f732aa Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Thu, 30 May 2019 12:22:01 +0200 Subject: [PATCH 0042/1227] load category filters before picking filters --- core/modules/catalog-next/store/category/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modules/catalog-next/store/category/actions.ts b/core/modules/catalog-next/store/category/actions.ts index 744828bc5..b28494e56 100644 --- a/core/modules/catalog-next/store/category/actions.ts +++ b/core/modules/catalog-next/store/category/actions.ts @@ -25,9 +25,9 @@ const actions: ActionTree = { }, async loadCategoryProducts ({ commit, getters, dispatch }, { route } = {}) { await dispatch('initCategoryModule') - const searchQuery = getters.getCurrentFiltersFrom(route[products.routerFiltersSource]) const searchCategory = getters.getCategoryFrom(route.path) await dispatch('loadCategoryFilters', searchCategory) + const searchQuery = getters.getCurrentFiltersFrom(route[products.routerFiltersSource]) let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters) const searchResult = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort }) let configuredProducts = searchResult.items.map(product => { From 738ddcef5d30da11201a3bc961c23c1e798a9ac8 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Mon, 3 Jun 2019 09:15:52 +0200 Subject: [PATCH 0043/1227] test caching on server --- .../catalog-next/store/category/actions.ts | 15 +++++++++++++++ src/themes/default/pages/Category.vue | 3 +++ 2 files changed, 18 insertions(+) diff --git a/core/modules/catalog-next/store/category/actions.ts b/core/modules/catalog-next/store/category/actions.ts index b28494e56..7f16c30ba 100644 --- a/core/modules/catalog-next/store/category/actions.ts +++ b/core/modules/catalog-next/store/category/actions.ts @@ -39,6 +39,21 @@ const actions: ActionTree = { return searchResult.items }, + async cacheProducts ({ commit, getters, dispatch }, { route } = {}) { + const searchCategory = getters.getCategoryFrom(route.path) + const searchQuery = getters.getCurrentFiltersFrom(route[products.routerFiltersSource]) + let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters) + + console.error('CACHE 2 step...') + const xx = await dispatch('product/list', { + query: filterQr, + sort: searchQuery.sort, + updateState: false // not update the product listing - this request is only for caching + }, { root: true }) + console.error('RETURNED PRODUCTS', xx) + + // return searchResult.items + }, async findCategories () { return await CategoryService.getCategories() }, diff --git a/src/themes/default/pages/Category.vue b/src/themes/default/pages/Category.vue index e030ae646..ac0b163b4 100644 --- a/src/themes/default/pages/Category.vue +++ b/src/themes/default/pages/Category.vue @@ -111,6 +111,9 @@ export default { console.error('Problem with Category asyncData', e) } }, + async mounted () { + await this.$store.dispatch('category-next/cacheProducts', { route: this.$route }) + }, methods: { openFilters () { this.mobileFilters = true From 6208010757ffcc09c8529d1ce56eaa2bb70c249a Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Mon, 3 Jun 2019 16:18:16 +0200 Subject: [PATCH 0044/1227] improve service worker catalog cache --- core/build/webpack.prod.sw.config.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/build/webpack.prod.sw.config.ts b/core/build/webpack.prod.sw.config.ts index f21fb672a..f8ae620ec 100644 --- a/core/build/webpack.prod.sw.config.ts +++ b/core/build/webpack.prod.sw.config.ts @@ -60,10 +60,12 @@ module.exports = merge(base, { { urlPattern: '/img/(.*)', handler: 'fastest' - }, { - urlPattern: '/api/catalog/*', + }, + { + urlPattern: /(http[s]?:\/\/)?(\/)?([^\/\s]+\/)?(api\/catalog\/)(.*)/g, handler: 'networkFirst' - }, { + }, + { urlPattern: '/api/*', handler: 'networkFirst' }, { From 4a687c5b6f86c33ca13ef0e09f01327efed31509 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Tue, 4 Jun 2019 15:25:14 +0200 Subject: [PATCH 0045/1227] use filters on product page --- core/modules/catalog/helpers/index.ts | 4 +- core/pages/Product.js | 4 +- .../default/components/core/ColorSelector.vue | 1 + src/themes/default/mixins/filterMixin.ts | 4 +- src/themes/default/pages/Product.vue | 87 ++++++++++++------- 5 files changed, 67 insertions(+), 33 deletions(-) diff --git a/core/modules/catalog/helpers/index.ts b/core/modules/catalog/helpers/index.ts index 6174b1cca..04a445922 100644 --- a/core/modules/catalog/helpers/index.ts +++ b/core/modules/catalog/helpers/index.ts @@ -437,9 +437,9 @@ export function findConfigurableChildAsync ({ product, configuration = null, sel return Object.keys(omit(configuration, ['price'])).every((configProperty) => { let configurationPropertyFilters = configuration[configProperty] || [] if (!Array.isArray(configurationPropertyFilters)) configurationPropertyFilters = [configurationPropertyFilters] - const configurationIds = configurationPropertyFilters.map(filter => filter.id).filter(filterId => !!filterId) + const configurationIds = configurationPropertyFilters.map(filter => toString(filter.id)).filter(filterId => !!filterId) if (!configurationIds.length) return true // skip empty - return configurationIds.includes(configurableChild[configProperty]) + return configurationIds.includes(toString(configurableChild[configProperty])) }) } }) diff --git a/core/pages/Product.js b/core/pages/Product.js index 3ded41026..15be420ba 100644 --- a/core/pages/Product.js +++ b/core/pages/Product.js @@ -127,7 +127,9 @@ export default { isOptionAvailable (option) { // check if the option is available let currentConfig = Object.assign({}, this.configuration) currentConfig[option.attribute_code] = option - return isOptionAvailableAsync(this.$store, { product: this.product, configuration: currentConfig }) + const x = isOptionAvailableAsync(this.$store, { product: this.product, configuration: currentConfig }) + console.error(x) + return true // TODO fix checking }, onAfterCustomOptionsChanged (payload) { let priceDelta = 0 diff --git a/src/themes/default/components/core/ColorSelector.vue b/src/themes/default/components/core/ColorSelector.vue index 0cc0ce667..7b9669c04 100644 --- a/src/themes/default/components/core/ColorSelector.vue +++ b/src/themes/default/components/core/ColorSelector.vue @@ -19,6 +19,7 @@ export default { mixins: [filterMixin], methods: { colorFrom (label) { + if (!label) return '' if (config.products.colorMappings) { if (typeof config.products.colorMappings[label] !== 'undefined') { label = config.products.colorMappings[label] diff --git a/src/themes/default/mixins/filterMixin.ts b/src/themes/default/mixins/filterMixin.ts index 3778ccb55..a911c7f5f 100644 --- a/src/themes/default/mixins/filterMixin.ts +++ b/src/themes/default/mixins/filterMixin.ts @@ -1,3 +1,5 @@ +import toString from 'lodash-es/toString' + export default { props: { variant: { @@ -14,7 +16,7 @@ export default { const selectedVariantFilter = this.selectedFilters[this.variant.type] if (!selectedVariantFilter) return false if (Array.isArray(selectedVariantFilter)) return !!selectedVariantFilter.find(variant => variant.id === this.variant.id) - return selectedVariantFilter.id === this.variant.id + return toString(selectedVariantFilter.id) === toString(this.variant.id) } } } diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index 3c4d17562..bbcd7fb6e 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -59,9 +59,8 @@
{{ option.label }} @@ -72,42 +71,34 @@
{ + const type = configurableOption.attribute_code + const filterVariants = configurableOption.values.map(({value_index, label}) => { + return {id: value_index, label, type} + }) + filtersMap[type] = filterVariants + }) + } + return filtersMap + }, + getSelectedFilters () { + // TODO move to helper + let selectedFilters = {} + if (this.configuration) { + Object.keys(this.configuration).map(filterType => { + const filter = this.configuration[filterType] + selectedFilters[filterType] = { + id: filter.id, + label: filter.label, + type: filterType + } + }) + } + return selectedFilters } }, methods: { @@ -306,6 +332,9 @@ export default { message: this.$t('No such configuration for the product. Please do choose another combination of attributes.'), action1: { label: this.$t('OK') } }) + }, + changeFilter (variant) { + this.$bus.$emit('filter-changed-product', Object.assign({ attribute_code: variant.type} , variant)) } }, validations: { From abfa197cb6e92a6159d0c60e8c516cb331110cb9 Mon Sep 17 00:00:00 2001 From: patzick Date: Fri, 7 Jun 2019 08:12:37 +0200 Subject: [PATCH 0046/1227] cleaning code and dependencies --- .../modules/catalog-next/helpers/categoryHelpers.ts | 10 ++++++++++ .../categoryLogic.ts => helpers/filterHelpers.ts} | 13 +++---------- .../catalog-next/store/category/CategoryState.ts | 11 ----------- core/modules/catalog-next/store/category/actions.ts | 2 +- core/modules/catalog-next/store/category/getters.ts | 4 ++-- .../test/unit/changeFilterQuery.spec.ts | 2 +- .../test/unit/getFiltersFromQuery.spec.ts | 2 +- 7 files changed, 18 insertions(+), 26 deletions(-) rename core/modules/catalog-next/{store/category/logic/categoryLogic.ts => helpers/filterHelpers.ts} (93%) diff --git a/core/modules/catalog-next/helpers/categoryHelpers.ts b/core/modules/catalog-next/helpers/categoryHelpers.ts index 804466ca1..b426b3d89 100644 --- a/core/modules/catalog-next/helpers/categoryHelpers.ts +++ b/core/modules/catalog-next/helpers/categoryHelpers.ts @@ -1,5 +1,15 @@ import { parseCategoryPath } from '@vue-storefront/core/modules/breadcrumbs/helpers' +export const compareByLabel = ( a, b ) => { + if ( a.label < b.label ){ + return -1 + } + if ( a.label > b.label ){ + return 1 + } + return 0 +} + export const calculateBreadcrumbs = (categories, id, list = []) => { const category = categories.find(category => category.id === id) if (!category) return parseCategoryPath(list).reverse() diff --git a/core/modules/catalog-next/store/category/logic/categoryLogic.ts b/core/modules/catalog-next/helpers/filterHelpers.ts similarity index 93% rename from core/modules/catalog-next/store/category/logic/categoryLogic.ts rename to core/modules/catalog-next/helpers/filterHelpers.ts index 3c72c5e01..8cd55504e 100644 --- a/core/modules/catalog-next/store/category/logic/categoryLogic.ts +++ b/core/modules/catalog-next/helpers/filterHelpers.ts @@ -1,17 +1,10 @@ import FilterVariant from 'core/modules/catalog-next/types/FilterVariant'; -export const compareByLabel = ( a, b ) => { - if ( a.label < b.label ){ - return -1 - } - if ( a.label > b.label ){ - return 1 - } - return 0 -} - export const getSystemFilterNames:Array = ['sort'] +/** + * Creates new filtersQuery (based on currentQuery) by modifying specific filter variant. + */ export const changeFilterQuery = ({currentQuery = {}, filterVariant}:{currentQuery?:any, filterVariant?:FilterVariant} = {}) => { const newQuery = JSON.parse(JSON.stringify(currentQuery)) if (!filterVariant) return newQuery diff --git a/core/modules/catalog-next/store/category/CategoryState.ts b/core/modules/catalog-next/store/category/CategoryState.ts index 317fe81d1..f3aef14f4 100644 --- a/core/modules/catalog-next/store/category/CategoryState.ts +++ b/core/modules/catalog-next/store/category/CategoryState.ts @@ -2,15 +2,4 @@ export default interface CategoryState { categories: any, availableFilters: any, products: any - // list: any, - // current: any, - // filters: { - // available: any, - // chosen: any - // }, - // breadcrumbs: { - // routes: any - // }, - // current_product_query: any, - // current_path: any } diff --git a/core/modules/catalog-next/store/category/actions.ts b/core/modules/catalog-next/store/category/actions.ts index b28494e56..51a6ac852 100644 --- a/core/modules/catalog-next/store/category/actions.ts +++ b/core/modules/catalog-next/store/category/actions.ts @@ -8,7 +8,7 @@ import { buildFilterProductsQuery } from '@vue-storefront/core/helpers' import { router } from '@vue-storefront/core/app' import FilterVariant from '../../types/FilterVariant' import { CategoryService } from '@vue-storefront/core/data-resolver' -import { changeFilterQuery } from './logic/categoryLogic' +import { changeFilterQuery } from '../../helpers/filterHelpers' import { products } from 'config' import { configureProductAsync } from '@vue-storefront/core/modules/catalog/helpers' diff --git a/core/modules/catalog-next/store/category/getters.ts b/core/modules/catalog-next/store/category/getters.ts index 00ea6558b..8b37dfdec 100644 --- a/core/modules/catalog-next/store/category/getters.ts +++ b/core/modules/catalog-next/store/category/getters.ts @@ -1,13 +1,13 @@ import { GetterTree } from 'vuex' import RootState from '@vue-storefront/core/types/RootState' import CategoryState from './CategoryState' -import { calculateBreadcrumbs } from '../../helpers/categoryHelpers' +import { compareByLabel, calculateBreadcrumbs } from '../../helpers/categoryHelpers' import { products } from 'config' import FilterVariant from '../../types/FilterVariant' import { optionLabel } from '../../helpers/optionLabel' import trim from 'lodash-es/trim' import toString from 'lodash-es/toString' -import { compareByLabel, getFiltersFromQuery } from './logic/categoryLogic' +import { getFiltersFromQuery } from '../../helpers/filterHelpers' const getters: GetterTree = { getCategories: (state) => state.categories || [], diff --git a/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts b/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts index 2612ef643..8f86a7d5e 100644 --- a/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts +++ b/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts @@ -1,4 +1,4 @@ -import { changeFilterQuery } from '@vue-storefront/core/modules/catalog-next/store/category/logic/categoryLogic'; +import { changeFilterQuery } from '@vue-storefront/core/modules/catalog-next/helpers/filterHelpers'; import FilterVariant from '@vue-storefront/core/modules/catalog-next/types/FilterVariant'; describe('changeFilterQuery method', () => { diff --git a/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts b/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts index 73f4b4654..73e67f260 100644 --- a/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts +++ b/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts @@ -1,4 +1,4 @@ -import { getFiltersFromQuery } from "@vue-storefront/core/modules/catalog-next/store/category/logic/categoryLogic"; +import { getFiltersFromQuery } from "../../helpers/filterHelpers"; describe('getFiltersFromQuery method', () => { let availableFilters From d562a39fcd88f4274447ee0dfedab474e15a2a70 Mon Sep 17 00:00:00 2001 From: miluka Date: Mon, 10 Jun 2019 09:40:38 +0200 Subject: [PATCH 0047/1227] Links product in the wishlist with a proper variant. --- .../core/blocks/Wishlist/Product.vue | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/themes/default/components/core/blocks/Wishlist/Product.vue b/src/themes/default/components/core/blocks/Wishlist/Product.vue index 3fc70abc3..61008fb43 100644 --- a/src/themes/default/components/core/blocks/Wishlist/Product.vue +++ b/src/themes/default/components/core/blocks/Wishlist/Product.vue @@ -1,52 +1,57 @@ diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index 247fc93b6..280bb8b69 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -33,7 +33,9 @@ class="mb20 uppercase cl-secondary" itemprop="sku" :content="product.sku" - >{{ $t('SKU') }}: {{ product.sku }}
+ > + {{ $t('SKU') }}: {{ product.sku }} +
@@ -54,13 +56,17 @@
{{ product.qty > 0 ? product.priceInclTax * product.qty : product.priceInclTax | price }}
+ > + {{ product.qty > 0 ? product.priceInclTax * product.qty : product.priceInclTax | price }} +
{{ product.errors | formatProductMessages }}
+ > + {{ product.errors | formatProductMessages }} +
- +
- +
@@ -175,11 +182,13 @@
-

{{ $t('Product details') }}

+

+ {{ $t('Product details') }} +

-
+
    @@ -192,15 +201,15 @@ />
-
+
- - - - - + + + + + @@ -250,7 +259,7 @@ export default { SizeGuide }, mixins: [Product, VueOfflineMixin], - data() { + data () { return { detailsOpen: false, quantity: 0 @@ -258,24 +267,24 @@ export default { }, directives: { focusClean }, computed: { - structuredData() { + structuredData () { return { availability: this.product.stock.is_in_stock ? 'InStock' : 'OutOfStock' } } }, - created() { + created () { this.getQuantity() }, - updated() { + updated () { this.getQuantity() }, methods: { - showDetails(event) { + showDetails (event) { this.detailsOpen = true event.target.classList.add('hidden') }, - notifyOutStock() { + notifyOutStock () { this.$store.dispatch('notification/spawnNotification', { type: 'error', message: this.$t( @@ -284,7 +293,7 @@ export default { action1: { label: this.$t('OK') } }) }, - notifyWrongAttributes() { + notifyWrongAttributes () { this.$store.dispatch('notification/spawnNotification', { type: 'warning', message: this.$t( @@ -293,10 +302,10 @@ export default { action1: { label: this.$t('OK') } }) }, - openSizeGuide() { + openSizeGuide () { this.$bus.$emit('modal-show', 'modal-sizeguide') }, - getQuantity() { + getQuantity () { this.$store .dispatch('stock/check', { product: this.product, From 4bfa06486b1f48bfe042276a9a098340dd03a8c5 Mon Sep 17 00:00:00 2001 From: Michal-Dziedzinski Date: Mon, 1 Jul 2019 17:00:05 +0200 Subject: [PATCH 0148/1227] Added disable atribute to input component --- .../default/components/core/blocks/Form/BaseInputNumber.vue | 5 +++++ src/themes/default/pages/Product.vue | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/themes/default/components/core/blocks/Form/BaseInputNumber.vue b/src/themes/default/components/core/blocks/Form/BaseInputNumber.vue index aaf6d7bf4..0bc85e7e9 100644 --- a/src/themes/default/components/core/blocks/Form/BaseInputNumber.vue +++ b/src/themes/default/components/core/blocks/Form/BaseInputNumber.vue @@ -6,6 +6,7 @@ type="number" :min="min" :max="max" + :disabled="disabled" class="m0 no-outline base-input-number__input brdr-cl-primary bg-cl-transparent h4" :focus="autofocus" :value="value" @@ -44,6 +45,10 @@ export default { type: Number, default: 0 }, + disabled: { + type: Boolean, + default: false + }, autofocus: { type: Boolean, required: false, diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index 280bb8b69..dd88f9d59 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -151,8 +151,10 @@ = product.originalPriceInclTax) { + if (product.price_incl_tax >= product.original_price_incl_tax) { product.special_price_incl_tax = 0 product.special_price = 0 } + + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceInclTax = product.price_incl_tax + product.priceTax = product.price_tax + product.originalPrice = product.original_price + product.originalPriceInclTax = product.original_price_incl_tax + product.originalPriceTax = product.original_price_tax + product.specialPriceInclTax = product.special_price_incl_tax + product.specialPriceTax = product.special_price_tax + /** END */ EventBus.$emit('product-after-priceupdate', product) // Logger.log(product.sku, product, backProduct)() return product @@ -198,30 +208,50 @@ export function doPlatformPricesSync (products) { if (config.products.clearPricesBeforePlatformSync) { for (let product of products) { // clear out the prices as we need to sync them with Magento product.price_incl_tax = null - product.originalPriceInclTax = null + product.original_price_incl_tax = null product.special_price_incl_tax = null product.special_price = null product.price = null - product.originalPrice = null + product.original_price = null product.price_tax = null product.special_price_tax = null - product.originalPriceTax = null + product.original_price_tax = null + + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceInclTax = product.price_incl_tax + product.priceTax = product.price_tax + product.originalPrice = product.original_price + product.originalPriceInclTax = product.original_price_incl_tax + product.originalPriceTax = product.original_price_tax + product.specialPriceInclTax = product.special_price_incl_tax + product.specialPriceTax = product.special_price_tax + /** END */ if (product.configurable_children) { for (let sc of product.configurable_children) { sc.price_incl_tax = null - sc.originalPriceInclTax = null + sc.original_price_incl_tax = null sc.special_price_incl_tax = null sc.special_price = null sc.price = null - sc.originalPrice = null + sc.original_price = null sc.price_tax = null sc.special_price_tax = null - sc.originalPriceTax = null + sc.original_price_tax = null + + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + sc.priceInclTax = sc.price_incl_tax + sc.priceTax = sc.price_tax + sc.originalPrice = sc.original_price + sc.originalPriceInclTax = sc.original_price_incl_tax + sc.originalPriceTax = sc.original_price_tax + sc.specialPriceInclTax = sc.special_price_incl_tax + sc.specialPriceTax = sc.special_price_tax + /** END */ } } } diff --git a/core/modules/catalog/helpers/tax.ts b/core/modules/catalog/helpers/tax.ts index 15947439b..f736e52df 100644 --- a/core/modules/catalog/helpers/tax.ts +++ b/core/modules/catalog/helpers/tax.ts @@ -77,7 +77,6 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) product.price_tax = product.special_price_tax /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - product.price = special_price_excl_tax product.priceInclTax = product.price_incl_tax product.priceTax = product.price_tax product.originalPrice = product.original_price diff --git a/docs/guide/basics/configuration.md b/docs/guide/basics/configuration.md index e8d780055..286621852 100644 --- a/docs/guide/basics/configuration.md +++ b/docs/guide/basics/configuration.md @@ -232,11 +232,11 @@ Please take a look at the [core/modules/cart](https://github.com/DivanteLtd/vue- }, "productList": { "sort": "", - "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "priceInclTax", "originalPriceInclTax", "originalPrice", "specialPriceInclTax", "id", "image", "sale", "new", "url_key", "status" ], + "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "specialPriceInclTax", "id", "image", "sale", "new", "url_key", "status" ], "excludeFields": [ "configurable_children", "description", "configurable_options", "sgn" ] }, "productListWithChildren": { - "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "priceInclTax", "originalPriceInclTax", "originalPrice", "specialPriceInclTax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.originalPrice", "configurable_children.originalPriceInclTax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "product_links", "url_key", "status"], + "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "priceInclTax", "original_price_incl_tax", "original_price", "specialPriceInclTax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "product_links", "url_key", "status"], "excludeFields": [ "description", "sgn"] }, "product": { diff --git a/docs/guide/upgrade-notes/README.md b/docs/guide/upgrade-notes/README.md index fe58e2a1b..2c4e4d4f9 100644 --- a/docs/guide/upgrade-notes/README.md +++ b/docs/guide/upgrade-notes/README.md @@ -413,11 +413,11 @@ The endpoints are also set by the `yarn installer` so You can try to reinstall V "includeFields": [ "attribute_code", "id", "entity_type_id", "options", "default_value", "is_user_defined", "frontend_label", "attribute_id", "default_frontend_label", "is_visible_on_front", "is_visible", "is_comparable" ] }, "productList": { - "includeFields": [ "type_id", "sku", "name", "price", "priceInclTax", "originalPriceInclTax", "id", "image", "sale", "new" ], + "includeFields": [ "type_id", "sku", "name", "price", "priceInclTax", "original_price_incl_tax", "id", "image", "sale", "new" ], "excludeFields": [ "configurable_children", "description", "configurable_options", "sgn", "tax_class_id" ] }, "productListWithChildren": { - "includeFields": [ "type_id", "sku", "name", "price", "priceInclTax", "originalPriceInclTax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.originalPrice", "configurable_children.originalPriceInclTax", "configurable_children.color", "configurable_children.size" ], + "includeFields": [ "type_id", "sku", "name", "price", "priceInclTax", "original_price_incl_tax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size" ], "excludeFields": [ "description", "sgn", "tax_class_id" ] }, "product": { diff --git a/src/themes/default-amp/components/core/ProductTile.vue b/src/themes/default-amp/components/core/ProductTile.vue index d47f62d72..006374296 100755 --- a/src/themes/default-amp/components/core/ProductTile.vue +++ b/src/themes/default-amp/components/core/ProductTile.vue @@ -26,9 +26,9 @@ - {{ product.originalPriceInclTax | price }} + {{ product.original_price_incl_tax | price }}
{{ product.price_incl_tax * product.qty | price }}   - {{ product.originalPriceInclTax * product.qty | price }} + {{ product.original_price_incl_tax * product.qty | price }}
-
+
{{ productLink.product.price_incl_tax | price }}  - {{ productLink.product.originalPriceInclTax | price }} + {{ productLink.product.original_price_incl_tax | price }}
{{ productLink.product.price_incl_tax | price }} diff --git a/src/themes/default/components/core/ProductTile.vue b/src/themes/default/components/core/ProductTile.vue index 7f7e2b590..018c82d00 100644 --- a/src/themes/default/components/core/ProductTile.vue +++ b/src/themes/default/components/core/ProductTile.vue @@ -26,9 +26,9 @@ - {{ product.originalPriceInclTax | price }} + {{ product.original_price_incl_tax | price }}
{{ product.price_incl_tax * product.qty | price }} - {{ product.originalPriceInclTax * product.qty | price }} + {{ product.original_price_incl_tax * product.qty | price }} {{ product.price_incl_tax * product.qty | price }}
diff --git a/src/themes/default/components/core/blocks/Microcart/Product.vue b/src/themes/default/components/core/blocks/Microcart/Product.vue index ffb9ab792..59644a65d 100644 --- a/src/themes/default/components/core/blocks/Microcart/Product.vue +++ b/src/themes/default/components/core/blocks/Microcart/Product.vue @@ -52,10 +52,10 @@ {{ product.price_incl_tax * product.qty | price }}  - {{ product.originalPriceInclTax * product.qty | price }} + {{ product.original_price_incl_tax * product.qty | price }} - {{ (product.originalPriceInclTax ? product.originalPriceInclTax : product.price_incl_tax) * product.qty | price }} + {{ (product.original_price_incl_tax ? product.original_price_incl_tax : product.price_incl_tax) * product.qty | price }}
diff --git a/src/themes/default/components/core/blocks/Wishlist/Product.vue b/src/themes/default/components/core/blocks/Wishlist/Product.vue index 9af04b169..41ade9762 100644 --- a/src/themes/default/components/core/blocks/Wishlist/Product.vue +++ b/src/themes/default/components/core/blocks/Wishlist/Product.vue @@ -18,7 +18,7 @@
{{ product.price_incl_tax | price }}  - {{ product.originalPriceInclTax | price }} + {{ product.original_price_incl_tax | price }} {{ product.price_incl_tax | price }} diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index aea718421..27eef4643 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -35,13 +35,13 @@ >
{{ product.price_incl_tax * product.qty | price }}   - {{ product.originalPriceInclTax * product.qty | price }} + {{ product.original_price_incl_tax * product.qty | price }}
Date: Mon, 1 Jul 2019 23:06:38 +0200 Subject: [PATCH 0151/1227] eslint fixes --- config/default.json | 6 +++--- core/modules/catalog/helpers/index.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/default.json b/config/default.json index 4442a37ae..d882bc40a 100644 --- a/config/default.json +++ b/config/default.json @@ -164,11 +164,11 @@ }, "productList": { "sort": "updated_at:desc", - "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "specialprice_incl_tax", "id", "image", "sale", "new", "url_path", "url_key", "status", "tier_prices", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax" ], + "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "url_path", "url_key", "status", "tier_prices", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax" ], "excludeFields": [ "description", "configurable_options", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options" ] }, "productListWithChildren": { - "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "specialprice_incl_tax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "configurable_children.tier_prices", "product_links", "url_path", "url_key", "status", "tier_prices"], + "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "configurable_children.tier_prices", "product_links", "url_path", "url_key", "status", "tier_prices"], "excludeFields": [ "description", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options"] }, "review": { @@ -214,7 +214,7 @@ "price_tax", "price_incl_tax", "special_price_tax", - "specialprice_incl_tax", + "special_price_incl_tax", "_score", "slug", "errors", diff --git a/core/modules/catalog/helpers/index.ts b/core/modules/catalog/helpers/index.ts index 912fcd7eb..16bca786f 100644 --- a/core/modules/catalog/helpers/index.ts +++ b/core/modules/catalog/helpers/index.ts @@ -193,7 +193,7 @@ export function syncProductPrice (product, backProduct) { // TODO: we probably n product.originalPriceTax = product.original_price_tax product.specialPriceInclTax = product.special_price_incl_tax product.specialPriceTax = product.special_price_tax - /** END */ + /** END */ EventBus.$emit('product-after-priceupdate', product) // Logger.log(product.sku, product, backProduct)() return product @@ -227,7 +227,7 @@ export function doPlatformPricesSync (products) { product.originalPriceTax = product.original_price_tax product.specialPriceInclTax = product.special_price_incl_tax product.specialPriceTax = product.special_price_tax - /** END */ + /** END */ if (product.configurable_children) { for (let sc of product.configurable_children) { @@ -251,7 +251,7 @@ export function doPlatformPricesSync (products) { sc.originalPriceTax = sc.original_price_tax sc.specialPriceInclTax = sc.special_price_incl_tax sc.specialPriceTax = sc.special_price_tax - /** END */ + /** END */ } } } From 2063aadb3fc8131fe8baa02383df7681f81ac125 Mon Sep 17 00:00:00 2001 From: pkarw Date: Mon, 1 Jul 2019 23:12:25 +0200 Subject: [PATCH 0152/1227] Additional price names fixed --- core/modules/catalog/types/Product.ts | 8 ++++---- docs/guide/basics/configuration.md | 4 ++-- src/themes/default/resource/i18n/en-US.csv | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/modules/catalog/types/Product.ts b/core/modules/catalog/types/Product.ts index 356afbfe0..0c2a4b470 100644 --- a/core/modules/catalog/types/Product.ts +++ b/core/modules/catalog/types/Product.ts @@ -27,8 +27,8 @@ export default interface Product { parentSku?: string, pattern?: string, price: number, - priceInclTax?: number, - priceTax?: number, + price_incl_tax?: number, + price_tax?: number, product_links?: Record[], product_option?: Record, regular_price: number, @@ -40,8 +40,8 @@ export default interface Product { sku: string, slug?: string, small_image?: string, - specialPriceInclTax?: any, - specialPriceTax?: any, + special_price_incl_tax?: any, + special_price_tax?: any, special_price?: number, status: number, stock: Record, diff --git a/docs/guide/basics/configuration.md b/docs/guide/basics/configuration.md index 286621852..81100e676 100644 --- a/docs/guide/basics/configuration.md +++ b/docs/guide/basics/configuration.md @@ -232,11 +232,11 @@ Please take a look at the [core/modules/cart](https://github.com/DivanteLtd/vue- }, "productList": { "sort": "", - "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "specialPriceInclTax", "id", "image", "sale", "new", "url_key", "status" ], + "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "url_key", "status" ], "excludeFields": [ "configurable_children", "description", "configurable_options", "sgn" ] }, "productListWithChildren": { - "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "priceInclTax", "original_price_incl_tax", "original_price", "specialPriceInclTax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "product_links", "url_key", "status"], + "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "priceInclTax", "original_price_incl_tax", "original_price", "special_price_incl_t_ax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "product_links", "url_key", "status"], "excludeFields": [ "description", "sgn"] }, "product": { diff --git a/src/themes/default/resource/i18n/en-US.csv b/src/themes/default/resource/i18n/en-US.csv index 95d82e084..30716a430 100644 --- a/src/themes/default/resource/i18n/en-US.csv +++ b/src/themes/default/resource/i18n/en-US.csv @@ -5,6 +5,7 @@ "You have been successfully subscribed to our newsletter!","You have been successfully subscribed to our newsletter!" "Everything new","Everything new" "Get inspired","Get inspired" +"Columns","Columns" "Size guide","Size guide" "Add to favorite","Add to favorite" "Add to compare","Add to compare" From 1434ad8f7fb03200d32e33c819648bd6cfa19df9 Mon Sep 17 00:00:00 2001 From: pkarw Date: Mon, 1 Jul 2019 23:13:14 +0200 Subject: [PATCH 0153/1227] Update cartCacheHandler.spec.ts --- core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts index 4b079a0cd..553996471 100644 --- a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts +++ b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts @@ -2,7 +2,6 @@ import Vue from 'vue' import Vuex from 'vuex' import * as types from '../../../store/mutation-types' -import { cartCacheHandlerFactory } from '../../../helpers/cartCacheHandler'; const StorageManager = { cartsCollection: { setItem: jest.fn() @@ -12,6 +11,8 @@ const StorageManager = { } }; jest.mock('@vue-storefront/core/store/lib/storage-manager', () => ({StorageManager})) + +import { cartCacheHandlerFactory } from '../../../helpers/cartCacheHandler'; jest.mock('@vue-storefront/core/helpers', () => ({ isServer: () => false })); From 58f3ef71c15218cf944ac6613944355ce06a3e35 Mon Sep 17 00:00:00 2001 From: pkarw Date: Mon, 1 Jul 2019 23:23:30 +0200 Subject: [PATCH 0154/1227] Code sample removed from the docs --- .../offline-order/components/CancelOrders.ts | 8 +- .../helpers/onNetworkStatusChange.ts | 11 +-- .../modules/order/hooks/beforeRegistration.ts | 12 +-- docs/guide/data/data.md | 90 ------------------- 4 files changed, 6 insertions(+), 115 deletions(-) diff --git a/core/modules/offline-order/components/CancelOrders.ts b/core/modules/offline-order/components/CancelOrders.ts index 062f3fc58..5f733504b 100644 --- a/core/modules/offline-order/components/CancelOrders.ts +++ b/core/modules/offline-order/components/CancelOrders.ts @@ -4,16 +4,12 @@ import store from '@vue-storefront/core/store' import UniversalStorage from '@vue-storefront/core/store/lib/storage' import { Logger } from '@vue-storefront/core/lib/logger' import config from 'config' +import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' export const CancelOrders = { methods: { cancelOrders () { - const ordersCollection = new UniversalStorage(localForage.createInstance({ - name: 'shop', - storeName: 'orders', - driver: localForage[config.localForage.defaultDrivers['orders']] - })) - + const ordersCollection = initCacheStorage('orders', false, true) ordersCollection.iterate((order, id, iterationNumber) => { if (!order.transmited) { ordersCollection.removeItem(id) diff --git a/core/modules/offline-order/helpers/onNetworkStatusChange.ts b/core/modules/offline-order/helpers/onNetworkStatusChange.ts index 3c4347965..1e8f0852f 100644 --- a/core/modules/offline-order/helpers/onNetworkStatusChange.ts +++ b/core/modules/offline-order/helpers/onNetworkStatusChange.ts @@ -1,9 +1,7 @@ -import * as localForage from 'localforage' import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus/index' -import UniversalStorage from '@vue-storefront/core/store/lib/storage' -import { currentStoreView } from '@vue-storefront/core/lib/multistore' import { Logger } from '@vue-storefront/core/lib/logger' import config from 'config' +import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage'; export function onNetworkStatusChange (store) { Logger.log('Are we online: ' + navigator.onLine, 'offline-order')() @@ -15,12 +13,7 @@ export function onNetworkStatusChange (store) { EventBus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue } else { const ordersToConfirm = [] - const storeView = currentStoreView() - const ordersCollection = new UniversalStorage(localForage.createInstance({ - name: 'shop', - storeName: 'orders', - driver: localForage[config.localForage.defaultDrivers['orders']] - })) + const ordersCollection = initCacheStorage('orders', false, true) ordersCollection.iterate((order, id, iterationNumber) => { if (!order.transmited) { diff --git a/core/modules/order/hooks/beforeRegistration.ts b/core/modules/order/hooks/beforeRegistration.ts index f7eaa4269..39f984b9b 100644 --- a/core/modules/order/hooks/beforeRegistration.ts +++ b/core/modules/order/hooks/beforeRegistration.ts @@ -2,11 +2,11 @@ import * as localForage from 'localforage' import UniversalStorage from '@vue-storefront/core/store/lib/storage' import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus/index' import { Logger } from '@vue-storefront/core/lib/logger' -import { currentStoreView } from '@vue-storefront/core/lib/multistore'; import rootStore from '@vue-storefront/core/store' import i18n from '@vue-storefront/i18n' import { serial, onlineHelper, processURLAddress } from '@vue-storefront/core/helpers' import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' +import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' export function beforeRegistration ({ Vue, config, store, isServer }) { StorageManager.register('ordersCollection', new UniversalStorage(localForage.createInstance({ @@ -20,15 +20,7 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { EventBus.$on('order/PROCESS_QUEUE', async event => { if (onlineHelper.isOnline) { Logger.log('Sending out orders queue to server ...')() - - const storeView = currentStoreView() - const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - - const ordersCollection = new UniversalStorage(localForage.createInstance({ - name: dbNamePrefix + 'shop', - storeName: 'orders', - driver: localForage[config.localForage.defaultDrivers['orders']] - })) + const ordersCollection = initCacheStorage('orders', false, true) const fetchQueue = [] ordersCollection.iterate((order, id) => { diff --git a/docs/guide/data/data.md b/docs/guide/data/data.md index 391539689..e8e7a7d6a 100644 --- a/docs/guide/data/data.md +++ b/docs/guide/data/data.md @@ -11,96 +11,6 @@ You can access localForage repositories through the `StorageManager` (`@vue-stor Details on localForage API can be found [here](http://localforage.github.io/localForage/) -We have the following data stores accessible in the browser (`/core/store/index.ts`): - -```js -const StorageManager = { - ordersCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'orders', - }), - ), - - categoriesCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'categories', - }), - ), - - attributesCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'attributes', - }), - ), - - cartsCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'carts', - }), - ), - - elasticCacheCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'elasticCache', - }), - ), - - productsCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'products', - }), - ), - - claimsCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'claims', - }), - ), - - wishlistCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'wishlist', - }), - ), - - compareCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'compare', - }), - ), - - usersCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'user', - }), - ), - - syncTaskCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'syncTasks', - }), - ), - - checkoutFieldsCollection: new UniversalStorage( - localForage.createInstance({ - name: 'shop', - storeName: 'checkoutFieldValues', - }), - ), -}; -``` - ## Example Vuex store Here you have an example on how the Vuex store should be constructed. Please notice the _Ajv data validation_: From 706a68be4728926d1eb4646a39636c641e27beeb Mon Sep 17 00:00:00 2001 From: pkarw Date: Tue, 2 Jul 2019 00:06:26 +0200 Subject: [PATCH 0155/1227] Fix - final_price does include tax --- core/modules/catalog/helpers/tax.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/modules/catalog/helpers/tax.ts b/core/modules/catalog/helpers/tax.ts index f736e52df..63eba7c7a 100644 --- a/core/modules/catalog/helpers/tax.ts +++ b/core/modules/catalog/helpers/tax.ts @@ -22,7 +22,8 @@ function isSpecialPriceActive (fromDate, toDate) { export function updateProductPrices (product, rate, sourcePriceInclTax = false) { const rate_factor = parseFloat(rate.rate) / 100 - product.final_price = parseFloat(product.final_price) + product.final_price_incl_tax = parseFloat(product.final_price) // final price does include tax + product.final_price = product.final_price_incl_tax / (1 + rate_factor) product.price = parseFloat(product.price) product.special_price = parseFloat(product.special_price) @@ -97,7 +98,8 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) } configurableChild.price = parseFloat(configurableChild.price) configurableChild.special_price = parseFloat(configurableChild.special_price) - configurableChild.final_price = parseFloat(configurableChild.final_price) + configurableChild.final_price_incl_tax = parseFloat(configurableChild.final_price) // final price does include tax + configurableChild.final_price = configurableChild.final_price_incl_tax / (1 + rate_factor) if (configurableChild.final_price) { if (configurableChild.final_price < configurableChild.price) { // compare the prices with the product final price if provided; final prices is used in case of active catalog promo rules for example From 60727db5686e1c042861dad9bb75a95ce58f66bb Mon Sep 17 00:00:00 2001 From: pkarw Date: Tue, 2 Jul 2019 00:06:54 +0200 Subject: [PATCH 0156/1227] Fix - final_price does include tax --- core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts | 4 ++-- core/modules/catalog/helpers/tax.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts index 553996471..15351df0b 100644 --- a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts +++ b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts @@ -2,6 +2,8 @@ import Vue from 'vue' import Vuex from 'vuex' import * as types from '../../../store/mutation-types' + +import { cartCacheHandlerFactory } from '../../../helpers/cartCacheHandler'; const StorageManager = { cartsCollection: { setItem: jest.fn() @@ -11,8 +13,6 @@ const StorageManager = { } }; jest.mock('@vue-storefront/core/store/lib/storage-manager', () => ({StorageManager})) - -import { cartCacheHandlerFactory } from '../../../helpers/cartCacheHandler'; jest.mock('@vue-storefront/core/helpers', () => ({ isServer: () => false })); diff --git a/core/modules/catalog/helpers/tax.ts b/core/modules/catalog/helpers/tax.ts index 63eba7c7a..268462b19 100644 --- a/core/modules/catalog/helpers/tax.ts +++ b/core/modules/catalog/helpers/tax.ts @@ -99,7 +99,7 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) configurableChild.price = parseFloat(configurableChild.price) configurableChild.special_price = parseFloat(configurableChild.special_price) configurableChild.final_price_incl_tax = parseFloat(configurableChild.final_price) // final price does include tax - configurableChild.final_price = configurableChild.final_price_incl_tax / (1 + rate_factor) + configurableChild.final_price = configurableChild.final_price_incl_tax / (1 + rate_factor) if (configurableChild.final_price) { if (configurableChild.final_price < configurableChild.price) { // compare the prices with the product final price if provided; final prices is used in case of active catalog promo rules for example From 54767330cedf076233d0ea92e5ba0a609ca0987b Mon Sep 17 00:00:00 2001 From: pkarw Date: Tue, 2 Jul 2019 00:27:58 +0200 Subject: [PATCH 0157/1227] Unit tests to green --- core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts index 15351df0b..64443933e 100644 --- a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts +++ b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts @@ -3,7 +3,6 @@ import Vuex from 'vuex' import * as types from '../../../store/mutation-types' -import { cartCacheHandlerFactory } from '../../../helpers/cartCacheHandler'; const StorageManager = { cartsCollection: { setItem: jest.fn() @@ -13,6 +12,7 @@ const StorageManager = { } }; jest.mock('@vue-storefront/core/store/lib/storage-manager', () => ({StorageManager})) +import { cartCacheHandlerFactory } from '../../../helpers/cartCacheHandler'; jest.mock('@vue-storefront/core/helpers', () => ({ isServer: () => false })); From 483cc4e06d34d8059cf833f0a42dadfeb4945ffd Mon Sep 17 00:00:00 2001 From: pkarw Date: Tue, 2 Jul 2019 00:28:15 +0200 Subject: [PATCH 0158/1227] Update cartCacheHandler.spec.ts --- core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts index 64443933e..af7c96fc0 100644 --- a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts +++ b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts @@ -2,6 +2,7 @@ import Vue from 'vue' import Vuex from 'vuex' import * as types from '../../../store/mutation-types' +import { cartCacheHandlerFactory } from '../../../helpers/cartCacheHandler'; const StorageManager = { cartsCollection: { @@ -12,7 +13,6 @@ const StorageManager = { } }; jest.mock('@vue-storefront/core/store/lib/storage-manager', () => ({StorageManager})) -import { cartCacheHandlerFactory } from '../../../helpers/cartCacheHandler'; jest.mock('@vue-storefront/core/helpers', () => ({ isServer: () => false })); From 4b8cb3372adc5997a5f53bd0e925a4108aacc1f0 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 2 Jul 2019 09:14:49 +0200 Subject: [PATCH 0159/1227] remove autogenerated files --- packages/cli/boilerplates/module/.gitignore | 2 + packages/cli/boilerplates/module/package.json | 5 +- .../cli/boilerplates/module/tsconfig.json | 3 +- packages/module/helpers.js | 4 -- packages/module/hooks.js | 52 ------------------- packages/module/index.d.ts | 12 ----- packages/module/index.js | 15 ------ packages/module/index.ts | 3 +- 8 files changed, 9 insertions(+), 87 deletions(-) create mode 100644 packages/cli/boilerplates/module/.gitignore delete mode 100644 packages/module/helpers.js delete mode 100644 packages/module/hooks.js delete mode 100644 packages/module/index.d.ts delete mode 100644 packages/module/index.js diff --git a/packages/cli/boilerplates/module/.gitignore b/packages/cli/boilerplates/module/.gitignore new file mode 100644 index 000000000..9a18fd13b --- /dev/null +++ b/packages/cli/boilerplates/module/.gitignore @@ -0,0 +1,2 @@ +*.js +*.d.ts \ No newline at end of file diff --git a/packages/cli/boilerplates/module/package.json b/packages/cli/boilerplates/module/package.json index 2bb61ab43..09010c680 100644 --- a/packages/cli/boilerplates/module/package.json +++ b/packages/cli/boilerplates/module/package.json @@ -1,10 +1,11 @@ { - "name": "packages", + "name": "vsf-package", "version": "1.0.0", "description": "", "main": "index.js", + "types": "index.d.ts", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "tsc" }, "keywords": [], "author": "", diff --git a/packages/cli/boilerplates/module/tsconfig.json b/packages/cli/boilerplates/module/tsconfig.json index ebf2b301a..0c73c87de 100644 --- a/packages/cli/boilerplates/module/tsconfig.json +++ b/packages/cli/boilerplates/module/tsconfig.json @@ -4,7 +4,8 @@ "module": "commonjs", "declaration": true, "outDir": "./", - "strict": true + "strict": true, + "moduleResolution": "node" }, "include": [ "*.ts" diff --git a/packages/module/helpers.js b/packages/module/helpers.js deleted file mode 100644 index b544a86f7..000000000 --- a/packages/module/helpers.js +++ /dev/null @@ -1,4 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -function extendStore(moduleName, module) { } -exports.extendStore = extendStore; diff --git a/packages/module/hooks.js b/packages/module/hooks.js deleted file mode 100644 index 24b47c9ae..000000000 --- a/packages/module/hooks.js +++ /dev/null @@ -1,52 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var _a, _b, _c; -/** - Listener hook just fires functions passed to hook function when executor is invoked. - e. g. We want to listen for onAppInit event in various places of the application. - Functions passed to this hook will be invoked only when executor function is executed. - Usually we want to use hook in app/modules and executor in core. - @return hook: a hook function to use in modules - @return executor: a function that will run all the collected hooks - */ -function createListenerHook() { - var functionsToRun = []; - function hook(fn) { - functionsToRun.push(fn); - } - function executor(args) { - if (args === void 0) { args = null; } - functionsToRun.forEach(function (fn) { return fn(args); }); - } - return { - hook: hook, - executor: executor - }; -} -/** - Mutators work like listeners except they can modify passed value in hooks. - e.g we can apply the hook mutator to object order that is returned before placing order - now you can access and modify this value from hook returned by this function - @return hook: a hook function to use in modules - @return executor: a function that will apply all hooks on a given value - */ -function createMutatorHook() { - var mutators = []; - function hook(mutator) { - mutators.push(mutator); - } - function executor(rawOutput) { - var modifiedOutput = null; - mutators.forEach(function (fn) { - modifiedOutput = fn(rawOutput); - }); - return modifiedOutput; - } - return { - hook: hook, - executor: executor - }; -} -exports.afterAppInitHook = (_a = createListenerHook(), _a.hook), exports.afterAppInitExecutor = _a.executor; -exports.beforePlaceOrderHook = (_b = createMutatorHook(), _b.hook), exports.beforePlaceOrderExecutor = _b.executor; -exports.afterPlaceOrderHook = (_c = createListenerHook(), _c.hook), exports.afterPlaceOrderExecutor = _c.executor; diff --git a/packages/module/index.d.ts b/packages/module/index.d.ts deleted file mode 100644 index e49810a4b..000000000 --- a/packages/module/index.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface StorefrontModule { - (app: any, store: any, router: any, config: any, appConfig: any): void; -} -declare let refs: { - app: null; - store: null; - router: null; - config: null; -}; -declare function injectReferences(app: any, store: any, router: any, config: any): any; -declare function registerModule(module: StorefrontModule, config: any): void; -export { refs, injectReferences, registerModule }; diff --git a/packages/module/index.js b/packages/module/index.js deleted file mode 100644 index cc0ea46c3..000000000 --- a/packages/module/index.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var refs = { app: null, store: null, router: null, config: null }; -exports.refs = refs; -function injectReferences(app, store, router, config) { - refs.app = app; - refs.store = store; - refs.router = router; - refs.config = config; -} -exports.injectReferences = injectReferences; -function registerModule(module, config) { - module(refs.app, refs.store, refs.router, config, refs.config); -} -exports.registerModule = registerModule; diff --git a/packages/module/index.ts b/packages/module/index.ts index 18201b1e4..0e917bbce 100644 --- a/packages/module/index.ts +++ b/packages/module/index.ts @@ -7,6 +7,7 @@ export interface StorefrontModule { ( appConfig: any ) : void } +// because config can't be shared as peer dependency let refs = { app: null, store: null, router: null, config: null } function injectReferences (app: any, store: any, router: any, config: any): any { @@ -16,7 +17,7 @@ function injectReferences (app: any, store: any, router: any, config: any): any refs.config = config } -function registerModule (module: StorefrontModule, config) { +function registerModule (module: StorefrontModule, config: Object) { module(refs.app, refs.store, refs.router, config, refs.config) } From 3f2be046f8cf6ff096f910ac006cb5e70b4657e0 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 2 Jul 2019 09:15:16 +0200 Subject: [PATCH 0160/1227] make generated js ignored --- packages/module/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/module/.gitignore b/packages/module/.gitignore index 7d9896d1a..9a18fd13b 100644 --- a/packages/module/.gitignore +++ b/packages/module/.gitignore @@ -1,2 +1,2 @@ -.js +*.js *.d.ts \ No newline at end of file From a414803894096e0e4dcaf0c5041ebe90fccee786 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 2 Jul 2019 09:20:39 +0200 Subject: [PATCH 0161/1227] update helpers --- packages/module/helpers.ts | 2 +- packages/module/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/module/helpers.ts b/packages/module/helpers.ts index d7550c821..cdd1701a8 100644 --- a/packages/module/helpers.ts +++ b/packages/module/helpers.ts @@ -1 +1 @@ -export function extendStore (moduleName, module) {} \ No newline at end of file +export function extendStore (moduleName: String, module: any) {} \ No newline at end of file diff --git a/packages/module/package.json b/packages/module/package.json index 19f401412..3869cf813 100644 --- a/packages/module/package.json +++ b/packages/module/package.json @@ -2,7 +2,7 @@ "name": "@vue-storefront/module", "sideEffects": "false", "version": "0.0.1", - "description": "Vue Storefront modules implementation", + "description": "Vue Storefront modules source", "main": "index.js", "typings": "index.d.ts", From e52b1e92705ba85c137f08d93402f7c545c9a852 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 2 Jul 2019 09:48:56 +0200 Subject: [PATCH 0162/1227] change lerna versining to independent --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 76f848c82..b083c58a8 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "3.14.1", - "version": "1.11.0-rc.1", + "version": "independent", "npmClient": "yarn", "useWorkspaces": true, "registry": "https://registry.npmjs.org/" From 23dab04f6e3735380256c53db2ec59df4b2d554e Mon Sep 17 00:00:00 2001 From: Michal-Dziedzinski Date: Tue, 2 Jul 2019 12:30:51 +0200 Subject: [PATCH 0163/1227] Added button disable if quantity is equal 0 and changed InputNumber style --- .../default/components/core/blocks/Form/BaseInputNumber.vue | 1 - src/themes/default/pages/Product.vue | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/themes/default/components/core/blocks/Form/BaseInputNumber.vue b/src/themes/default/components/core/blocks/Form/BaseInputNumber.vue index 0bc85e7e9..a287633eb 100644 --- a/src/themes/default/components/core/blocks/Form/BaseInputNumber.vue +++ b/src/themes/default/components/core/blocks/Form/BaseInputNumber.vue @@ -88,7 +88,6 @@ export default { &__label { font-size: 0.8rem; line-height: 1.2rem; - max-width: 100px; @media (min-width: 768px) { font-size: 1rem; line-height: 1.4rem; diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index dd88f9d59..b0e584252 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -167,7 +167,7 @@
@@ -261,13 +261,13 @@ export default { SizeGuide }, mixins: [Product, VueOfflineMixin], + directives: { focusClean }, data () { return { detailsOpen: false, quantity: 0 } }, - directives: { focusClean }, computed: { structuredData () { return { From 716377f033eda43fefb8ad0ba21407738e71e069 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 2 Jul 2019 13:00:00 +0200 Subject: [PATCH 0164/1227] add unit tests --- packages/module/tests.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/module/tests.spec.ts b/packages/module/tests.spec.ts index e69de29bb..bd2c2a844 100644 --- a/packages/module/tests.spec.ts +++ b/packages/module/tests.spec.ts @@ -0,0 +1,18 @@ +import { refs, injectReferences } from "./index" + +describe('Modules', () => { + + it('Sets proper references', () => { + const appMock = {} + const storeMock = {} + const routerMock = {} + const configMock = {} + + injectReferences(appMock, storeMock, routerMock, configMock) + + expect(refs.app).toBe(appMock) + expect(refs.store).toBe(storeMock) + expect(refs.router).toBe(routerMock) + expect(refs.config).toBe(configMock) + }) +}) \ No newline at end of file From 016bec962d22fded7124633530f1542b8dedc206 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 2 Jul 2019 13:11:36 +0200 Subject: [PATCH 0165/1227] comment unit tests for now --- packages/module/tests.spec.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/module/tests.spec.ts b/packages/module/tests.spec.ts index bd2c2a844..0d15115ef 100644 --- a/packages/module/tests.spec.ts +++ b/packages/module/tests.spec.ts @@ -1,18 +1,18 @@ -import { refs, injectReferences } from "./index" +// import { refs, injectReferences } from "./index" -describe('Modules', () => { +// describe('Modules', () => { - it('Sets proper references', () => { - const appMock = {} - const storeMock = {} - const routerMock = {} - const configMock = {} +// it('Sets proper references', () => { +// const appMock = {} +// const storeMock = {} +// const routerMock = {} +// const configMock = {} - injectReferences(appMock, storeMock, routerMock, configMock) +// injectReferences(appMock, storeMock, routerMock, configMock) - expect(refs.app).toBe(appMock) - expect(refs.store).toBe(storeMock) - expect(refs.router).toBe(routerMock) - expect(refs.config).toBe(configMock) - }) -}) \ No newline at end of file +// expect(refs.app).toBe(appMock) +// expect(refs.store).toBe(storeMock) +// expect(refs.router).toBe(routerMock) +// expect(refs.config).toBe(configMock) +// }) +// }) \ No newline at end of file From 1e4b05e9c69d85452d3ae1e614ebd4e670a216a4 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 2 Jul 2019 14:10:37 +0200 Subject: [PATCH 0166/1227] module typings --- packages/module/index.ts | 12 +++++++----- packages/module/package.json | 13 ++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/module/index.ts b/packages/module/index.ts index 0e917bbce..1c589587a 100644 --- a/packages/module/index.ts +++ b/packages/module/index.ts @@ -1,23 +1,25 @@ +import VueRouter from 'vue-router' +import { Store } from "vuex" export interface StorefrontModule { ( app: any, - store: any, - router: any, + store: Store, + router: VueRouter, config: any, appConfig: any ) : void } // because config can't be shared as peer dependency -let refs = { app: null, store: null, router: null, config: null } +let refs: { app: any, store: Store, router: VueRouter, config: Object } -function injectReferences (app: any, store: any, router: any, config: any): any { +function injectReferences (app: any, store: Store, router: VueRouter, config: any): void { refs.app = app refs.store = store refs.router = router refs.config = config } -function registerModule (module: StorefrontModule, config: Object) { +function registerModule (module: StorefrontModule, config: any) { module(refs.app, refs.store, refs.router, config, refs.config) } diff --git a/packages/module/package.json b/packages/module/package.json index 3869cf813..649a2a801 100644 --- a/packages/module/package.json +++ b/packages/module/package.json @@ -1,21 +1,24 @@ { "name": "@vue-storefront/module", "sideEffects": "false", - "version": "0.0.1", + "version": "0.0.3", "description": "Vue Storefront modules source", "main": "index.js", "typings": "index.d.ts", - "scripts": { "build": "tsc", "clean": "rm -- *.js && rm -- *.d.ts", - "version": "npm run build", + "prepublishOnly": "npm run build", "postpublish": "npm run clean" }, - "files" : [ + "files": [ "*.js", "*.d.ts" ], "author": "Filip Rakowski (@filrak)", - "license": "MIT" + "license": "MIT", + "dependencies": { + "vue-router": "^3.0.6", + "vuex": "^3.1.1" + } } From 970bf7f0a8c86885664098b96f7273f8c8aee365 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 2 Jul 2019 14:19:01 +0200 Subject: [PATCH 0167/1227] remove demo module --- src/themes/default/index.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/themes/default/index.js b/src/themes/default/index.js index 86b013138..bf24e4169 100644 --- a/src/themes/default/index.js +++ b/src/themes/default/index.js @@ -6,9 +6,7 @@ import VueProgressBar from 'vue-progressbar' import '@vue-storefront/core/lib/passive-listeners' import { RouterManager } from '@vue-storefront/core/lib/router-manager' import { once } from '@vue-storefront/core/helpers' -import { registerModule } from '@vue-storefront/module' -// temp -import { ExampleModule } from 'packages/cli/boilerplates/module' + once('__VUE_EXTEND_DROPPOINT_VPB__', () => { Vue.use(VueProgressBar) }) @@ -19,9 +17,6 @@ function initTheme (app, router, store, config, ssrContext) { // You can do it on your own and then be able to customize the components used for example for German storeView checkout // To do so please execlude the desired storeView from the config.storeViews.mapStoreUrlsFor and map the urls by Your own like: // { name: 'de-checkout', path: '/checkout', component: CheckoutCustomized }, - registerModule(ExampleModule, { - message: 'Hello World!' - }) setupMultistoreRoutes(config, router, routes) RouterManager.addRoutes(routes, router) } From 36a24df7959c8308429875184a2a6e524c43ff2e Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 2 Jul 2019 14:20:47 +0200 Subject: [PATCH 0168/1227] remove boilerplates from packages --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index f25137c1b..b91590e12 100755 --- a/package.json +++ b/package.json @@ -184,7 +184,6 @@ "docs", "core/modules/*", "test/unit", - "packages/*", - "packages/cli/boilerplates" + "packages/*" ] } From eeef1bf3710deca2b45d0e145117de5edb9f621b Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 2 Jul 2019 14:25:21 +0200 Subject: [PATCH 0169/1227] add commands to cli --- packages/cli/bin/vsf.js | 4 +++- packages/cli/scripts/manual.js | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/cli/bin/vsf.js b/packages/cli/bin/vsf.js index d5101c167..1d2785c95 100755 --- a/packages/cli/bin/vsf.js +++ b/packages/cli/bin/vsf.js @@ -2,11 +2,13 @@ const command = process.argv[2] - switch (command) { case 'init': require('../scripts/install.js')(process.argv[3]) break; + case 'init-module': + console.log('Soon to be commited :)') + break; case '--help': require('../scripts/manual.js')() break; diff --git a/packages/cli/scripts/manual.js b/packages/cli/scripts/manual.js index 73ef380d6..b433bdba8 100644 --- a/packages/cli/scripts/manual.js +++ b/packages/cli/scripts/manual.js @@ -1,8 +1,9 @@ module.exports = function () { console.log('Usage: vsf [command] [options]\n') console.log('Options:') - console.log(' --help available commands') - console.log(' --version CLI version\n') + console.log(' --help available commands') + console.log(' --version CLI version\n') console.log('Commands:') - console.log(' init [dir] setup new VS project') -} \ No newline at end of file + console.log(' init [dir] setup new VS project') + console.log(' init-module [name] generate vs module boilerplate') +} From 5664fd837c932b6cef3561b318c206066396adf8 Mon Sep 17 00:00:00 2001 From: pkarw Date: Tue, 2 Jul 2019 21:40:53 +0200 Subject: [PATCH 0170/1227] eslint fix --- core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts index af7c96fc0..1ce9a8571 100644 --- a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts +++ b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts @@ -2,7 +2,6 @@ import Vue from 'vue' import Vuex from 'vuex' import * as types from '../../../store/mutation-types' -import { cartCacheHandlerFactory } from '../../../helpers/cartCacheHandler'; const StorageManager = { cartsCollection: { @@ -12,6 +11,8 @@ const StorageManager = { return this[key] } }; +const cartCacheHandlerFactory = require('../../../helpers/cartCacheHandler').cartCacheHandlerFactory + jest.mock('@vue-storefront/core/store/lib/storage-manager', () => ({StorageManager})) jest.mock('@vue-storefront/core/helpers', () => ({ isServer: () => false From 2d95ed3b3cb4819ea7945b10547fb7ecaa2502de Mon Sep 17 00:00:00 2001 From: pkarw Date: Tue, 2 Jul 2019 23:12:01 +0200 Subject: [PATCH 0171/1227] Fix for finding the cheapest product variant (if no specific configuration given) + removed the `state` dependency in the configureProductAsync --- .../catalog-next/store/category/actions.ts | 2 +- core/modules/catalog/helpers/index.ts | 25 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/core/modules/catalog-next/store/category/actions.ts b/core/modules/catalog-next/store/category/actions.ts index 1835dec4b..fc4f7104e 100644 --- a/core/modules/catalog-next/store/category/actions.ts +++ b/core/modules/catalog-next/store/category/actions.ts @@ -25,7 +25,7 @@ const actions: ActionTree = { const {items, perPage, start, total} = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort }) commit(types.CATEGORY_SET_SEARCH_PRODUCTS_STATS, { perPage, start, total }) let configuredProducts = items.map(product => { - const configuredProductVariant = configureProductAsync({rootState, state: {current_configuration: {}}}, {product, configuration: searchQuery.filters, selectDefaultVariant: false, fallbackToDefaultWhenNoAvailable: true, setProductErorrs: false}) + const configuredProductVariant = configureProductAsync({rootState}, {product, configuration: searchQuery.filters, selectDefaultVariant: false, fallbackToDefaultWhenNoAvailable: true, setProductErorrs: false}) return Object.assign(product, configuredProductVariant) }) commit(types.CATEGORY_SET_PRODUCTS, configuredProducts) diff --git a/core/modules/catalog/helpers/index.ts b/core/modules/catalog/helpers/index.ts index 18d27b51c..eb40c449c 100644 --- a/core/modules/catalog/helpers/index.ts +++ b/core/modules/catalog/helpers/index.ts @@ -31,6 +31,7 @@ function _filterRootProductByStockitem (context, stockItem, product, errorCallba } export function findConfigurableChildAsync ({ product, configuration = null, selectDefaultChildren = false, availabilityCheck = true }) { + let regularProductPrice = product.original_price_incl_tax ? product.original_price_incl_tax : product.price_incl_tax let selectedVariant = product.configurable_children.find((configurableChild) => { if (availabilityCheck) { if (configurableChild.stock && !config.products.listOutOfStockProducts) { @@ -48,13 +49,19 @@ export function findConfigurableChildAsync ({ product, configuration = null, sel if (configuration.sku) { return configurableChild.sku === configuration.sku // by sku or first one } else { - return Object.keys(omit(configuration, ['price'])).every((configProperty) => { - let configurationPropertyFilters = configuration[configProperty] || [] - if (!Array.isArray(configurationPropertyFilters)) configurationPropertyFilters = [configurationPropertyFilters] - const configurationIds = configurationPropertyFilters.map(filter => toString(filter.id)).filter(filterId => !!filterId) - if (!configurationIds.length) return true // skip empty - return configurationIds.includes(toString(configurableChild[configProperty])) - }) + if (!configuration || Object.keys(configuration).length === 0) { // no configuration - return the first child cheaper than the original price - if found + if (configurableChild.price_incl_tax <= regularProductPrice) { + return true + } + } else { + return Object.keys(omit(configuration, ['price'])).every((configProperty) => { + let configurationPropertyFilters = configuration[configProperty] || [] + if (!Array.isArray(configurationPropertyFilters)) configurationPropertyFilters = [configurationPropertyFilters] + const configurationIds = configurationPropertyFilters.map(filter => toString(filter.id)).filter(filterId => !!filterId) + if (!configurationIds.length) return true // skip empty + return configurationIds.includes(toString(configurableChild[configProperty])) + }) + } } }) return selectedVariant @@ -504,7 +511,7 @@ export function configureProductAsync (context, { product, configuration, select } if (selectedVariant) { - if (!desiredProductFound) { // update the configuration + if (!desiredProductFound && selectDefaultVariant /** don't change the state when no selectDefaultVariant is set */) { // update the configuration populateProductConfigurationAsync(context, { product: product, selectedVariant: selectedVariant }) configuration = context.state.current_configuration } @@ -526,7 +533,7 @@ export function configureProductAsync (context, { product, configuration, select const fieldsToOmit = ['name'] if (selectedVariant.image === '') fieldsToOmit.push('image') selectedVariant = omit(selectedVariant, fieldsToOmit) // We need to send the parent SKU to the Magento cart sync but use the child SKU internally in this case - // use chosen variant + // use chosen variant for the current product if (selectDefaultVariant) { context.dispatch('setCurrent', selectedVariant) } From dd15b73d06d1ccbd023371e309776d400847ea71 Mon Sep 17 00:00:00 2001 From: pkarw Date: Tue, 2 Jul 2019 23:21:40 +0200 Subject: [PATCH 0172/1227] FIx for configuring the products in the Search bar by default --- core/modules/catalog/components/Search.ts | 2 +- core/modules/catalog/helpers/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/modules/catalog/components/Search.ts b/core/modules/catalog/components/Search.ts index c4c010582..a4fa3db75 100644 --- a/core/modules/catalog/components/Search.ts +++ b/core/modules/catalog/components/Search.ts @@ -47,7 +47,7 @@ export const Search = { let startValue = 0; this.start = startValue this.readMore = true - this.$store.dispatch('product/list', { query, start: this.start, size: this.size, updateState: false }).then(resp => { + this.$store.dispatch('product/list', { query, start: this.start, configuration: {}, size: this.size, updateState: false }).then(resp => { this.products = resp.items this.start = startValue + this.size this.emptyResults = resp.items.length < 1 diff --git a/core/modules/catalog/helpers/index.ts b/core/modules/catalog/helpers/index.ts index eb40c449c..01783a569 100644 --- a/core/modules/catalog/helpers/index.ts +++ b/core/modules/catalog/helpers/index.ts @@ -49,7 +49,7 @@ export function findConfigurableChildAsync ({ product, configuration = null, sel if (configuration.sku) { return configurableChild.sku === configuration.sku // by sku or first one } else { - if (!configuration || Object.keys(configuration).length === 0) { // no configuration - return the first child cheaper than the original price - if found + if (!configuration || (configuration && Object.keys(configuration).length === 0)) { // no configuration - return the first child cheaper than the original price - if found if (configurableChild.price_incl_tax <= regularProductPrice) { return true } From 9ddc043ade39cb3b8ba10fe9eb1ff23140fde757 Mon Sep 17 00:00:00 2001 From: pkarw Date: Tue, 2 Jul 2019 23:39:47 +0200 Subject: [PATCH 0173/1227] Final price fields added to systemFields --- config/default.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/default.json b/config/default.json index 70d385be6..07e2c6e6e 100644 --- a/config/default.json +++ b/config/default.json @@ -180,6 +180,8 @@ "size_options", "regular_price", "final_price", + "final_price_incl_tax", + "final_price_tax", "price", "color_options", "id", From ae793cbaaa8c992b517e7264f3737afcbb4b625f Mon Sep 17 00:00:00 2001 From: pkarw Date: Wed, 3 Jul 2019 00:05:26 +0200 Subject: [PATCH 0174/1227] Two missing conditions reverted --- core/modules/catalog/helpers/tax.ts | 127 ++++++++++++++++------------ 1 file changed, 74 insertions(+), 53 deletions(-) diff --git a/core/modules/catalog/helpers/tax.ts b/core/modules/catalog/helpers/tax.ts index 268462b19..b7ffaa554 100644 --- a/core/modules/catalog/helpers/tax.ts +++ b/core/modules/catalog/helpers/tax.ts @@ -20,10 +20,17 @@ function isSpecialPriceActive (fromDate, toDate) { } } -export function updateProductPrices (product, rate, sourcePriceInclTax = false) { +export function updateProductPrices (product, rate, sourcePriceInclTax = false, deprecatedPriceFieldsSupport = false, finalPriceInclTax = true) { const rate_factor = parseFloat(rate.rate) / 100 - product.final_price_incl_tax = parseFloat(product.final_price) // final price does include tax - product.final_price = product.final_price_incl_tax / (1 + rate_factor) + if (finalPriceInclTax) { + product.final_price_incl_tax = parseFloat(product.final_price) // final price does include tax + product.final_price = product.final_price_incl_tax / (1 + rate_factor) + product.final_price_tax = product.final_price_incl_tax - product.final_price + } else { + product.final_price = parseFloat(product.final_price) // final price does include tax + product.final_price_tax = product.final_price * rate_factor + product.final_price_incl_tax = product.final_price + product.final_price_tax + } product.price = parseFloat(product.price) product.special_price = parseFloat(product.special_price) @@ -58,12 +65,14 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) product.special_price_tax = special_price_excl_tax * rate_factor product.special_price_incl_tax = special_price_excl_tax + product.special_price_tax - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - product.priceTax = product.price_tax - product.priceInclTax = product.price_incl_tax - product.specialPriceTax = product.special_price_tax - product.specialPriceInclTax = product.special_price_incl_tax - /** END */ + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceTax = product.price_tax + product.priceInclTax = product.price_incl_tax + product.specialPriceTax = product.special_price_tax + product.specialPriceInclTax = product.special_price_incl_tax + /** END */ + } if (product.special_price && (product.special_price < product.price)) { if (!isSpecialPriceActive(product.special_from_date, product.special_to_date)) { @@ -77,13 +86,15 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) product.price_incl_tax = product.special_price_incl_tax product.price_tax = product.special_price_tax - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - product.priceInclTax = product.price_incl_tax - product.priceTax = product.price_tax - product.originalPrice = product.original_price - product.originalPriceInclTax = product.original_price_incl_tax - product.originalPriceTax = product.original_price_tax - /** END */ + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceInclTax = product.price_incl_tax + product.priceTax = product.price_tax + product.originalPrice = product.original_price + product.originalPriceInclTax = product.original_price_incl_tax + product.originalPriceTax = product.original_price_tax + /** END */ + } } } else { product.special_price = 0 // the same price as original; it's not a promotion @@ -133,12 +144,14 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) configurableChild.special_price_tax = special_price_excl_tax * rate_factor configurableChild.special_price_incl_tax = special_price_excl_tax + configurableChild.special_price_tax - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - configurableChild.priceTax = configurableChild.price_tax - configurableChild.priceInclTax = configurableChild.price_incl_tax - configurableChild.specialPriceTax = configurableChild.special_price_tax - configurableChild.specialPriceInclTax = configurableChild.special_price_incl_tax - /** END */ + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + configurableChild.priceTax = configurableChild.price_tax + configurableChild.priceInclTax = configurableChild.price_incl_tax + configurableChild.specialPriceTax = configurableChild.special_price_tax + configurableChild.specialPriceInclTax = configurableChild.special_price_incl_tax + /** END */ + } if (configurableChild.special_price && (configurableChild.special_price < configurableChild.price)) { if (!isSpecialPriceActive(configurableChild.special_from_date, configurableChild.special_to_date)) { @@ -152,19 +165,21 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) configurableChild.price_incl_tax = configurableChild.special_price_incl_tax configurableChild.price_tax = configurableChild.special_price_tax - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - configurableChild.originalPrice = configurableChild.original_price - configurableChild.originalPriceInclTax = configurableChild.original_price_incl_tax - configurableChild.originalPriceTax = configurableChild.original_price_tax - configurableChild.priceInclTax = configurableChild.price_incl_tax - configurableChild.priceTax = configurableChild.price_tax - /** END */ + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + configurableChild.originalPrice = configurableChild.original_price + configurableChild.originalPriceInclTax = configurableChild.original_price_incl_tax + configurableChild.originalPriceTax = configurableChild.original_price_tax + configurableChild.priceInclTax = configurableChild.price_incl_tax + configurableChild.priceTax = configurableChild.price_tax + /** END */ + } } } else { configurableChild.special_price = 0 } - if (configurableChild.price_incl_tax < product.price_incl_tax || product.price === 0) { // always show the lowest price + if ((configurableChild.price_incl_tax <= product.price_incl_tax) || product.price === 0) { // always show the lowest price product.price_incl_tax = configurableChild.price_incl_tax product.price_tax = configurableChild.price_tax product.price = configurableChild.price @@ -175,28 +190,30 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) product.original_price_incl_tax = configurableChild.original_price_incl_tax product.original_price_tax = configurableChild.original_price_tax - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - product.priceInclTax = product.price_incl_tax - product.priceTax = product.price_tax - product.specialPriceInclTax = product.special_price_incl_tax - product.specialPriceTax = product.special_price_tax - product.originalPrice = product.original_price - product.originalPriceInclTax = product.original_price_incl_tax - product.originalPriceTax = product.original_price_tax - /** END */ + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceInclTax = product.price_incl_tax + product.priceTax = product.price_tax + product.specialPriceInclTax = product.special_price_incl_tax + product.specialPriceTax = product.special_price_tax + product.originalPrice = product.original_price + product.originalPriceInclTax = product.original_price_incl_tax + product.originalPriceTax = product.original_price_tax + /** END */ + } } } } } -export function calculateProductTax (product, taxClasses, taxCountry = 'PL', taxRegion = '', sourcePriceInclTax = false) { +export function calculateProductTax (product, taxClasses, taxCountry = 'PL', taxRegion = '', sourcePriceInclTax = false, deprecatedPriceFieldsSupport = false, finalPriceInclTax = true) { let rateFound = false if (product.tax_class_id > 0) { let taxClass = taxClasses.find((el) => el.product_tax_class_ids.indexOf(parseInt(product.tax_class_id) >= 0)) if (taxClass) { for (let rate of taxClass.rates) { // TODO: add check for zip code ranges (!) if (rate.tax_country_id === taxCountry && (rate.region_name === taxRegion || rate.tax_region_id === 0 || !rate.region_name)) { - updateProductPrices(product, rate, sourcePriceInclTax) + updateProductPrices(product, rate, sourcePriceInclTax, deprecatedPriceFieldsSupport) rateFound = true break } @@ -211,12 +228,14 @@ export function calculateProductTax (product, taxClasses, taxCountry = 'PL', tax product.special_price_incl_tax = 0 product.special_price_tax = 0 - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - product.priceInclTax = product.price - product.priceTax = 0 - product.specialPriceInclTax = 0 - product.specialPriceTax = 0 - /** END */ + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + product.priceInclTax = product.price + product.priceTax = 0 + product.specialPriceInclTax = 0 + product.specialPriceTax = 0 + /** END */ + } if (product.configurable_children) { for (let configurableChildren of product.configurable_children) { @@ -225,12 +244,14 @@ export function calculateProductTax (product, taxClasses, taxCountry = 'PL', tax configurableChildren.special_price_incl_tax = 0 configurableChildren.special_price_tax = 0 - /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ - configurableChildren.priceInclTax = configurableChildren.price - configurableChildren.priceTax = 0 - configurableChildren.specialPriceInclTax = 0 - configurableChildren.specialPriceTax = 0 - /** END */ + if (deprecatedPriceFieldsSupport) { + /** BEGIN @deprecated - inconsitent naming kept just for the backward compatibility */ + configurableChildren.priceInclTax = configurableChildren.price + configurableChildren.priceTax = 0 + configurableChildren.specialPriceInclTax = 0 + configurableChildren.specialPriceTax = 0 + /** END */ + } } } } From 37a06bf57c7aee2f4076e37dcb2e18de2768f0af Mon Sep 17 00:00:00 2001 From: Dmitry Schegolikhin Date: Wed, 3 Jul 2019 09:59:49 +0400 Subject: [PATCH 0175/1227] [3053] Updated changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eae741758..1255901c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed product link in wishlist and microcart - @michasik (#2987) - Resolve problem with getting CMS block from cache - @qiqqq (#2499) - Make image proxy url work with relative base url - @cewald (#3158) +- Fixed memory leak with enabled dynamicConfigReload - @dimasch (#3075) ### Changed / Improved - Shipping address is saved as default when not logged in user chooses to create account during checkout - @iwonapiotrowska (#2636) From 3dfda6c26ea8cb359b3869df7c4501ab2efcf87b Mon Sep 17 00:00:00 2001 From: Dmitry Chertkov Date: Wed, 3 Jul 2019 14:28:43 +0300 Subject: [PATCH 0176/1227] add stock object in cart item after stock check --- core/modules/catalog/store/stock/actions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/modules/catalog/store/stock/actions.ts b/core/modules/catalog/store/stock/actions.ts index 8fbceccae..985f092d2 100644 --- a/core/modules/catalog/store/stock/actions.ts +++ b/core/modules/catalog/store/stock/actions.ts @@ -75,10 +75,10 @@ const actions: ActionTree = { Logger.log('Removing product from cart' + event.product_sku, 'stock')() rootStore.commit('cart/' + types.CART_DEL_ITEM, { product: { sku: event.product_sku } }, {root: true}) } else { - rootStore.dispatch('cart/updateItem', { product: { errors: { stock: i18n.t('Out of the stock!') }, sku: event.product_sku, is_in_stock: false } }) + rootStore.dispatch('cart/updateItem', { product: { errors: { stock: i18n.t('Out of the stock!') }, sku: event.product_sku, is_in_stock: false, stock: event.result } }) } } else { - rootStore.dispatch('cart/updateItem', { product: { info: { stock: i18n.t('In stock!') }, sku: event.product_sku, is_in_stock: true } }) + rootStore.dispatch('cart/updateItem', { product: { info: { stock: i18n.t('In stock!') }, sku: event.product_sku, is_in_stock: true, stock: event.result } }) } Vue.prototype.$bus.$emit('cart-after-itemchanged', { item: cartItem }) } From 2cbfc1214a0e661775250eec9cca04d076247755 Mon Sep 17 00:00:00 2001 From: Dmitry Chertkov Date: Wed, 3 Jul 2019 14:45:57 +0300 Subject: [PATCH 0177/1227] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1255901c0..90b485fa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed / Improved - Shipping address is saved as default when not logged in user chooses to create account during checkout - @iwonapiotrowska (#2636) - Can set transition style for Modal content - @grimasod (#3146) +- Added stock to cart items - @cheeerd (#3166) ## [1.10.0-rc.2] - UNRELEASED From 3d1d81c0e1aebfcdeda97ea7fec58b6d3ab8ef29 Mon Sep 17 00:00:00 2001 From: pkarw Date: Wed, 3 Jul 2019 14:22:51 +0200 Subject: [PATCH 0178/1227] priceInclTax -> price_incl_tax --- src/modules/google-tag-manager/hooks/afterRegistration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/google-tag-manager/hooks/afterRegistration.ts b/src/modules/google-tag-manager/hooks/afterRegistration.ts index b1c9eda6f..ce3faf894 100644 --- a/src/modules/google-tag-manager/hooks/afterRegistration.ts +++ b/src/modules/google-tag-manager/hooks/afterRegistration.ts @@ -6,7 +6,7 @@ export function afterRegistration (Vue, config, store, isServer) { const currencyCode = storeView.i18n.currencyCode const getProduct = (item) => { - const { name, id, sku, priceInclTax: price, category, qty: quantity } = item + const { name, id, sku, price_incl_tax: price, category, qty: quantity } = item let product = { name, id, From 7035fc445c7e25c6a4c399db94b1439199f58e8d Mon Sep 17 00:00:00 2001 From: pkarw Date: Wed, 3 Jul 2019 15:06:58 +0200 Subject: [PATCH 0179/1227] Changelog + docs updated --- CHANGELOG.md | 1 + docs/guide/data/static-data.md | 14 +------------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4205e25e..eff9bd6af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed wrong meta description attribute by page overwrite - @przspa (#3091) +- The SSR Cms console errors fixed + `magento-2-cms` module removed - @pkarw (#3155) ## [1.10.0-rc.1] - 2019.06.19 diff --git a/docs/guide/data/static-data.md b/docs/guide/data/static-data.md index 73987fa57..b14aa9a3f 100644 --- a/docs/guide/data/static-data.md +++ b/docs/guide/data/static-data.md @@ -2,19 +2,7 @@ In Vue Storefront, we can use CMS Static Blocks and CMS Static Pages from Magento 2. -## Old solution - -Until version 1.6, the `magento2-cms-extention` (we can find it in: `src/modules/magento-2-cms/`). It's deprecated. - -### How it works? - -To display CMS data, we need a `SnowdogApps/magento2-cms-api` module installed in the Magento 2 instance. The extension fetches data using the API and displays compiled content on the storefront. You can display blocks and pages by ID or identifiers—it supports different store IDs in a multi-languages store. Find more details [here](https://github.com/DivanteLtd/vue-storefront/tree/master/src/modules/magento-2-cms) - -This solution will be deprecated soon. - -## New solution - -From version 1.6, thanks to @yuriboyko,we have a better solution for static data—it's added to the Elasticsearch database and is using qraphQL query, displayed on the storefront. +From version 1.6, thanks to @yuriboyko we have a better solution for static data—it's added to the Elasticsearch database and is using qraphQL query, displayed on the storefront. ### How it works? From 7d57584f72bc5b439a8a72b12087cb2d5f2e50b2 Mon Sep 17 00:00:00 2001 From: pkarw Date: Wed, 3 Jul 2019 15:09:58 +0200 Subject: [PATCH 0180/1227] Router update --- src/themes/default/router/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/themes/default/router/index.js b/src/themes/default/router/index.js index f7a5f260c..619c78588 100644 --- a/src/themes/default/router/index.js +++ b/src/themes/default/router/index.js @@ -4,7 +4,6 @@ const ErrorPage = () => import(/* webpackChunkName: "vsf-error" */ 'theme/pages/ const Product = () => import(/* webpackChunkName: "vsf-product" */ 'theme/pages/Product.vue') const Category = () => import(/* webpackChunkName: "vsf-category" */ 'theme/pages/Category.vue') const CmsPage = () => import(/* webpackChunkName: "vsf-cms" */ 'theme/pages/CmsPage.vue') -const CmsBlockDemoPageSsr = () => import(/* webpackChunkName: "vsf-cms-demo" */ 'theme/pages/CmsBlockDemoPageSsr.vue') const Checkout = () => import(/* webpackChunkName: "vsf-checkout" */ 'theme/pages/Checkout.vue') const Compare = () => import(/* webpackChunkName: "vsf-compare" */ 'theme/pages/Compare.vue') const MyAccount = () => import(/* webpackChunkName: "vsf-my-account" */ 'theme/pages/MyAccount.vue') @@ -36,7 +35,6 @@ let routes = [ { name: 'compare', path: '/compare', component: Compare, props: {title: 'Compare Products'} }, { name: 'page-not-found', path: '/page-not-found', component: PageNotFound }, { name: 'error', path: '/error', component: ErrorPage, meta: { layout: 'minimal' } }, - { name: 'cms-block-demo-page-ssr', path: '/cms-block-demo-page-ssr', component: CmsBlockDemoPageSsr }, { name: 'virtual-product', path: '/p/:parentSku/:slug', component: Product }, // :sku param can be marked as optional with ":sku?" (https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js#L16), but it requires a lot of work to adjust the rest of the site { name: 'bundle-product', path: '/p/:parentSku/:slug', component: Product }, // :sku param can be marked as optional with ":sku?" (https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js#L16), but it requires a lot of work to adjust the rest of the site { name: 'simple-product', path: '/p/:parentSku/:slug', component: Product }, // :sku param can be marked as optional with ":sku?" (https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js#L16), but it requires a lot of work to adjust the rest of the site From b71f5647438634185e543a39e15b086437587d0a Mon Sep 17 00:00:00 2001 From: Luke Romanowicz Date: Wed, 3 Jul 2019 15:47:29 +0200 Subject: [PATCH 0181/1227] fix inheritance through extend --- core/lib/multistore.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index ecb705ad4..60efa4400 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -51,14 +51,14 @@ function getExtendedStoreviewConfig (storeView: StoreView): StoreView { if (storeView.extend) { const originalParent = storeView.extend - if (!config.storeViews[storeView.storeCode]) { + if (!config.storeViews[originalParent]) { Logger.error(`Storeview "${storeView.extend}" doesn't exist!`)() } else { delete storeView.extend storeView = merge( {}, - getExtendedStoreviewConfig(config.storeViews[storeView.storeCode]), + getExtendedStoreviewConfig(config.storeViews[originalParent]), storeView ) storeView.extend = originalParent @@ -85,9 +85,8 @@ export function prepareStoreView (storeCode: string): StoreView { if (storeCode) { // current store code if ((config.storeViews[storeCode])) { - storeView = merge(storeView, config.storeViews[storeCode]) rootStore.state.user.current_storecode = storeCode - storeView = getExtendedStoreviewConfig(storeView) + storeView = merge(storeView, getExtendedStoreviewConfig(config.storeViews[storeCode])) } } else { storeView.storeCode = config.defaultStoreCode || '' From b201e7343f30b2e3a780e09658f6dcf64cdbda08 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Thu, 4 Jul 2019 12:43:53 +0200 Subject: [PATCH 0182/1227] cli-generator for module boilerplates --- packages/cli/.gitignore | 2 +- packages/cli/README.md | 7 +- packages/cli/bin/vsf.js | 6 +- packages/cli/boilerplates/module/.gitignore | 4 +- packages/cli/boilerplates/module/README.md | 17 + packages/cli/boilerplates/module/package.json | 15 +- .../boilerplates/module/{ => src}/index.ts | 2 + .../boilerplates/module/{ => src}/store.ts | 0 .../cli/boilerplates/module/tsconfig.json | 10 +- .../cli/boilerplates/module/webpack.config.js | 11 + packages/cli/package.json | 6 +- packages/cli/scripts/generateModule.js | 24 ++ packages/cli/scripts/install.js | 6 +- yarn.lock | 293 +++++++++++++++--- 14 files changed, 342 insertions(+), 61 deletions(-) create mode 100644 packages/cli/boilerplates/module/README.md rename packages/cli/boilerplates/module/{ => src}/index.ts (83%) rename packages/cli/boilerplates/module/{ => src}/store.ts (100%) create mode 100644 packages/cli/boilerplates/module/webpack.config.js create mode 100644 packages/cli/scripts/generateModule.js diff --git a/packages/cli/.gitignore b/packages/cli/.gitignore index 3c3629e64..c2658d7d1 100644 --- a/packages/cli/.gitignore +++ b/packages/cli/.gitignore @@ -1 +1 @@ -node_modules +node_modules/ diff --git a/packages/cli/README.md b/packages/cli/README.md index ec188d39a..aa5043fee 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -10,6 +10,7 @@ npm i -g @vue-storefront/cli ## Commands After installing CLI you'll get access to following commands: -- `vsf init [dirname] - Use it to set up new VS project. The CLI will ask you a few questions and set up new, ready to work with Vue Storefront instance. -- `vsf --help' - available commands -- 'vsf -version - current version of cli +- `vsf init [dirname]` - Use it to set up new VS project. The CLI will ask you a few questions and set up new, ready to work with Vue Storefront instance. +- `vsf generate-module [module-name]` - generates boilerplate for Vue Storefront module named `vsf-module-name` in a current directory +- `vsf --help` - available commands +- `vsf -version` - current version of cli diff --git a/packages/cli/bin/vsf.js b/packages/cli/bin/vsf.js index 1d2785c95..a56209027 100755 --- a/packages/cli/bin/vsf.js +++ b/packages/cli/bin/vsf.js @@ -6,8 +6,8 @@ switch (command) { case 'init': require('../scripts/install.js')(process.argv[3]) break; - case 'init-module': - console.log('Soon to be commited :)') + case 'generate-module': + require('../scripts/generateModule.js')(process.argv[3]) break; case '--help': require('../scripts/manual.js')() @@ -18,4 +18,4 @@ switch (command) { default: console.log('Unknown command. try one of those:\n') require('../scripts/manual.js')() -} \ No newline at end of file +} diff --git a/packages/cli/boilerplates/module/.gitignore b/packages/cli/boilerplates/module/.gitignore index 9a18fd13b..04c01ba7b 100644 --- a/packages/cli/boilerplates/module/.gitignore +++ b/packages/cli/boilerplates/module/.gitignore @@ -1,2 +1,2 @@ -*.js -*.d.ts \ No newline at end of file +node_modules/ +dist/ \ No newline at end of file diff --git a/packages/cli/boilerplates/module/README.md b/packages/cli/boilerplates/module/README.md new file mode 100644 index 000000000..af1a16065 --- /dev/null +++ b/packages/cli/boilerplates/module/README.md @@ -0,0 +1,17 @@ +# vsf-package + + +## Installation + +``` +yarn add vsf-package +``` + +## API + + + +## Development + +- `yarn build` - bundles package into main.js file with typescript/es6 transpilations +- `npm publish` - publishes package to NPM registry (automatically runs `yarn build` before publishing) \ No newline at end of file diff --git a/packages/cli/boilerplates/module/package.json b/packages/cli/boilerplates/module/package.json index 09010c680..528a6fec1 100644 --- a/packages/cli/boilerplates/module/package.json +++ b/packages/cli/boilerplates/module/package.json @@ -2,15 +2,22 @@ "name": "vsf-package", "version": "1.0.0", "description": "", - "main": "index.js", - "types": "index.d.ts", + "main": "dist/main.js", "scripts": { - "build": "tsc" + "build": "webpack", + "prePublishOnly": "yarn build" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { - "@vue-storefront/module": "^0.0.1" + "@vue-storefront/module": "^0.0.3", + "vuex": "^3.1.1" + }, + "devDependencies": { + "ts-loader": "^6.0.4", + "typescript": "^3.5.2", + "webpack": "^4.35.2", + "webpack-cli": "^3.3.5" } } diff --git a/packages/cli/boilerplates/module/index.ts b/packages/cli/boilerplates/module/src/index.ts similarity index 83% rename from packages/cli/boilerplates/module/index.ts rename to packages/cli/boilerplates/module/src/index.ts index 499a0c446..be4c8bae4 100644 --- a/packages/cli/boilerplates/module/index.ts +++ b/packages/cli/boilerplates/module/src/index.ts @@ -6,6 +6,8 @@ import { ExampleStore } from './store' export const ExampleModule: StorefrontModule = function (app, store, router, config, appConfig) { // You can access config passed to registerModule via config variable console.info('From module config: ', config.message) + // This is how you register new Vuex modules store.registerModule('example', ExampleStore) + // This is how you can hook into various palces of the application afterAppInitHook(() => console.log('Do something when application is initialized!')) } diff --git a/packages/cli/boilerplates/module/store.ts b/packages/cli/boilerplates/module/src/store.ts similarity index 100% rename from packages/cli/boilerplates/module/store.ts rename to packages/cli/boilerplates/module/src/store.ts diff --git a/packages/cli/boilerplates/module/tsconfig.json b/packages/cli/boilerplates/module/tsconfig.json index 0c73c87de..bcf0447cd 100644 --- a/packages/cli/boilerplates/module/tsconfig.json +++ b/packages/cli/boilerplates/module/tsconfig.json @@ -2,16 +2,14 @@ "compilerOptions": { "target": "es5", "module": "commonjs", - "declaration": true, - "outDir": "./", - "strict": true, + "outDir": "./dist", + "strict": false, "moduleResolution": "node" }, "include": [ - "*.ts" + "**/*.ts" ], "exclude": [ - "node_modules", - "**/*.spec.ts" + "node_modules" ] } \ No newline at end of file diff --git a/packages/cli/boilerplates/module/webpack.config.js b/packages/cli/boilerplates/module/webpack.config.js new file mode 100644 index 000000000..2f26fa8c4 --- /dev/null +++ b/packages/cli/boilerplates/module/webpack.config.js @@ -0,0 +1,11 @@ +module.exports = { + entry: './src/index.ts', + resolve: { + extensions: ['.ts', '.js', '.json'] + }, + module: { + rules: [ + { test: /\.ts$/, use: ['ts-loader'], exclude: /node_modules/ } + ] + } +} diff --git a/packages/cli/package.json b/packages/cli/package.json index 5ea868a4b..aa7ba669d 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@vue-storefront/cli", - "version": "0.0.8", + "version": "0.0.10", "description": "", "main": "index.js", "scripts": { @@ -17,7 +17,9 @@ "license": "MIT", "dependencies": { "execa": "^1.0.0", + "fs-extra": "^8.1.0", "inquirer": "^6.3.1", - "listr": "^0.14.3" + "listr": "^0.14.3", + "replace-in-file": "^4.1.1" } } diff --git a/packages/cli/scripts/generateModule.js b/packages/cli/scripts/generateModule.js new file mode 100644 index 000000000..d78b210a2 --- /dev/null +++ b/packages/cli/scripts/generateModule.js @@ -0,0 +1,24 @@ +const fse = require('fs-extra') +const path = require('path') +const replace = require('replace-in-file') +const cwd = process.cwd() +const bilerplatePath = path.resolve(__dirname, '../boilerplates/module') + +module.exports = function (moduleName) { + const modulePath = cwd + '/vsf-' + moduleName + const replacementOptions = { + files: [modulePath + '/**/*.*'], + from: 'vsf-package', + to: 'vsf-' + moduleName + } + + fse.copy(bilerplatePath, modulePath, (err) => { + if (err) { + console.error(err) + } else { + replace(replacementOptions) + .catch(error => console.error('Error occurred:', error)) + console.log('Module vsf-' + moduleName + ' has been succesfully created!\n cd vsf-' + moduleName) + } + }) +} diff --git a/packages/cli/scripts/install.js b/packages/cli/scripts/install.js index 1cd736c31..407bcccb2 100644 --- a/packages/cli/scripts/install.js +++ b/packages/cli/scripts/install.js @@ -19,11 +19,11 @@ module.exports = function (installationDir) { manual: 'Manual installation' } } - + const tasks = { installDeps: { title: 'Installing dependencies', - task: () => execa.shell('cd '+ installationDir + ' && yarn') + task: () => execa.shell('cd ' + installationDir + ' && yarn') }, cloneMaster: { title: 'Copying Vue Storefront files', @@ -38,7 +38,7 @@ module.exports = function (installationDir) { task: () => spawn.execFileSync('yarn', ['installer'], {stdio: 'inherit', cwd: installationDir}) } } - + if (fs.existsSync(installationDir)) { console.error('Vue Storefront is already installed in directory ./' + installationDir + '. Aborting.') } else { diff --git a/yarn.lock b/yarn.lock index 673fb9ad1..f9294dde5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2299,6 +2299,11 @@ lodash.unescape "4.0.1" semver "5.5.0" +"@vue-storefront/module@^0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@vue-storefront/module/-/module-0.0.1.tgz#9b0afb84771116a70c3b97d1cfbca3a7e8aae090" + integrity sha512-9zYEbUFNqh967MN+xDZVIitBItgxWbxd5mm3Xs0kQQk5kjmoiVlU1BM7iYMhMY8lff9kZjPBJtUggL1g0PzZVw== + "@vue/babel-preset-app@3.0.0-beta.11": version "3.0.0-beta.11" resolved "https://registry.yarnpkg.com/@vue/babel-preset-app/-/babel-preset-app-3.0.0-beta.11.tgz#c8b889aa73464050f9cd3f9dc621951d85c24508" @@ -3796,6 +3801,13 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" +braces@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -4305,6 +4317,15 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + clone-deep@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" @@ -4785,6 +4806,16 @@ cross-env@^3.1.4: cross-spawn "^5.1.0" is-windows "^1.0.0" +cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + cross-spawn@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" @@ -4800,16 +4831,6 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -5490,7 +5511,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: +enhanced-resolve@4.1.0, enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" dependencies: @@ -6231,6 +6252,13 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + finalhandler@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" @@ -6293,6 +6321,16 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +findup-sync@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" + integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + findup-sync@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" @@ -6439,6 +6477,15 @@ fs-extra@^7.0.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" @@ -6509,6 +6556,11 @@ get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-installed-path@^2.0.3: version "2.1.1" resolved "https://registry.yarnpkg.com/get-installed-path/-/get-installed-path-2.1.1.tgz#a1f33dc6b8af542c9331084e8edbe37fe2634152" @@ -6681,6 +6733,13 @@ global-modules@1.0.0, global-modules@^1.0.0: is-windows "^1.0.1" resolve-dir "^1.0.0" +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + global-prefix@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" @@ -6691,6 +6750,15 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + global@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" @@ -6773,6 +6841,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" +graceful-fs@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== + graphql-tag@^2.9.2: version "2.10.1" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.1.tgz#10aa41f1cd8fae5373eaf11f1f67260a3cad5e02" @@ -7149,6 +7222,13 @@ import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" +import-local@2.0.0, import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + import-local@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" @@ -7156,13 +7236,6 @@ import-local@^1.0.0: pkg-dir "^2.0.0" resolve-cwd "^2.0.0" -import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -7204,7 +7277,7 @@ inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" -ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: +ini@^1.3.2, ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" @@ -7258,7 +7331,7 @@ inquirer@^6.2.0, inquirer@^6.2.2, inquirer@^6.3.1: strip-ansi "^5.1.0" through "^2.3.6" -interpret@^1.0.0, interpret@^1.1.0: +interpret@1.2.0, interpret@^1.0.0, interpret@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" @@ -7478,6 +7551,11 @@ is-number@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + is-obj@^1.0.0, is-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" @@ -8629,6 +8707,14 @@ loader-runner@^2.3.0: version "2.4.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" +loader-utils@1.2.3, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + loader-utils@^0.2.16: version "0.2.17" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" @@ -8638,14 +8724,6 @@ loader-utils@^0.2.16: json5 "^0.5.0" object-assign "^4.0.1" -loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" - dependencies: - big.js "^5.2.2" - emojis-list "^2.0.0" - json5 "^1.0.1" - localforage@^1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.7.3.tgz#0082b3ca9734679e1bd534995bdd3b24cf10f204" @@ -9089,6 +9167,14 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: snapdragon "^0.8.1" to-regex "^3.0.2" +micromatch@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -9835,7 +9921,7 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -os-locale@^3.0.0: +os-locale@^3.0.0, os-locale@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" dependencies: @@ -10179,6 +10265,11 @@ phantomjs-prebuilt@^2.1.10: request-progress "^2.0.1" which "^1.2.10" +picomatch@^2.0.5: + version "2.0.7" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" + integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== + pidusage@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-1.2.0.tgz#65ee96ace4e08a4cd3f9240996c85b367171ee92" @@ -11277,6 +11368,15 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" +replace-in-file@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/replace-in-file/-/replace-in-file-4.1.1.tgz#f9d5f4665e708cc15a23c900e7596c3792e08a93" + integrity sha512-0Va403DpFFRpm6oIsEf2U9fH9mVuDgRmSbXwrzpC3tmGduah9FhJJmu424rlogJo+0t7ho9f1HOpR+0qcXtzWQ== + dependencies: + chalk "^2.4.2" + glob "^7.1.3" + yargs "^13.2.2" + request-progress@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-0.4.0.tgz#c1954e39086aa85269c5660bcee0142a6a70d7e7" @@ -12060,7 +12160,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^3.0.0: +string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" dependencies: @@ -12100,7 +12200,7 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.0.0, strip-ansi@^5.1.0: +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" dependencies: @@ -12178,6 +12278,12 @@ supports-color@5.5.0, supports-color@^5.3.0, supports-color@^5.4.0, supports-col dependencies: has-flag "^3.0.0" +supports-color@6.1.0, supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + dependencies: + has-flag "^3.0.0" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -12188,12 +12294,6 @@ supports-color@^3.2.3: dependencies: has-flag "^1.0.0" -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - dependencies: - has-flag "^3.0.0" - svgo@^0.7.0: version "0.7.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" @@ -12464,6 +12564,13 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" @@ -12573,6 +12680,17 @@ ts-loader@^5.3.0: micromatch "^3.1.4" semver "^5.0.1" +ts-loader@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.0.4.tgz#bc331ad91a887a60632d94c9f79448666f2c4b63" + integrity sha512-p2zJYe7OtwR+49kv4gs7v4dMrfYD1IPpOtqiSPCbe8oR+4zEBtdHwzM7A7M91F+suReqgzZrlClk4LRSSp882g== + dependencies: + chalk "^2.3.0" + enhanced-resolve "^4.0.0" + loader-utils "^1.0.2" + micromatch "^4.0.0" + semver "^6.0.0" + ts-node@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" @@ -12644,6 +12762,11 @@ typescript@^3.1.6: version "3.4.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" +typescript@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.2.tgz#a09e1dc69bc9551cadf17dba10ee42cf55e5d56c" + integrity sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA== + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" @@ -12868,6 +12991,11 @@ uuid@^3.0.1, uuid@^3.1.0, uuid@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" +v8-compile-cache@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" + integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== + v8-compile-cache@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4" @@ -13024,6 +13152,11 @@ vue-router@^3.0.1: version "3.0.6" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.6.tgz#2e4f0f9cbb0b96d0205ab2690cfe588935136ac3" +vue-router@^3.0.6: + version "3.0.7" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.7.tgz#b36ca107b4acb8ff5bc4ff824584059c23fcb87b" + integrity sha512-utJ+QR3YlIC/6x6xq17UMXeAfxEvXA0VKD3PiSio7hBOZNusA1jXcbxZxVEfJunLp48oonjTepY8ORoIlRx/EQ== + vue-server-renderer@^2.5.16, vue-server-renderer@^2.6.6: version "2.6.10" resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.6.10.tgz#cb2558842ead360ae2ec1f3719b75564a805b375" @@ -13151,6 +13284,11 @@ vuex@^3.0.1: version "3.1.0" resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.0.tgz#634b81515cf0cfe976bd1ffe9601755e51f843b9" +vuex@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.1.tgz#0c264bfe30cdbccf96ab9db3177d211828a5910e" + integrity sha512-ER5moSbLZuNSMBFnEBVGhQ1uCBNJslH9W/Dw2W7GZN23UQA69uapP5GTT9Vm8Trc0PzBSVt6LzF3hGjmv41xcg== + vxx@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/vxx/-/vxx-1.2.2.tgz#741fb51c6f11d3383da6f9b92018a5d7ba807611" @@ -13238,6 +13376,23 @@ webpack-cli@^3.1.2: v8-compile-cache "^2.0.2" yargs "^12.0.5" +webpack-cli@^3.3.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.5.tgz#f4d1238a66a2843d9cebf189835ea22142e72767" + integrity sha512-w0j/s42c5UhchwTmV/45MLQnTVwRoaUTu9fM5LuyOd/8lFoCNCELDogFoecx5NzRUndO0yD/gF2b02XKMnmAWQ== + dependencies: + chalk "2.4.2" + cross-spawn "6.0.5" + enhanced-resolve "4.1.0" + findup-sync "3.0.0" + global-modules "2.0.0" + import-local "2.0.0" + interpret "1.2.0" + loader-utils "1.2.3" + supports-color "6.1.0" + v8-compile-cache "2.0.3" + yargs "13.2.4" + webpack-dev-middleware@^3.0.0, webpack-dev-middleware@^3.4.0: version "3.6.2" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.6.2.tgz#f37a27ad7c09cd7dc67cd97655413abaa1f55942" @@ -13354,6 +13509,36 @@ webpack@^4.25.1, webpack@^4.8.1: watchpack "^1.5.0" webpack-sources "^1.3.0" +webpack@^4.35.2: + version "4.35.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.35.2.tgz#5c8b8a66602cbbd6ec65c6e6747914a61c1449b1" + integrity sha512-TZAmorNymV4q66gAM/h90cEjG+N3627Q2MnkSgKlX/z3DlNVKUtqy57lz1WmZU2+FUZwzM+qm7cGaO95PyrX5A== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/wasm-edit" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + acorn "^6.0.5" + acorn-dynamic-import "^4.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + micromatch "^3.1.8" + mkdirp "~0.5.0" + neo-async "^2.5.0" + node-libs-browser "^2.0.0" + schema-utils "^1.0.0" + tapable "^1.1.0" + terser-webpack-plugin "^1.1.0" + watchpack "^1.5.0" + webpack-sources "^1.3.0" + webpackbar@^2.6.1: version "2.6.4" resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-2.6.4.tgz#9118dde6b8f513a2d50ce630952157bca9218c6f" @@ -13588,6 +13773,15 @@ wrap-ansi@^3.0.1: string-width "^2.1.1" strip-ansi "^4.0.0" +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -13705,12 +13899,37 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^13.1.0: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" dependencies: camelcase "^3.0.0" +yargs@13.2.4, yargs@^13.2.2: + version "13.2.4" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" + integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.0" + yargs@^12.0.1, yargs@^12.0.2, yargs@^12.0.5: version "12.0.5" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" From 66d73b816d940b5794cdd95c5077bb8eded085a9 Mon Sep 17 00:00:00 2001 From: Michal-Dziedzinski Date: Thu, 4 Jul 2019 12:44:27 +0200 Subject: [PATCH 0183/1227] Fixed CR comments --- CHANGELOG.md | 117 +++++++++++++++--- .../compare/components/RemoveFromCompare.ts | 18 +-- core/modules/compare/store/getters.ts | 4 +- .../default/components/core/ProductTile.vue | 16 +-- 4 files changed, 116 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c8be2f90..c484a94b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) @@ -7,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.10.0-rc.1] - 2019.06.19 ### Added + - Make installer work for windows - @Flyingmana (#2616) - "Clear cart" button in the cart - @jablpiotrek (#2587) - Global config api path under `api.url` - @BartoszLiburski (#2622) @@ -25,8 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Products column change functionality - @vishal-7037 (#3017) - New Module order-history this provides the pagination via lazy laod - @hackbard (#2810) - OrderNumber on ThankYouPage - @Flyingmana (#2743) +- Add icons on the product tiles that allow to add to the wish list and to the list to compare products from the list of products - @Michal-Dziedzinski (#2773) ### Removed + - The getter `cart/totals` has ben replaced with `cart/getTotals` - @pkarw (#2522) - The getter `cart/coupon` has ben replaced with `cart/getCoupon` - @pkarw (#2522) - The getter `cart/totalQuantity` has ben replaced with `cart/getItemsTotalQuantity` - @pkarw (#2522) @@ -38,6 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Make all links with the primary color - @hackbard (#2932) ### Fixed + - Back button on the Error page has been fixed - @pkarw (#3077) - Special price got zeroed - @pkarw (#2940) - Microcart tax + discount totals fix - @pkarw (#2892) @@ -76,6 +81,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Back icon on product page causing inconsistent behavior - @patzick (#3056) ### Changed / Improved + - The `cart/sync`, `cart/addItems`, `cart/removeItem` and `cart/updateQuantity` now returns the `diffLog` object with all the notifications, server statuses and items changed during the shopping cart sync - The `cart/addItem` is no longer displaying the error messages - please use the `diffLog.clientNorifications` to update the UI instead (take a look at the `AddToCart.ts` for a reference) - The action `cart/userAfterLoggedin` got renamed to `cart/authorize` - @pkarw (#2522) @@ -87,7 +93,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Disabled the server cart sync in case user is in the checkout - @pkarw (#2749) - Improved ProductGalleryCarousel component to handle nonnumeric options id’s - @danieldomurad (#2586) - Number of displayed products is now visible on PLP on desktop - @awierzbiak (#2504) -- Improved visibility of product SKU in wishlist - @PanMisza (#2606) +- Improved visibility of product SKU in wishlist - @PanMisza (#2606) - Instant focus to search input field after click on search icon in navbar - @ca1zr (#2608) - Login flow from authorized pages after session expired, show the modal with new error message and redirect after login - @gdomiciano, @natalledm (#2674) - Added support for the newest node version - @gdomiciano (#2669) @@ -125,7 +131,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.9.2] - 2019.06.10 ### Fixed -- Instant Checkout visible on Safari - @przspa (#2991) + +- Instant Checkout visible on Safari - @przspa (#2991) - Search Sidebar on Safari - @przspa (#2990) - Country label style - @przspa (#2989) - BaseInputNumber for qty of the product in the cart can change by using arrows - @przspa (#2988) @@ -137,6 +144,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.9.1] - 2019.05.27 ### Fixed + - Remove security vulnerabilities by updating project dependencies - @patzick (#2942) - Fix Configurable Products not accessible in CSR when children visibility is set to "not visible individually" - @revlis-x (#2933) - ProductTile placeholders are visible on SSR - @patzick (#2939) @@ -144,18 +152,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.9.0] - 2019.05.06 ### Added + - The Url Dispatcher feature added for friendly URLs. When `config.seo.useUrlDispatcher` set to true the `product.url_path` and `category.url_path` fields are used as absolute URL addresses (no `/c` and `/p` prefixes anymore). Check the latest `mage2vuestorefront` snapshot and reimport Your products to properly set `url_path` fields - #2010 - @pkarw - Unit tests of cart module written in jest - @lukeromanowicz (#2305) - validation for UTF8 alpha and alphanumeric characters in most checkout fields - @lromanowicz (#2653) - helper to process config urls with default endpoint host `config.api.host` - @patzick (#2858) ### Changed / Improved + - The `core/helpers` parsing URL methods exchanged to `query-string` package - @pkarw (#2446) - Unit tests in Karma are now removed in favor of jest - @lukeromanowicz (#2305) - Material Icons are loaded asynchronously - @JKrupinski, @filrak (#2060) - Update to babel 7 - @lukeromanowicz (#2554) ### Fixed + - For first time setup of the SSR Cache, a local cache-version.json file is required. The path has been removed from .gitignore and a template has been added. - @rio-vps - Gallery low quality image in offline mode when high quality already cached - @patzick (#2557) - Payment issue when no address set - @szafran89 (#2593) @@ -189,28 +200,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.8.5] - 2019-04-17 ### Fixed + - Memory leaks on SSR with Vue.use - @patzick (#2745) ## [1.8.4] - 2019-03-26 ### Fixed + - Problem with incomplete category products load for offline use - @patzick (#2543) - Category products view crash on scrolling down in offline mode - @patzick (#2569) -- Default propery issue for the col-xs-* classes - @cnviradiya (#2558) +- Default propery issue for the col-xs-\* classes - @cnviradiya (#2558) - Wishlist and compare list not cached properly - @filrak (#2580) ### Changed / Improved + - Category and Homepage products are now cached for offline use on SSR entry - @patzick (@1698) ## [1.8.3] - 2019-03-03 ### Added + - Payment Request API integration - @qiqqq (#2306) - New reactive helper to check online state. Usage: `import { onlineHelper } from '@vue-storefront/core/helpers'` and then `onlineHelper.isOnline` - @patzick (#2510) - Cart count config, allows you to display the item count instead of a sum of the item quantities - @pauluse (#2483) - Video support in Product Gallery component. - @rain2o (#2433) ### Fixed + - Problem with placing second order (unbinding payment methods after first order) - @patzick (#2195, #2503) - Remaking order on user orders page - @patzick (#2480) - Images blinking on category page - @pkarw (#2523) @@ -219,6 +235,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Non-integer qty of product added to the cart - @pkarw (#2517) ### Changed / Improved + - Fixed an issue where the correct image for a product configuration wasn't set on the product page image carousel. Also added the fix on the productcarousel in the zoom component - @DaanKouters (#2419) - Way of creating VS Modules was changed to use factory method instead of explict object creation. - @filrak (#2434) - Added clear filters button on desktop also and only show if filters are applied - @DaanKouters (#2342) @@ -248,23 +265,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed editing mode from My Newsletter section - @aniamusial (#2766) - Clicking Remake order now adds your items and redirects you to the checkout - @mikesheward (#2710) - ### Deprecated / Removed + - `@vue-storefront/store` package deprecated - @filrak ## [1.8.2] - 2019-02-11 + - Fixed docker-compose configuration for network_mode and TS build config - @lukeromanowicz (#2415) ## [1.8.1] - 2019-02-10 + This is hot-fix release for fixing the payment methods switching issue when both: `payments-cash-on-delivery` and `payments-backend-methods` modules enabled. ### Changed / Improved - - Fixed doubled invlication of `placeOrder` when both: `payments-cash-on-delivery` and `payments-backend-methods` modules enabled - #2405 + +- Fixed doubled invlication of `placeOrder` when both: `payments-cash-on-delivery` and `payments-backend-methods` modules enabled - #2405 ## [1.8.0] - 2019-02-07 + Additional migration tips are available [here](https://github.com/DivanteLtd/vue-storefront/blob/master/docs/guide/upgrade-notes/README.md). ### Added + - Chinese translation added - @wadereye (#2265) - Categories filter in search view - @kjugi, @patzick (#1710) - AsyncDataLoader feature - @pkarw (#2300) @@ -277,6 +299,7 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - Hotjar integration - @lukeromanowicz (#840) ### Changed / Improved + - Theme structure improvements - @filrak (#2223) - Type interfaces and refactor - @filrak (#2227, #2267) - Changed beforeRegistration and afterRegistration hooks signature. Now it contains only one object VSF. The subfields are the same as before so changing `beforeRegistration( Vue, config, store, isServer )` to `beforeRegistration({ Vue, config, store, isServer })`(and same with `afterRegistration`) is enough to make a proper migration to new API. - @filrak (#2330) @@ -292,7 +315,7 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - `store/lib/search` has been moved to `core/lib/search` - @lukeromanowicz (#2225) - `store/lib/multistore` has been moved to `core/lib/multistore` - @lukeromanowicz (#2224) - BaseSelect syntax improvements - @jszczech (#2237) -- Optional cart discounts display on side cart - @mcspronko (#1758) +- Optional cart discounts display on side cart - @mcspronko (#1758) - Special price dates checking - backport of @igloczek's (#2245) - Category filters reset functionality on mobile - @vue-kacper, @patzick, @renatocason (#2262) - Improve sortBy mobile view - @martaradziszewska (#2251) @@ -325,12 +348,16 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - Configurable options attribute descriptor - @pkarw (#2384) ## [1.7.3] - 2019-01-31 + ### Fixed + - Output cache between build, cache versioning added - @igloczek (#2309) - Missing `no-ssr` wrapper around user specific content, which leads to broken app in production mode - @igloczek (#2314) ## [1.7.2] - 2019-01-28 + ### Fixed + - clear search filters on mobile - @patzick (#2282) - SSR problem on checkout page on reload - @vue-kacper (#2220) - Improved offline mode handlers - @pkarw (#2217) @@ -340,9 +367,11 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - SSR detection in components - @patzick (#2173) ### Added + - Hotjar extension (#840) ### Changed + - compress banner images - @patzick (#2280) - Dynamic attributes loader (#2137) - Dynamic categories prefetching (#2076) @@ -350,16 +379,21 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - Support regional characters in urls - Backport of @aekal's (#2243) ### Added + - Translations of banners - @patzick (#2276) - Banners title background on mobile - @patzick (#2272) - New main site look - @patzick (#2266) ## [1.7.1] - 2019-01-15 + ### Fixed + - Corrected scrolled sidebar menu position ## [1.7.0] - 2019-01-15 + ### Added + - Dynamic categories prefetching — @pkarw #2100 - Per-route codesplitting for SSR pages — @patzick #2068 - async/await support — @patzick #2092 @@ -373,6 +407,7 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - Out of the box GZIP compression and sourcemap removal in prod mode — @patzick #2186 ### Changed / Improved + - Invalidate output cache using POST - @Cyclonecode #2084 - NGNIX installation improvements for docs — @janmyszkier #2080 - HTML semantics improvements — @patzick #2094 @@ -389,6 +424,7 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - IndexedDb changed to LocalStorage + ServiceWorker native caching (#2112) ### Fixed + - Fix Notification.vue compiling issue on prod - @ladrua #2079 - Fix wishlist toggle bug — @shkodasv #2086 - findConfigurableChildAsync — fix checking stock for configurable child — @afirlejczyk #2097 @@ -410,19 +446,24 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - Fix Cart Configurable Item pulled from Magento loaded as Simple — @pkarw @valeriish #2169 #2181 ### Depreciated + - extendStore depreciation - @filrak #2143 - ValidationError class depreciation - @filrak #2143 ## [1.6.0] - 2018-12-05 + ### Added + - Lazy loading for SSR and non-SSR routes - app splitted into modules ### Removed + - `vsf-payment-stripe` module integration removed from core ### Changed -- There is new config option `config.orders.directBackendSync` that changes the behavior of placing an order. Please do read [more on this change](https://github.com/DivanteLtd/vue-storefront/commit/e73f2ca19a5d33a39f8b0fd6346543eced24167e) and [more on vue-storefront-api change](https://github.com/DivanteLtd/vue-storefront-api/commit/80c497f72362c72983db4fdcac14c8ba6f8729a8) + +- There is new config option `config.orders.directBackendSync` that changes the behavior of placing an order. Please do read [more on this change](https://github.com/DivanteLtd/vue-storefront/commit/e73f2ca19a5d33a39f8b0fd6346543eced24167e) and [more on vue-storefront-api change](https://github.com/DivanteLtd/vue-storefront-api/commit/80c497f72362c72983db4fdcac14c8ba6f8729a8) - ProductSlider, ProductLinks, ProductListing moved to theme. - Many theme-related logic moved to theme (+ deleted empty core components just with `name`) - Components required for backward compatibility moved to `compatibility` folder. For all this files you just need to add `compatibility` after `core` in import path to make them work like before. @@ -437,6 +478,7 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue ## [1.5.0] - 2018-10-22 ### Added + - Contact form mailer - #1875 - Akbar Abdrakhmanov @akbarik - oauth2 configuration in setup - #1865 - Krister Andersson @Cyclonecode - GraphQL schema extendibility in the API - Yoann Vié @@ -445,9 +487,11 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - 'Apply' filters button on mobile category - #1709 - Damian Fiałkiewicz @Aekal ### Changed + - New Modules API, and base modules (cart, wishlist, newsletter ...) refactored [read more...](https://github.com/DivanteLtd/vue-storefront/blob/master/doc/api-modules/about-modules.md) - Filip Rakowski @filrak ### Fixed + - The `regionId` field added to Order interface - #1258 - Jim Hil @jimcreate78 - SSR Memory leaks fixed - #1882 Tomasz Duda @tomasz-duda - E2E tests fixed - #1861 - Patryk Tomczyk @patzik @@ -459,6 +503,7 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue ## [1.4.0] - 2018-10-05 ### Added + - GraphQL support - #1616 - Yuri Boyko @yuriboyko, Vladimir Plastovets @VladimirPlastovets => [PHOENIX MEDIA](https://www.phoenix-media.eu/) - Layout switching + Advanced output mechanisms - #1787 - Piotr Karwatka @pkarw - Dynamic config reload - #1800 - Piotr Karwatka @pkarw @@ -469,9 +514,11 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - Console silent mode (disabled by default) - #1752 - Piotr Karwatka - @pkarw ### Changed + - Please check the [Upgrade notes](https://github.com/DivanteLtd/vue-storefront/blob/develop/doc/Upgrade%20notes.md) for the full list ### Fixed + - `docker-compose.yml` files updated - @kovinka - Non-core translations moved to theme resource files (i18n) - #1747 - David Rouyer @DavidRouyer - Non-core assets moved to the theme - #1739, #1740 - David Rouyer @DavidRouyer @@ -485,6 +532,7 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue ## [1.3.0] - 2018-08-31 ### Added + - TypeScript support - please check [TypeScript Action Plan](https://github.com/DivanteLtd/vue-storefront/blob/master/docs/guide/basics/typescript.md) for details - New `core/modules` added regarding the [Refactor to modules plan](https://github.com/DivanteLtd/vue-storefront/blob/master/doc/api-modules/refactoring-to-modules.md) - Price tier's support #1625 @@ -494,15 +542,18 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue - dynamic port allocation #1511 ### Removed + - unused `libs`, `components`, `core/api/cart` webpack aliases - `global.$VS` has been replaced with `rootStore` #1624 ### Changed + - `core` directory is now a `@vue-storefront/core` package, webpack alias and all related imports reflect this change [#1513] - `core/api` renamed to `core/modules`, mixin features moved to `core/modules/module_name/features` - `core/lib/i18n` moved into separate `@vue-storefront/i18n` package ### Fixed + - installer paths are now normalized (to support paths including spaces) #1645 - status check added to the configurable_children products #1639 - product info update when clicking the related products #1601 @@ -517,12 +568,14 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue ## [1.2.0] - 2018-08-01 ### Fixed + - Improved integration tests [#1471] - Minor taxcalc.js improvements [#1467] - Search by SKU fixed [#1455] - ProductList dbl click fix [#1438] ### Added + - Docker support for vue-storefront - Production config docs added [#1450] - Integration tests for Compare products added [#1422] @@ -535,6 +588,7 @@ Additional migration tips are available [here](https://github.com/DivanteLtd/vue Please keep an eye on the **[UPGRADE NOTES](https://github.com/DivanteLtd/vue-storefront/blob/master/doc/Upgrade%20notes.md)** ### Fixed + - Zip Code validation [#1372] - Get inpspired block [#968] - Favicon [#836] @@ -546,6 +600,7 @@ Please keep an eye on the **[UPGRADE NOTES](https://github.com/DivanteLtd/vue-st - IndexedDB locking issue ### Added + - Added PM2 process manager [#1162] - Added billing data phone number support [#1338] - Added validation labels + generic control for CountrySelector [#1227] @@ -557,47 +612,61 @@ Please keep an eye on the **[UPGRADE NOTES](https://github.com/DivanteLtd/vue-st - Production ready Docker config for vue-storefront-api ## [1.0.5] - 2018-06-04 + ### Fixed + - Shipping region fix - Hotfix for missing config.storeViews.multistore check - Minor fixes ## [1.0.4] - 2018-06-02 + ### Fixed + - defaultCountry fix for IT - Tax classes hotfix - tax_class_id is required by taxcalc - restored along with version inc - Minor fixes ## [1.0.3] - 2018-06-02 + ### Fixed + - Minor fixes ## [1.0.2] - 2018-06-02 + ### Fixed + - vue-storefront-stripe renamed to vsf-payment-stripe hotfix - Minor fixes ## [1.0.1] - 2018-05-31 + ### Fixed + - Minor fixes ## [1.0.0] - 2018-05-30 + ### Added -- __Multistore__ - now it's possible to manage the store views with all the features like translations, custom category, and products content, shipping rates - basically all Magento2 features are supported! You can read more on how to setup Multistore here. -- __Bundle products__ - support for the Magento-like bundle products with all the custom options, pricing rules etc. -- __Configurable options__ - that allows users to select radio/checkbox options + put some custom notes (textboxes) on the products they like to order, -- __Crossell, Upsell, Related products__ - are now synchronized with Magento2, -- __Webpack4 support__ - we've migrated from Webpack2 -> Webpack4 and now the build process takes much less time while providing some cool new features, -- __Core components refactor__ - without changing APIs, we've stripped the core components from s to improve the performance and improve the code readability, -- __PWA Manifest fixes__ - iOS PWA support required us to adjust some settings, -- __Improved translations__ - we're constantly tweaking the translation files :) We've just added it-IT and pl-PL (finally!) support recently -- __Improved Travis-CI pipeline__ - and added support for end-2-end testing, -- __Lot of bugfixes + UX fixes__ - countless hours spent on improving the code and UI quality! -- __Please check it out:__ visit: https://demo.vuestorefront.io/ + +- **Multistore** - now it's possible to manage the store views with all the features like translations, custom category, and products content, shipping rates - basically all Magento2 features are supported! You can read more on how to setup Multistore here. +- **Bundle products** - support for the Magento-like bundle products with all the custom options, pricing rules etc. +- **Configurable options** - that allows users to select radio/checkbox options + put some custom notes (textboxes) on the products they like to order, +- **Crossell, Upsell, Related products** - are now synchronized with Magento2, +- **Webpack4 support** - we've migrated from Webpack2 -> Webpack4 and now the build process takes much less time while providing some cool new features, +- **Core components refactor** - without changing APIs, we've stripped the core components from s to improve the performance and improve the code readability, +- **PWA Manifest fixes** - iOS PWA support required us to adjust some settings, +- **Improved translations** - we're constantly tweaking the translation files :) We've just added it-IT and pl-PL (finally!) support recently +- **Improved Travis-CI pipeline** - and added support for end-2-end testing, +- **Lot of bugfixes + UX fixes** - countless hours spent on improving the code and UI quality! +- **Please check it out:** visit: https://demo.vuestorefront.io/ ## [1.0.0-rc.3] - 2018-04-29 + ### Added + - Performance tweaks: improved service worker config, reduced JSONs, two-stage caching, - User token auto refresh, - My Account fixes @@ -610,7 +679,9 @@ Please keep an eye on the **[UPGRADE NOTES](https://github.com/DivanteLtd/vue-st - Product and Category page refactoring ## [1.0.0-rc.2] - 2018-03-29 + ### Added + - Basic Magento 1.9 support, - Translations: ES, DE, NL, FR - Lerna support for managing the npm packages within the one repository, @@ -623,7 +694,9 @@ Please keep an eye on the **[UPGRADE NOTES](https://github.com/DivanteLtd/vue-st - Other fixes. ## [1.0.0-rc.0] - 2018-03-01 + ### Added + - i18n (internationalization) support for the UI, - Support for Magento2 dynamic cart totals - which enables the shopping cart rules mechanism of Magento to work with VS, - ESlint-plugin-vue installed, @@ -637,7 +710,9 @@ Please keep an eye on the **[UPGRADE NOTES](https://github.com/DivanteLtd/vue-st - Droppoints shipping methods (NL support) added. ## [0.4.0] - 2018-01-28 + ### Added + - Improved theming support + B2B product catalog theme included (original github repo); it's PoC made in just one week! Isn't it amazing that you can customize VS in just one week to this extent? :) - Pimcore support (more on this, github repo) - Customer's dashboard + address book, integration with Checkout @@ -652,7 +727,9 @@ Please keep an eye on the **[UPGRADE NOTES](https://github.com/DivanteLtd/vue-st - Lot of smaller tweaks ## [0.3.0] - 2017-12-21 + ### Added + - Bundle products support, - Tax calculation regarding the Magento's logic for different rates per countries, states. - User registration, log-in, password reset @@ -670,7 +747,9 @@ Please keep an eye on the **[UPGRADE NOTES](https://github.com/DivanteLtd/vue-st - Updated installer with support for Linux and MacOSX ## [0.2.1-alpha.0] - 2017-11-16 + ### Added + - Homepage - Category page - Product page @@ -685,5 +764,7 @@ Please keep an eye on the **[UPGRADE NOTES](https://github.com/DivanteLtd/vue-st - RWD (except some checkout issues to be fixed) ## [0.2.0-alpha.0] - 2017-11-15 + ### Fixed + - Lazy loaded blocks size fixed diff --git a/core/modules/compare/components/RemoveFromCompare.ts b/core/modules/compare/components/RemoveFromCompare.ts index 56ce0fba9..9e3eff929 100644 --- a/core/modules/compare/components/RemoveFromCompare.ts +++ b/core/modules/compare/components/RemoveFromCompare.ts @@ -1,20 +1,14 @@ -import Product from '@vue-storefront/core/modules/catalog/types/Product' -import { Compare as CompareModule } from '..' -import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin' +import Product from '@vue-storefront/core/modules/catalog/types/Product'; +import { Compare as CompareModule } from '..'; +import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin'; export const RemoveFromCompare = { name: 'RemoveFromCompare', mixins: [compareMountedMixin], - props: { - product: { - required: true, - type: Object - } - }, methods: { removeFromCompare (product: Product) { - CompareModule.register() - this.$store.dispatch('compare/removeItem', product) + CompareModule.register(); + this.$store.dispatch('compare/removeItem', product); } } -} +}; diff --git a/core/modules/compare/store/getters.ts b/core/modules/compare/store/getters.ts index 79213a865..5dfea67da 100644 --- a/core/modules/compare/store/getters.ts +++ b/core/modules/compare/store/getters.ts @@ -4,8 +4,8 @@ import CompareState from '../types/CompareState'; const getters: GetterTree = { isEmpty: state => state.items.length === 0, - isToCompare: state => product => state.items.find(p => p.sku === product.sku), - isCompareLoaded: state => state.loaded + isCompareLoaded: state => state.loaded, + isToCompare: state => product => state.items.find(p => p.sku === product.sku) }; export default getters; diff --git a/src/themes/default/components/core/ProductTile.vue b/src/themes/default/components/core/ProductTile.vue index e8b3a630f..197f7f859 100644 --- a/src/themes/default/components/core/ProductTile.vue +++ b/src/themes/default/components/core/ProductTile.vue @@ -37,7 +37,9 @@ />
-

{{ product.name | htmlDecode }}

+

+ {{ product.name | htmlDecode }} +

Date: Thu, 4 Jul 2019 13:07:30 +0200 Subject: [PATCH 0184/1227] update manual for vsf cli --- packages/cli/bin/vsf.js | 21 --------------------- packages/cli/index.js | 20 ++++++++++++++++++++ packages/cli/package.json | 7 ++----- packages/cli/scripts/manual.js | 8 ++++---- 4 files changed, 26 insertions(+), 30 deletions(-) delete mode 100755 packages/cli/bin/vsf.js diff --git a/packages/cli/bin/vsf.js b/packages/cli/bin/vsf.js deleted file mode 100755 index a56209027..000000000 --- a/packages/cli/bin/vsf.js +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env node - -const command = process.argv[2] - -switch (command) { - case 'init': - require('../scripts/install.js')(process.argv[3]) - break; - case 'generate-module': - require('../scripts/generateModule.js')(process.argv[3]) - break; - case '--help': - require('../scripts/manual.js')() - break; - case '--version': - console.log('v' + require('../package.json').version) - break; - default: - console.log('Unknown command. try one of those:\n') - require('../scripts/manual.js')() -} diff --git a/packages/cli/index.js b/packages/cli/index.js index 908ba8417..cfae06053 100644 --- a/packages/cli/index.js +++ b/packages/cli/index.js @@ -1 +1,21 @@ #!/usr/bin/env node + +const command = process.argv[2] + +switch (command) { + case 'init': + require('./scripts/install.js')(process.argv[3]) + break; + case 'generate-module': + require('./scripts/generateModule.js')(process.argv[3]) + break; + case '--help': + require('./scripts/manual.js')() + break; + case '--version': + console.log('v' + require('../package.json').version) + break; + default: + console.log('Unknown command. try one of those:\n') + require('./scripts/manual.js')() +} diff --git a/packages/cli/package.json b/packages/cli/package.json index aa7ba669d..633c73c1d 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,13 +1,10 @@ { "name": "@vue-storefront/cli", - "version": "0.0.10", + "version": "0.0.11", "description": "", "main": "index.js", - "scripts": { - "init": "./index.js" - }, "bin": { - "vsf": "./bin/vsf.js" + "vsf": "./index.js" }, "publishConfig": { "access": "public" diff --git a/packages/cli/scripts/manual.js b/packages/cli/scripts/manual.js index b433bdba8..7fdce1a91 100644 --- a/packages/cli/scripts/manual.js +++ b/packages/cli/scripts/manual.js @@ -1,9 +1,9 @@ module.exports = function () { console.log('Usage: vsf [command] [options]\n') console.log('Options:') - console.log(' --help available commands') - console.log(' --version CLI version\n') + console.log(' --help available commands') + console.log(' --version CLI version\n') console.log('Commands:') - console.log(' init [dir] setup new VS project') - console.log(' init-module [name] generate vs module boilerplate') + console.log(' init [dir] setup new VS project') + console.log(' generate-module [name] generate vs module boilerplate') } From 8c2019bfd77343d17344ad69a1910c7300370f3a Mon Sep 17 00:00:00 2001 From: pkarw Date: Thu, 4 Jul 2019 13:40:03 +0200 Subject: [PATCH 0185/1227] Decreased the `localStorage` quota usage + error handling --- CHANGELOG.md | 1 + config/default.json | 8 ++++++-- core/lib/sync/index.ts | 2 +- core/modules/catalog/hooks/beforeRegistration.ts | 5 ----- core/modules/catalog/store/product/actions.ts | 8 +++++++- core/modules/compare/store/plugin.ts | 2 +- core/modules/url/store/actions.ts | 12 +++++++++++- core/store/lib/storage.ts | 10 +++++++++- docs/guide/upgrade-notes/README.md | 10 ++++++++++ 9 files changed, 46 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90b485fa3..a5ae5077c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Shipping address is saved as default when not logged in user chooses to create account during checkout - @iwonapiotrowska (#2636) - Can set transition style for Modal content - @grimasod (#3146) - Added stock to cart items - @cheeerd (#3166) +- Decreased the `localStorage` quota usage + error handling by introducing new config variables: `config.products.disableLocalStorageProductsCache` to not store products by SKU (by default it's on). Products are cached in ServiceWorker cache anyway so the `product/list` will populate the in-memory cache (`cache.setItem(..., memoryOnly = true)`); `config.seodisableUrlRoutesLocalStorageCache` - to not store the url mappings; they're stored in in-memory cache anyway so no additional requests will be made to the backend for url mapping; however it might cause some issues with url routing in the offline mode (when the offline mode PWA installed on homescreen got reloaded, the in-memory cache will be cleared so there won't potentially be the url mappings; however the same like with `product/list` the ServiceWorker cache SHOULD populate url mappings anyway); `config.syncTasks.disableLocalStorageTaskQueue` to not store the network requests queue in service worker. Currently only the stock-check and user-data changes were using this queue. The only downside it introuces can be related to the offline mode and these tasks will not be re-executed after connectivity established, but just in a case when the page got reloaded while offline (yeah it might happen using ServiceWorker; `syncTasks` can't be re-populated in cache from SW) ## [1.10.0-rc.2] - UNRELEASED diff --git a/config/default.json b/config/default.json index 8ec8790a6..b172a33d9 100644 --- a/config/default.json +++ b/config/default.json @@ -20,7 +20,8 @@ } }, "seo": { - "useUrlDispatcher": true + "useUrlDispatcher": true, + "disableUrlRoutesLocalStorageCache": true }, "console": { "showErrorOnProduction" : false, @@ -256,6 +257,7 @@ "applycoupon_endpoint": "/api/cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}" }, "products": { + "disableLocalStorageProductsCache": true, "useMagentoUrlKeys": true, "setFirstVarianAsDefaultInURL": false, "configurableChildrenStockPrefetchStatic": false, @@ -335,7 +337,6 @@ "wishlist": "LOCALSTORAGE", "categories": "LOCALSTORAGE", "attributes": "LOCALSTORAGE", - "products": "INDEXEDDB", "elasticCache": "LOCALSTORAGE", "claims": "LOCALSTORAGE", "syncTasks": "LOCALSTORAGE", @@ -391,6 +392,9 @@ } ] }, + "syncTasks": { + "disableLocalStorageTaskQueue": true + }, "i18n": { "defaultCountry": "US", "defaultLanguage": "EN", diff --git a/core/lib/sync/index.ts b/core/lib/sync/index.ts index 91efdfc4e..46c0bbe1c 100644 --- a/core/lib/sync/index.ts +++ b/core/lib/sync/index.ts @@ -17,7 +17,7 @@ async function queue (task) { if (err) Logger.error(err, 'sync')() Vue.prototype.$bus.$emit('sync/PROCESS_QUEUE', { config: config }) // process checkout queue resolve(task) - }).catch((reason) => { + }, config.syncTasks.disableLocalStorageTaskQueue).catch((reason) => { Logger.error(reason, 'sync')() // it doesn't work on SSR reject(reason) }) diff --git a/core/modules/catalog/hooks/beforeRegistration.ts b/core/modules/catalog/hooks/beforeRegistration.ts index 0535e5a45..afe8e7809 100644 --- a/core/modules/catalog/hooks/beforeRegistration.ts +++ b/core/modules/catalog/hooks/beforeRegistration.ts @@ -24,9 +24,4 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { driver: localForage[config.localForage.defaultDrivers['elasticCache']] }), true, config.server.elasticCacheQuota) - Vue.prototype.$db.productsCollection = new UniversalStorage(localForage.createInstance({ - name: dbNamePrefix + 'shop', - storeName: 'products', - driver: localForage[config.localForage.defaultDrivers['products']] - })) } diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts index 159b54d40..85959fa56 100644 --- a/core/modules/catalog/store/product/actions.ts +++ b/core/modules/catalog/store/product/actions.ts @@ -340,9 +340,15 @@ const actions: ActionTree = { } const cacheKey = entityKeyName(cacheByKey, prod[(cacheByKey === 'sku' && prod['parentSku']) ? 'parentSku' : cacheByKey]) // to avoid caching products by configurable_children.sku if (isCacheable) { // store cache only for full loads - cache.setItem(cacheKey, prod) + cache.setItem(cacheKey, prod, null, config.products.disableLocalStorageProductsCache) .catch((err) => { Logger.error('Cannot store cache for ' + cacheKey, err)() + if ( + err.name === 'QuotaExceededError' || + err.name === 'NS_ERROR_DOM_QUOTA_REACHED' + ) { // quota exceeded error + cache.clear() // clear products cache if quota exceeded + } }) } if ((prod.type_id === 'grouped' || prod.type_id === 'bundle') && prefetchGroupProducts && !isServer) { diff --git a/core/modules/compare/store/plugin.ts b/core/modules/compare/store/plugin.ts index 6f887e95c..d88b163c7 100644 --- a/core/modules/compare/store/plugin.ts +++ b/core/modules/compare/store/plugin.ts @@ -7,7 +7,7 @@ export function plugin (mutation, state) { if (type.includes(types.COMPARE_ADD_ITEM) || type.includes(types.COMPARE_DEL_ITEM)) { // check if this mutation is comapre related cacheStorage.setItem('current-compare', state.compare.items).catch((reason) => { - Logger.error(reason, 'compare') // it doesn't work on SSR + Logger.error(reason, 'compare') }) } } diff --git a/core/modules/url/store/actions.ts b/core/modules/url/store/actions.ts index 5bcd4694a..b6073ece2 100644 --- a/core/modules/url/store/actions.ts +++ b/core/modules/url/store/actions.ts @@ -4,6 +4,7 @@ import * as types from './mutation-types' // you can use this storage if you want to enable offline capabilities import { cacheStorage } from '../' import queryString from 'query-string' +import config from 'config' import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' import { processDynamicRoute, normalizeUrlPath, parametrizeRouteData } from '../helpers' import { storeCodeFromRoute, removeStoreCodeFromRoute } from '@vue-storefront/core/lib/multistore' @@ -13,7 +14,16 @@ export const actions: ActionTree = { // if you want to use cache in your module you can load cached data like this async registerMapping ({ commit }, { url, routeData }: { url: string, routeData: any}) { commit(types.REGISTER_MAPPING, { url, routeData }) - await cacheStorage.setItem(url, routeData) + try { + await cacheStorage.setItem(url, routeData, null, config.seo.disableUrlRoutesLocalStorageCache) + } catch (err) { + if ( + err.name === 'QuotaExceededError' || + err.name === 'NS_ERROR_DOM_QUOTA_REACHED' + ) { // quota exceeded error + cacheStorage.clear() // clear the url cache if quota has been exceeded + } + } return routeData }, /** diff --git a/core/store/lib/storage.ts b/core/store/lib/storage.ts index 673d2fa07..c30859e17 100644 --- a/core/store/lib/storage.ts +++ b/core/store/lib/storage.ts @@ -42,7 +42,6 @@ class LocalForageCacheDriver { private _persistenceErrorNotified: boolean; private _useLocalCacheByDefault: boolean; private cacheErrorsCount: any; - private localCache: any; private _storageQuota: number; public constructor (collection, useLocalCacheByDefault = true, storageQuota = 0) { @@ -128,6 +127,14 @@ class LocalForageCacheDriver { } } + public getLastError () { + return this._lastError + } + + public getDbName () { + return this._dbName + } + // Retrieve an item from the store. Unlike the original async_storage // library in Gaia, we don't modify return values at all. If a key's value // is `undefined`, we pass that value to the callback function. @@ -313,6 +320,7 @@ class LocalForageCacheDriver { }).catch(err => { isResolved = true this._lastError = err + throw err })) setTimeout(() => { if (!isResolved) { // this is cache time out check diff --git a/docs/guide/upgrade-notes/README.md b/docs/guide/upgrade-notes/README.md index f0077d279..79911caf6 100644 --- a/docs/guide/upgrade-notes/README.md +++ b/docs/guide/upgrade-notes/README.md @@ -2,6 +2,16 @@ We're trying to keep the upgrade process as easy as possible. Unfortunately, sometimes manual code changes are required. Before pulling out the latest version, please take a look at the upgrade notes below: +## 1.10 -> 1.11 + +We've decreased the `localStorage` quota usage + error handling by introducing new config variables: + +- `config.products.disableLocalStorageProductsCache` to not store products by SKU (by default it's on). Products are cached in ServiceWorker cache anyway so the `product/list` will populate the in-memory cache (`cache.setItem(..., memoryOnly = true)`); +- `config.seodisableUrlRoutesLocalStorageCache` - to not store the url mappings; they're stored in in-memory cache anyway so no additional requests will be made to the backend for url mapping; however it might cause some issues with url routing in the offline mode (when the offline mode PWA installed on homescreen got reloaded, the in-memory cache will be cleared so there won't potentially be the url mappings; however the same like with `product/list` the ServiceWorker cache SHOULD populate url mappings anyway); +- `config.syncTasks.disableLocalStorageTaskQueue` to not store the network requests queue in service worker. Currently only the stock-check and user-data changes were using this queue. The only downside it introuces can be related to the offline mode and these tasks will not be re-executed after connectivity established, but just in a case when the page got reloaded while offline (yeah it might happen using ServiceWorker; `syncTasks` can't be re-populated in cache from SW) + +If by some reasons you wan't to have the `localStorage` back on for `Products by SKU`, `Url Routes` and `SyncTasks` - please juset set these variables back to `false` in your `config/local.json`. + ## 1.9 -> 1.10 - Event `application-after-init` is now emitted by event bus instead of root Vue instance (app), so you need to listen to `Vue.prototype.$bus` (`Vue.prototype.$bus.$on()`) now - The lowest supported node version is currently 8.10.0, From 08cd4832db47cedd5ca0625710f66b8b37be861c Mon Sep 17 00:00:00 2001 From: pkarw Date: Thu, 4 Jul 2019 13:41:16 +0200 Subject: [PATCH 0186/1227] eslint fixes --- core/modules/catalog/hooks/beforeRegistration.ts | 1 - core/modules/catalog/store/product/actions.ts | 2 +- core/modules/url/store/actions.ts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/modules/catalog/hooks/beforeRegistration.ts b/core/modules/catalog/hooks/beforeRegistration.ts index afe8e7809..9a529e6c2 100644 --- a/core/modules/catalog/hooks/beforeRegistration.ts +++ b/core/modules/catalog/hooks/beforeRegistration.ts @@ -23,5 +23,4 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { storeName: 'elasticCache', driver: localForage[config.localForage.defaultDrivers['elasticCache']] }), true, config.server.elasticCacheQuota) - } diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts index 85959fa56..07eac34e0 100644 --- a/core/modules/catalog/store/product/actions.ts +++ b/core/modules/catalog/store/product/actions.ts @@ -348,7 +348,7 @@ const actions: ActionTree = { err.name === 'NS_ERROR_DOM_QUOTA_REACHED' ) { // quota exceeded error cache.clear() // clear products cache if quota exceeded - } + } }) } if ((prod.type_id === 'grouped' || prod.type_id === 'bundle') && prefetchGroupProducts && !isServer) { diff --git a/core/modules/url/store/actions.ts b/core/modules/url/store/actions.ts index b6073ece2..5922f6cbe 100644 --- a/core/modules/url/store/actions.ts +++ b/core/modules/url/store/actions.ts @@ -22,7 +22,7 @@ export const actions: ActionTree = { err.name === 'NS_ERROR_DOM_QUOTA_REACHED' ) { // quota exceeded error cacheStorage.clear() // clear the url cache if quota has been exceeded - } + } } return routeData }, From 9a8bab8f7f8ef784f3132cb55947428c1ec53601 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Thu, 4 Jul 2019 14:51:51 +0200 Subject: [PATCH 0187/1227] add single choice filter variant and set price to that --- .../catalog-next/helpers/filterHelpers.ts | 6 +- .../catalog-next/store/category/getters.ts | 3 +- .../test/unit/changeFilterQuery.spec.ts | 103 +++++++++++++----- .../catalog-next/types/FilterVariant.ts | 3 +- 4 files changed, 84 insertions(+), 31 deletions(-) diff --git a/core/modules/catalog-next/helpers/filterHelpers.ts b/core/modules/catalog-next/helpers/filterHelpers.ts index 64fdbdf8d..cac1d3702 100644 --- a/core/modules/catalog-next/helpers/filterHelpers.ts +++ b/core/modules/catalog-next/helpers/filterHelpers.ts @@ -19,10 +19,14 @@ export const changeFilterQuery = ({currentQuery = {}, filterVariant}: {currentQu if (!Array.isArray(queryFilter)) queryFilter = [queryFilter] if (queryFilter.includes(filterVariant.id)) { queryFilter = queryFilter.filter(value => value !== filterVariant.id) + } else if (filterVariant.single) { + queryFilter = [filterVariant.id] } else { queryFilter.push(filterVariant.id) } - newQuery[filterVariant.type] = queryFilter + // delete or add filter variant to query + if (!queryFilter.length) delete newQuery[filterVariant.type] + else newQuery[filterVariant.type] = queryFilter } return newQuery } diff --git a/core/modules/catalog-next/store/category/getters.ts b/core/modules/catalog-next/store/category/getters.ts index 3d87cd1a4..779ba85d5 100644 --- a/core/modules/catalog-next/store/category/getters.ts +++ b/core/modules/catalog-next/store/category/getters.ts @@ -62,7 +62,8 @@ const getters: GetterTree = { type: attrToFilter, from: option.from, to: option.to, - label: (index === 0 || (index === count - 1)) ? (option.to ? '< ' + currencySign + option.to : '> ' + currencySign + option.from) : currencySign + option.from + (option.to ? ' - ' + option.to : '')// TODO: add better way for formatting, extract currency sign + label: (index === 0 || (index === count - 1)) ? (option.to ? '< ' + currencySign + option.to : '> ' + currencySign + option.from) : currencySign + option.from + (option.to ? ' - ' + option.to : ''), // TODO: add better way for formatting, extract currency sign + single: true }) index++ } diff --git a/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts b/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts index ff37d352e..d0145e932 100644 --- a/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts +++ b/core/modules/catalog-next/test/unit/changeFilterQuery.spec.ts @@ -5,73 +5,120 @@ describe('changeFilterQuery method', () => { it('should not change query when no filter variant provided', () => { const currentQuery = { color: 1 - } - const result = changeFilterQuery({currentQuery}) - expect(result).toEqual(currentQuery) - }) + }; + const result = changeFilterQuery({ currentQuery }); + expect(result).toEqual(currentQuery); + }); it('should not return same query object instance', () => { const currentQuery = { color: 1 - } - const result = changeFilterQuery({currentQuery}) - expect(result).not.toBe(currentQuery) + }; + const result = changeFilterQuery({ currentQuery }); + expect(result).not.toBe(currentQuery); }); it('should add filter to array', () => { - const currentQuery = {} + const currentQuery = {}; const filterVariant: FilterVariant = { id: '33', label: 'Red', type: 'color' - } - const result = changeFilterQuery({currentQuery, filterVariant}) - expect(result).toEqual({color: ['33']}) + }; + const result = changeFilterQuery({ currentQuery, filterVariant }); + expect(result).toEqual({ color: ['33'] }); }); it('should remove filter if exist in query', () => { const currentQuery = { color: ['23', '33'] - } + }; const filterVariant: FilterVariant = { id: '33', label: 'Red', type: 'color' - } - const result = changeFilterQuery({currentQuery, filterVariant}) - expect(result).toEqual({color: ['23']}) + }; + const result = changeFilterQuery({ currentQuery, filterVariant }); + expect(result).toEqual({ color: ['23'] }); }); it('should add sort filter', () => { - const currentQuery = {} + const currentQuery = {}; const filterVariant: FilterVariant = { id: 'final_price', label: 'Price: Low to high', type: 'sort' - } - const result = changeFilterQuery({currentQuery, filterVariant}) - expect(result).toEqual({sort: 'final_price'}) + }; + const result = changeFilterQuery({ currentQuery, filterVariant }); + expect(result).toEqual({ sort: 'final_price' }); }); it('should remove sort filter', () => { - const currentQuery = {sort: 'final_price'} + const currentQuery = { sort: 'final_price' }; const filterVariant: FilterVariant = { id: 'final_price', label: 'Price: Low to high', type: 'sort' - } - const result = changeFilterQuery({currentQuery, filterVariant}) - expect(result).toEqual({}) + }; + const result = changeFilterQuery({ currentQuery, filterVariant }); + expect(result).toEqual({}); }); it('should change sort filter', () => { - const currentQuery = {sort: 'final_price'} + const currentQuery = { sort: 'final_price' }; const filterVariant: FilterVariant = { id: 'updated_at', label: 'Latest', type: 'sort' - } - const result = changeFilterQuery({currentQuery, filterVariant}) - expect(result).toEqual({sort: 'updated_at'}) + }; + const result = changeFilterQuery({ currentQuery, filterVariant }); + expect(result).toEqual({ sort: 'updated_at' }); + }); + + it('should add single filter when there is none', () => { + const currentQuery = { + }; + const filterVariant: FilterVariant = { + id: '50.0-100.0', + type: 'price', + from: '50', + to: '100', + label: '$50 - 100', + single: true + }; + const result = changeFilterQuery({ currentQuery, filterVariant }); + expect(result).toEqual({ price: ['50.0-100.0'] }); + }); + + it('should remove single filter when adding is the same', () => { + const currentQuery = { + price: ['50.0-100.0'] + }; + const filterVariant: FilterVariant = { + id: '50.0-100.0', + type: 'price', + from: '50', + to: '100', + label: '$50 - 100', + single: true + }; + const result = changeFilterQuery({ currentQuery, filterVariant }); + expect(result).toEqual({}); + }); + + it('should change single filter when adding another single', () => { + const currentQuery = { + price: ['100.0-150.0'] + }; + const filterVariant: FilterVariant = { + id: '50.0-100.0', + type: 'price', + from: '50', + to: '100', + label: '$50 - 100', + single: true + }; + const result = changeFilterQuery({ currentQuery, filterVariant }); + expect(result).toEqual({ price: ['50.0-100.0'] }); }); -}) +}); diff --git a/core/modules/catalog-next/types/FilterVariant.ts b/core/modules/catalog-next/types/FilterVariant.ts index e85e1c903..8f8f2d8d7 100644 --- a/core/modules/catalog-next/types/FilterVariant.ts +++ b/core/modules/catalog-next/types/FilterVariant.ts @@ -3,5 +3,6 @@ export default interface FilterVariant { label: string, type: string, from?: string, - to?: string + to?: string, + single?: boolean } From 4df3e75063deb158059c043ddd165fd41eb2d12d Mon Sep 17 00:00:00 2001 From: michasik Date: Thu, 4 Jul 2019 17:06:11 +0200 Subject: [PATCH 0188/1227] Adds storeCode to formatCategoryLink method --- core/modules/url/helpers/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/modules/url/helpers/index.ts b/core/modules/url/helpers/index.ts index 3f2094c2b..0afaa8da3 100644 --- a/core/modules/url/helpers/index.ts +++ b/core/modules/url/helpers/index.ts @@ -3,6 +3,8 @@ import config from 'config' import { localizedDispatcherRoute, localizedRoute, LocalizedRoute } from '@vue-storefront/core/lib/multistore' import { RouteConfig } from 'vue-router/types/router'; import { RouterManager } from '@vue-storefront/core/lib/router-manager' +import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import { Category } from 'core/modules/catalog-next/types/Category'; export function parametrizeRouteData (routeData: LocalizedRoute, query: { [id: string]: any } | string, storeCodeInPath: string): LocalizedRoute { const parametrizedRoute = Object.assign({}, routeData) @@ -52,8 +54,9 @@ export function normalizeUrlPath (url: string): string { return url } -export function formatCategoryLink (category: { url_path: string, slug: string }): string { - return config.seo.useUrlDispatcher ? ('/' + category.url_path) : ('/c/' + category.slug) +export function formatCategoryLink ({ url_path, slug }: Category, storeCode: string = currentStoreView().storeCode): string { + storeCode ? storeCode += '/' : storeCode = ''; + return config.seo.useUrlDispatcher ? ('/' + storeCode + url_path) : ('/' + storeCode + 'c/' + slug) } export function formatProductLink ( From 2860214bb7742ade26bf56df5f0d229d51dd55ec Mon Sep 17 00:00:00 2001 From: Michal-Dziedzinski Date: Fri, 5 Jul 2019 07:38:09 +0200 Subject: [PATCH 0189/1227] Change isToCompare to isOnCompare --- .../compare/components/{IsToCompare.ts => IsOnCompare.ts} | 8 ++++---- core/modules/compare/components/Product.ts | 4 ++-- core/modules/compare/store/getters.ts | 2 +- docs/guide/components/product.md | 2 +- src/themes/default/components/core/ProductTile.vue | 8 ++++---- .../components/core/blocks/Compare/AddToCompare.vue | 8 ++++---- 6 files changed, 16 insertions(+), 16 deletions(-) rename core/modules/compare/components/{IsToCompare.ts => IsOnCompare.ts} (82%) diff --git a/core/modules/compare/components/IsToCompare.ts b/core/modules/compare/components/IsOnCompare.ts similarity index 82% rename from core/modules/compare/components/IsToCompare.ts rename to core/modules/compare/components/IsOnCompare.ts index 4532afcbd..5ddcd1523 100644 --- a/core/modules/compare/components/IsToCompare.ts +++ b/core/modules/compare/components/IsOnCompare.ts @@ -1,8 +1,8 @@ import { Compare as CompareModule } from '..'; import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin'; -export const IsToCompare = { - name: 'isToCompare', +export const IsOnCompare = { + name: 'IsOnCompare', mixins: [compareMountedMixin], props: { product: { @@ -10,11 +10,11 @@ export const IsToCompare = { type: Object } }, - created () { + created() { CompareModule.register(); }, computed: { - isToCompare (): boolean { + isOnCompare(): boolean { return ( !!this.$store.state.compare.items.find( p => p.sku === this.product.sku diff --git a/core/modules/compare/components/Product.ts b/core/modules/compare/components/Product.ts index 980ce7228..07e2a565f 100644 --- a/core/modules/compare/components/Product.ts +++ b/core/modules/compare/components/Product.ts @@ -5,8 +5,8 @@ export const CompareProduct = { name: 'CompareProduct', mixins: [compareMountedMixin], computed: { - isToCompare (): boolean { - return this.$store.getters['compare/isToCompare'](this.product) + isOnCompare (): boolean { + return this.$store.getters['compare/isOnCompare'](this.product) } }, methods: { diff --git a/core/modules/compare/store/getters.ts b/core/modules/compare/store/getters.ts index 90f316b12..ca2c0d15a 100644 --- a/core/modules/compare/store/getters.ts +++ b/core/modules/compare/store/getters.ts @@ -4,7 +4,7 @@ import CompareState from '../types/CompareState'; const getters: GetterTree = { isEmpty: state => state.items.length === 0, - isToCompare: state => product => state.items.find(p => p.sku === product.sku), + isOnCompare: state => product => state.items.find(p => p.sku === product.sku), isCompareLoaded: state => state.loaded, getCompareProductsCount: state => state.items.length }; diff --git a/docs/guide/components/product.md b/docs/guide/components/product.md index 102696841..b8eb05eac 100644 --- a/docs/guide/components/product.md +++ b/docs/guide/components/product.md @@ -20,7 +20,7 @@ No props - `category` - A computed property representing a category object of the current product. Gets its value from `category/getCurrentCategory` Vuex store getter. - `productName` - A computed property that represents a product name. Gets its value from `category/getCurrentCategory` Vuex store getter. - `productId` - A computed property representing a product ID. Gets its value from `category/getCurrentCategory` Vuex store getter. -- `isToCompare` - A computed property that checks if a given product is in compare list. +- `isOnCompare` - A computed property that checks if a given product is in compare list. - `image` - A computed property that defines an image (thumbnail) that will be shown on the page and its size. - `customAttributes` - this is a subset of `attributesByCode` list of attributes that the current product has. diff --git a/src/themes/default/components/core/ProductTile.vue b/src/themes/default/components/core/ProductTile.vue index 197f7f859..30a922ec9 100644 --- a/src/themes/default/components/core/ProductTile.vue +++ b/src/themes/default/components/core/ProductTile.vue @@ -13,8 +13,8 @@
compare
@@ -67,10 +67,10 @@ import ProductImage from './ProductImage' import AddToWishlist from 'theme/components/core/blocks/Wishlist/AddToWishlist' import AddToCompare from 'theme/components/core/blocks/Compare/AddToCompare' import { IsOnWishlist } from '@vue-storefront/core/modules/wishlist/components/IsOnWishlist' -import { IsToCompare } from '@vue-storefront/core/modules/compare/components/IsToCompare' +import { IsOnCompare } from '@vue-storefront/core/modules/compare/components/IsOnCompare' export default { - mixins: [ProductTile, IsOnWishlist, IsToCompare], + mixins: [ProductTile, IsOnWishlist, IsOnCompare], components: { ProductImage, AddToWishlist, diff --git a/src/themes/default/components/core/blocks/Compare/AddToCompare.vue b/src/themes/default/components/core/blocks/Compare/AddToCompare.vue index f8cc974b0..da996729f 100644 --- a/src/themes/default/components/core/blocks/Compare/AddToCompare.vue +++ b/src/themes/default/components/core/blocks/Compare/AddToCompare.vue @@ -1,13 +1,13 @@ From 4993372461327c2c1c38f24f420b60e6e25a3cdd Mon Sep 17 00:00:00 2001 From: michasik Date: Tue, 9 Jul 2019 15:20:47 +0200 Subject: [PATCH 0241/1227] Changes the names of the stores --- src/themes/default/index.js | 10 +++++----- src/themes/default/store/claims.ts | 2 +- src/themes/default/store/homepage.ts | 2 +- src/themes/default/store/promoted-offers.ts | 2 +- src/themes/default/store/ui.ts | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/themes/default/index.js b/src/themes/default/index.js index 79569a894..d5435b50f 100644 --- a/src/themes/default/index.js +++ b/src/themes/default/index.js @@ -8,10 +8,10 @@ import { RouterManager } from '@vue-storefront/core/lib/router-manager' import { once } from '@vue-storefront/core/helpers' import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage'; -import { store as claimsStore } from 'theme/store/claims' -import { store as homeStore } from 'theme/store/homepage' -import { store as uiStore } from 'theme/store/ui' -import { store as promotedStore } from 'theme/store/promoted-offers' +import { claimsStore } from 'theme/store/claims' +import { homepageStore } from 'theme/store/homepage' +import { uiStore } from 'theme/store/ui' +import { promotedStore } from 'theme/store/promoted-offers' once('__VUE_EXTEND_DROPPOINT_VPB__', () => { Vue.use(VueProgressBar) @@ -28,7 +28,7 @@ function initTheme (app, router, store, config, ssrContext) { Vue.prototype.$db.claimsCollection = initCacheStorage('claims'); store.registerModule('claims', claimsStore); - store.registerModule('homepage', homeStore); + store.registerModule('homepage', homepageStore); store.registerModule('ui', uiStore); store.registerModule('promoted', promotedStore); } diff --git a/src/themes/default/store/claims.ts b/src/themes/default/store/claims.ts index dbc048f08..902de94a5 100644 --- a/src/themes/default/store/claims.ts +++ b/src/themes/default/store/claims.ts @@ -1,7 +1,7 @@ import Vue from 'vue' import { Logger } from '@vue-storefront/core/lib/logger' -export const store = { +export const claimsStore = { namespaced: true, actions: { set (context, { claimCode, value, description }) { diff --git a/src/themes/default/store/homepage.ts b/src/themes/default/store/homepage.ts index 2e716aa3c..a74a5520a 100644 --- a/src/themes/default/store/homepage.ts +++ b/src/themes/default/store/homepage.ts @@ -1,4 +1,4 @@ -export const store = { +export const homepageStore = { namespaced: true, state: { new_collection: [] diff --git a/src/themes/default/store/promoted-offers.ts b/src/themes/default/store/promoted-offers.ts index a07c453f4..17c875c00 100644 --- a/src/themes/default/store/promoted-offers.ts +++ b/src/themes/default/store/promoted-offers.ts @@ -9,7 +9,7 @@ export default interface PromotedOffersState { headImage: Record } -export const store = { +export const promotedStore = { namespaced: true, state: { banners: { diff --git a/src/themes/default/store/ui.ts b/src/themes/default/store/ui.ts index 96c1be28a..e1a6f8c29 100644 --- a/src/themes/default/store/ui.ts +++ b/src/themes/default/store/ui.ts @@ -1,4 +1,4 @@ -export const store = { +export const uiStore = { namespaced: true, state: { sidebar: false, From 474d1024569144a1e0e1a8b5fef900827374144b Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 9 Jul 2019 15:36:01 +0200 Subject: [PATCH 0242/1227] fix multistore --- core/lib/multistore.ts | 4 ++-- packages/module/hooks.ts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 5be807035..4e24a9bfe 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -8,7 +8,7 @@ import merge from 'lodash-es/merge' import { RouterManager } from '@vue-storefront/core/lib/router-manager' import VueRouter, { RouteConfig, RawLocation } from 'vue-router' import config from 'config' -import { beforeStoreViewChangeExecutor, afterStoreViewChangeExecutor } from '@vue-storefront/module/hooks' +import { afterStoreViewChangeExecutor } from '@vue-storefront/module/hooks' export interface LocalizedRoute { path?: string, name?: string, @@ -97,7 +97,7 @@ export function prepareStoreView (storeCode: string): StoreView { loadLanguageAsync(storeView.i18n.defaultLocale) if (storeViewHasChanged) { - storeView = beforeStoreViewChangeExecutor(storeView) + // storeView = beforeStoreViewChangeExecutor(storeView) rootStore.state.storeView = storeView } diff --git a/packages/module/hooks.ts b/packages/module/hooks.ts index 44a9104e6..5e692292e 100644 --- a/packages/module/hooks.ts +++ b/packages/module/hooks.ts @@ -76,3 +76,5 @@ export const beforeStoreViewChangeExecutor = beforeStoreViewChangeGen.executor export const afterStoreViewChange: (storeViewListener: (storeView: {}) => {}) => void = afterStoreViewChangeGen.hook export const afterStoreViewChangeExecutor = afterStoreViewChangeGen.executor + +// Client entry, replaceState, shopping cart loaded, user logged \ No newline at end of file From 0a5e0f4e43542c21b6056d96b3e00c6a7e4526cd Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 9 Jul 2019 15:45:00 +0200 Subject: [PATCH 0243/1227] better typings --- packages/module/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/module/index.ts b/packages/module/index.ts index acea823e4..61f226e8a 100644 --- a/packages/module/index.ts +++ b/packages/module/index.ts @@ -11,7 +11,7 @@ export interface StorefrontModule { ( // because config can't be shared as peer dependency let refs: any = {} -let registeredModules = [] +let registeredModules: StorefrontModule[] = [] function injectReferences (app: any, store: Store, router: VueRouter, config: any): void { refs.app = app From 0815aead506da866b986ec053cd8fdb8c6b44775 Mon Sep 17 00:00:00 2001 From: Vishal Sutariya Date: Wed, 10 Jul 2019 11:32:12 +0530 Subject: [PATCH 0244/1227] Fixed swatches not rendering properly at product detail page --- src/themes/default/pages/Product.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index d3895c4d1..4e940d617 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -293,6 +293,7 @@ export default { this.product.configurable_options.forEach(configurableOption => { const type = configurableOption.attribute_code const filterVariants = configurableOption.values.map(({value_index, label}) => { + label = label ? label : this.options[type].find(config => config.id === value_index).label return {id: value_index, label, type} }) filtersMap[type] = filterVariants From 58e3178fb95f3a6ff5f1af1b93a47d92fd7909ff Mon Sep 17 00:00:00 2001 From: Vishal Sutariya Date: Wed, 10 Jul 2019 11:38:02 +0530 Subject: [PATCH 0245/1227] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index da7242d8e..bc1889733 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Make image proxy url work with relative base url - @cewald (#3158) - Fixed memory leak with enabled dynamicConfigReload - @dimasch (#3075) - Fixed error for the orderhistory null for google-tag-manager extension - @cnviradiya (#3195) +- Fixed swatches not rendering properly at product detail page issue - @vishal-7037 (#3206) ### Changed / Improved - Shipping address is saved as default when not logged in user chooses to create account during checkout - @iwonapiotrowska (#2636) From 29331c3b2065a355ad4caa08ac2067a49c4d470f Mon Sep 17 00:00:00 2001 From: Vishal Sutariya Date: Wed, 10 Jul 2019 11:56:34 +0530 Subject: [PATCH 0246/1227] Updated suggested changes --- src/themes/default/pages/Product.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index 4e940d617..96c147ede 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -293,7 +293,8 @@ export default { this.product.configurable_options.forEach(configurableOption => { const type = configurableOption.attribute_code const filterVariants = configurableOption.values.map(({value_index, label}) => { - label = label ? label : this.options[type].find(config => config.id === value_index).label + let currentVariantLabel = this.options[type].find(config => config.id === value_index).label + label = label ? label : (currentVariantLabel !== null ? currentVariantLabel : null) return {id: value_index, label, type} }) filtersMap[type] = filterVariants From 20d429e45adb554826447c7d1054feaa6a0b01fe Mon Sep 17 00:00:00 2001 From: Vishal Sutariya Date: Wed, 10 Jul 2019 12:01:06 +0530 Subject: [PATCH 0247/1227] Added condition for undefined --- src/themes/default/pages/Product.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index 96c147ede..fa0bcd815 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -294,7 +294,7 @@ export default { const type = configurableOption.attribute_code const filterVariants = configurableOption.values.map(({value_index, label}) => { let currentVariantLabel = this.options[type].find(config => config.id === value_index).label - label = label ? label : (currentVariantLabel !== null ? currentVariantLabel : null) + label = label || (currentVariantLabel !== null && currentVariantLabel !== undefined ? currentVariantLabel : null) return {id: value_index, label, type} }) filtersMap[type] = filterVariants From 441e7dc2451f7351bca8539dfdc334dd9e52bfd0 Mon Sep 17 00:00:00 2001 From: Vishal Sutariya Date: Wed, 10 Jul 2019 12:11:53 +0530 Subject: [PATCH 0248/1227] Updated suggested changes --- src/themes/default/pages/Product.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index fa0bcd815..66d46ff86 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -293,8 +293,8 @@ export default { this.product.configurable_options.forEach(configurableOption => { const type = configurableOption.attribute_code const filterVariants = configurableOption.values.map(({value_index, label}) => { - let currentVariantLabel = this.options[type].find(config => config.id === value_index).label - label = label || (currentVariantLabel !== null && currentVariantLabel !== undefined ? currentVariantLabel : null) + let currentVariant = this.options[type].find(config => config.id === value_index) + label = label || (currentVariant ? currentVariant.label : value_index) return {id: value_index, label, type} }) filtersMap[type] = filterVariants From fc738293f817d6f062eccd39ae3e3ea1b4202098 Mon Sep 17 00:00:00 2001 From: pkarw Date: Wed, 10 Jul 2019 11:13:58 +0200 Subject: [PATCH 0249/1227] CR fixes --- core/helpers/initCacheStorage.ts | 2 +- core/lib/sync/task.ts | 2 +- core/modules/cart/hooks/beforeRegistration.ts | 2 +- core/modules/catalog/hooks/beforeRegistration.ts | 8 ++++---- core/modules/checkout/hooks/beforeRegistration.ts | 2 +- core/modules/cms/hooks/beforeRegistration.ts | 2 +- core/modules/compare/hooks/beforeRegistration.ts | 2 +- core/modules/order/hooks/beforeRegistration.ts | 2 +- core/modules/user/hooks/beforeRegistration.ts | 4 ++-- core/store/lib/storage-manager.ts | 4 ++-- src/modules/claims/hooks/beforeRegistration.ts | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/core/helpers/initCacheStorage.ts b/core/helpers/initCacheStorage.ts index 64669f84d..21fcd87fc 100644 --- a/core/helpers/initCacheStorage.ts +++ b/core/helpers/initCacheStorage.ts @@ -22,7 +22,7 @@ function _prepareCachestorage (key, localised = true) { export function initCacheStorage (key, localised = true, registerStorgeManager = true) { if (registerStorgeManager) { if (!StorageManager.exists(key)) { - return StorageManager.register(key, _prepareCachestorage(key, localised)) + return StorageManager.set(key, _prepareCachestorage(key, localised)) } else { return StorageManager.get(key) } diff --git a/core/lib/sync/task.ts b/core/lib/sync/task.ts index d1dab1547..41f6e64b0 100644 --- a/core/lib/sync/task.ts +++ b/core/lib/sync/task.ts @@ -182,7 +182,7 @@ export function initializeSyncTaskStorage () { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - StorageManager.register('syncTaskCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('syncTaskCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'syncTasks', driver: localForage[config.localForage.defaultDrivers['syncTasks']] diff --git a/core/modules/cart/hooks/beforeRegistration.ts b/core/modules/cart/hooks/beforeRegistration.ts index 976da9f79..1fe99a637 100644 --- a/core/modules/cart/hooks/beforeRegistration.ts +++ b/core/modules/cart/hooks/beforeRegistration.ts @@ -7,7 +7,7 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - StorageManager.register('cartsCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('cartsCollection', new UniversalStorage(localForage.createInstance({ name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', storeName: 'carts', driver: localForage[config.localForage.defaultDrivers['carts']] diff --git a/core/modules/catalog/hooks/beforeRegistration.ts b/core/modules/catalog/hooks/beforeRegistration.ts index 7e1dab1e1..85df57efe 100644 --- a/core/modules/catalog/hooks/beforeRegistration.ts +++ b/core/modules/catalog/hooks/beforeRegistration.ts @@ -7,25 +7,25 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - StorageManager.register('categoriesCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('categoriesCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'categories', driver: localForage[config.localForage.defaultDrivers['categories']] }))) - StorageManager.register('attributesCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('attributesCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'attributes', driver: localForage[config.localForage.defaultDrivers['attributes']] }))) - StorageManager.register('elasticCacheCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('elasticCacheCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'elasticCache', driver: localForage[config.localForage.defaultDrivers['elasticCache']] }), true, config.server.elasticCacheQuota)) - StorageManager.register('productsCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('productsCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'products', driver: localForage[config.localForage.defaultDrivers['products']] diff --git a/core/modules/checkout/hooks/beforeRegistration.ts b/core/modules/checkout/hooks/beforeRegistration.ts index e076097d8..351ab41cb 100644 --- a/core/modules/checkout/hooks/beforeRegistration.ts +++ b/core/modules/checkout/hooks/beforeRegistration.ts @@ -7,7 +7,7 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - StorageManager.register('checkoutFieldsCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('checkoutFieldsCollection', new UniversalStorage(localForage.createInstance({ name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', storeName: 'checkoutFieldValues', driver: localForage[config.localForage.defaultDrivers['checkoutFieldValues']] diff --git a/core/modules/cms/hooks/beforeRegistration.ts b/core/modules/cms/hooks/beforeRegistration.ts index 29acead71..4ef3eb891 100644 --- a/core/modules/cms/hooks/beforeRegistration.ts +++ b/core/modules/cms/hooks/beforeRegistration.ts @@ -7,7 +7,7 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - StorageManager.register('cmsData', new UniversalStorage(localForage.createInstance({ + StorageManager.set('cmsData', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'cms' }))) diff --git a/core/modules/compare/hooks/beforeRegistration.ts b/core/modules/compare/hooks/beforeRegistration.ts index 7723c9b02..7dfecfe4e 100644 --- a/core/modules/compare/hooks/beforeRegistration.ts +++ b/core/modules/compare/hooks/beforeRegistration.ts @@ -7,7 +7,7 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - StorageManager.register('compareCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('compareCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'compare', driver: localForage[config.localForage.defaultDrivers['compare']] diff --git a/core/modules/order/hooks/beforeRegistration.ts b/core/modules/order/hooks/beforeRegistration.ts index 39f984b9b..0f4065608 100644 --- a/core/modules/order/hooks/beforeRegistration.ts +++ b/core/modules/order/hooks/beforeRegistration.ts @@ -9,7 +9,7 @@ import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' export function beforeRegistration ({ Vue, config, store, isServer }) { - StorageManager.register('ordersCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('ordersCollection', new UniversalStorage(localForage.createInstance({ name: 'shop', storeName: 'orders', driver: localForage[config.localForage.defaultDrivers['orders']] diff --git a/core/modules/user/hooks/beforeRegistration.ts b/core/modules/user/hooks/beforeRegistration.ts index 060d0c1f0..ac1c35801 100644 --- a/core/modules/user/hooks/beforeRegistration.ts +++ b/core/modules/user/hooks/beforeRegistration.ts @@ -7,13 +7,13 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - StorageManager.register('usersCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('usersCollection', new UniversalStorage(localForage.createInstance({ name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', storeName: 'user', driver: localForage[config.localForage.defaultDrivers['user']] }))) - StorageManager.register('ordersHistoryCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('ordersHistoryCollection', new UniversalStorage(localForage.createInstance({ name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', storeName: 'ordersHistory', driver: localForage[config.localForage.defaultDrivers['ordersHistory']] diff --git a/core/store/lib/storage-manager.ts b/core/store/lib/storage-manager.ts index 5b39e5b76..074808729 100644 --- a/core/store/lib/storage-manager.ts +++ b/core/store/lib/storage-manager.ts @@ -7,7 +7,7 @@ const StorageManager = { * @param collectionName string name of the cache collection to register * @param collectionInstance UniversalStorage driver */ - register: function (collectionName, collectionInstance: UniversalStorage): UniversalStorage { + set: function (collectionName, collectionInstance: UniversalStorage): UniversalStorage { this[collectionName] = collectionInstance return collectionInstance }, @@ -24,7 +24,7 @@ const StorageManager = { */ get: function (collectionName): UniversalStorage { if (!this.exists(collectionName)) { - return this.register(collectionName, initCacheStorage(collectionName, true, false)) + return this.set(collectionName, initCacheStorage(collectionName, true, false)) } else { return this[collectionName] } diff --git a/src/modules/claims/hooks/beforeRegistration.ts b/src/modules/claims/hooks/beforeRegistration.ts index 0e570ace8..aeebd6429 100644 --- a/src/modules/claims/hooks/beforeRegistration.ts +++ b/src/modules/claims/hooks/beforeRegistration.ts @@ -7,7 +7,7 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - StorageManager.register('claimsCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('claimsCollection', new UniversalStorage(localForage.createInstance({ name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', storeName: 'claims', driver: localForage[config.localForage.defaultDrivers['claims']] From b5587aeca929e099559c12ce3003a28bcf03e12c Mon Sep 17 00:00:00 2001 From: pkarw Date: Wed, 10 Jul 2019 11:27:51 +0200 Subject: [PATCH 0250/1227] StorageMap --- core/store/lib/storage-manager.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/store/lib/storage-manager.ts b/core/store/lib/storage-manager.ts index 074808729..d17879f29 100644 --- a/core/store/lib/storage-manager.ts +++ b/core/store/lib/storage-manager.ts @@ -2,13 +2,14 @@ import UniversalStorage from '@vue-storefront/core/store/lib/storage' import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage'; const StorageManager = { currentStoreCode: '', + storageMap: {}, /** * Register the cache storage - this is required prior to accessing the collection * @param collectionName string name of the cache collection to register * @param collectionInstance UniversalStorage driver */ set: function (collectionName, collectionInstance: UniversalStorage): UniversalStorage { - this[collectionName] = collectionInstance + this.storageMap[collectionName] = collectionInstance return collectionInstance }, /** @@ -16,7 +17,7 @@ const StorageManager = { * @param collectionName string collection name to check */ exists (collectionName): boolean { - return !!this[collectionName] + return !!this.storageMap[collectionName] }, /** * Returns the UniversalStorage driver for specific key @@ -26,7 +27,7 @@ const StorageManager = { if (!this.exists(collectionName)) { return this.set(collectionName, initCacheStorage(collectionName, true, false)) } else { - return this[collectionName] + return this.storageMap[collectionName] } } } From bdaa00af85f71c2e882f399821b303996d55a661 Mon Sep 17 00:00:00 2001 From: pkarw Date: Wed, 10 Jul 2019 11:37:57 +0200 Subject: [PATCH 0251/1227] Unit test fix --- core/helpers/index.ts | 11 ++++++----- core/modules/cart/test/unit/store/actions.spec.ts | 3 +-- core/modules/catalog/hooks/beforeRegistration.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/helpers/index.ts b/core/helpers/index.ts index 7d22f26d7..071d716e6 100644 --- a/core/helpers/index.ts +++ b/core/helpers/index.ts @@ -5,6 +5,12 @@ import Vue from 'vue' import config from 'config' import { sha3_224 } from 'js-sha3' +export const processURLAddress = (url: string = '') => { + if (url.startsWith('/')) return `${config.api.url}${url}` + return url +} + + /** * Create slugify -> "create-slugify" permalink of text * @param {String} text @@ -172,11 +178,6 @@ export const onlineHelper = Vue.observable({ !isServer && window.addEventListener('online', () => { onlineHelper.isOnline = true }) !isServer && window.addEventListener('offline', () => { onlineHelper.isOnline = false }) -export const processURLAddress = (url: string = '') => { - if (url.startsWith('/')) return `${config.api.url}${url}` - return url -} - /* * serial executes Promises sequentially. * @param {funcs} An array of funcs that return promises. diff --git a/core/modules/cart/test/unit/store/actions.spec.ts b/core/modules/cart/test/unit/store/actions.spec.ts index d5321c61e..eb11613bf 100644 --- a/core/modules/cart/test/unit/store/actions.spec.ts +++ b/core/modules/cart/test/unit/store/actions.spec.ts @@ -205,8 +205,7 @@ describe('Cart actions', () => { cartconnectdAt: 1000000000 }, commit: jest.fn(), - dispatch: jest.fn(), - getters: { isCartSyncEnabled: true, isTotalsSyncRequired: true, isSyncRequired: true, isCartConnected: true } + dispatch: jest.fn() }; config.cart = { synchronize: true }; diff --git a/core/modules/catalog/hooks/beforeRegistration.ts b/core/modules/catalog/hooks/beforeRegistration.ts index 8186e9ad8..7fdb76e8e 100644 --- a/core/modules/catalog/hooks/beforeRegistration.ts +++ b/core/modules/catalog/hooks/beforeRegistration.ts @@ -23,5 +23,5 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { name: dbNamePrefix + 'shop', storeName: 'elasticCache', driver: localForage[config.localForage.defaultDrivers['elasticCache']] - }), true, config.server.elasticCacheQuota) + }), true, config.server.elasticCacheQuota)) } From 4dda5590455ccf52ceb581a8dbb7a42504b8f079 Mon Sep 17 00:00:00 2001 From: pkarw Date: Wed, 10 Jul 2019 11:38:38 +0200 Subject: [PATCH 0252/1227] Update index.ts --- core/helpers/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/core/helpers/index.ts b/core/helpers/index.ts index 071d716e6..d37a7babf 100644 --- a/core/helpers/index.ts +++ b/core/helpers/index.ts @@ -10,7 +10,6 @@ export const processURLAddress = (url: string = '') => { return url } - /** * Create slugify -> "create-slugify" permalink of text * @param {String} text From 9b6368ccdc1f9e61c1e9f1349b5cb3e0bae991f7 Mon Sep 17 00:00:00 2001 From: pkarw Date: Wed, 10 Jul 2019 12:39:48 +0200 Subject: [PATCH 0253/1227] Update task.ts --- core/lib/sync/task.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/core/lib/sync/task.ts b/core/lib/sync/task.ts index d0b04c318..f0bf29967 100644 --- a/core/lib/sync/task.ts +++ b/core/lib/sync/task.ts @@ -19,7 +19,6 @@ import { serial } from '@vue-storefront/core/helpers' import config from 'config' import { onlineHelper } from '@vue-storefront/core/helpers' - export function _prepareTask (task) { const taskId = entities.uniqueEntityId(task) // timestamp as a order id is not the best we can do but it's enough task.task_id = taskId.toString() From c8015049e40b122b6f62f5458bac0573bc2bcf16 Mon Sep 17 00:00:00 2001 From: cewald Date: Wed, 10 Jul 2019 13:15:03 +0200 Subject: [PATCH 0254/1227] #3207 Get also none product image thumbnails via API --- CHANGELOG.md | 1 + config/default.json | 5 +++++ core/helpers/index.ts | 22 +++++++++++++++------- core/mixins/thumbnail.js | 21 ++++++++++++++------- docs/guide/basics/configuration.md | 12 ++++++++++-- 5 files changed, 45 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25ff9ab62..f058aaf01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Default storeview settings are now overridden by specific storeview settings - @lukeromanowicz (#3057) - Apache2 proxy header support for store based on host - @resubaka (#3143) - Items count badges for Compare products and wishlist icons at header - @vishal-7037 (#3047) +- Get also none product image thumbnails via API - @cewald (#3207) ### Fixed - Fixed product link in wishlist and microcart - @michasik (#2987) diff --git a/config/default.json b/config/default.json index 8ec8790a6..89e9d3529 100644 --- a/config/default.json +++ b/config/default.json @@ -365,6 +365,11 @@ "images": { "useExactUrlsNoProxy": false, "baseUrl": "https://demo.vuestorefront.io/img/", + "useSpecificImagePaths": true, + "paths": { + "media": "", + "product": "/catalog/product" + }, "productPlaceholder": "/assets/placeholder.jpg" }, "install": { diff --git a/core/helpers/index.ts b/core/helpers/index.ts index 7d22f26d7..2f3545e9d 100644 --- a/core/helpers/index.ts +++ b/core/helpers/index.ts @@ -23,26 +23,34 @@ export function slugify (text) { } /** - * @param relativeUrl - * @param width - * @param height + * @param {string} relativeUrl + * @param {number} width + * @param {number} height + * @param {string} pathType * @returns {*} */ -export function getThumbnailPath (relativeUrl, width, height) { +export function getThumbnailPath (relativeUrl: string, width: number = 0, height: number = 0, pathType: string = 'product'): string { if (config.images.useExactUrlsNoProxy) { return relativeUrl // this is exact url mode } else { + if (config.images.hasOwnProperty('useSpecificImagePaths') && config.images.useSpecificImagePaths) { + if (!Object.keys(config.images.paths).includes(pathType)) { + pathType = 'product' + } + relativeUrl = config.images.paths[pathType] + relativeUrl + } + let resultUrl if (relativeUrl && (relativeUrl.indexOf('://') > 0 || relativeUrl.indexOf('?') > 0 || relativeUrl.indexOf('&') > 0)) relativeUrl = encodeURIComponent(relativeUrl) // proxyUrl is not a url base path but contains {{url}} parameters and so on to use the relativeUrl as a template value and then do the image proxy opertions let baseUrl = processURLAddress(config.images.proxyUrl ? config.images.proxyUrl : config.images.baseUrl) if (baseUrl.indexOf('{{') >= 0) { baseUrl = baseUrl.replace('{{url}}', relativeUrl) - baseUrl = baseUrl.replace('{{width}}', width) - baseUrl = baseUrl.replace('{{height}}', height) + baseUrl = baseUrl.replace('{{width}}', width.toString()) + baseUrl = baseUrl.replace('{{height}}', height.toString()) resultUrl = baseUrl } else { - resultUrl = `${baseUrl}${parseInt(width)}/${parseInt(height)}/resize${relativeUrl}` + resultUrl = `${baseUrl}${width.toString()}/${height.toString()}/resize${relativeUrl}` } return relativeUrl && relativeUrl.indexOf('no_selection') < 0 ? resultUrl : config.images.productPlaceholder || '' } diff --git a/core/mixins/thumbnail.js b/core/mixins/thumbnail.js index 0dafcc09e..014b96551 100644 --- a/core/mixins/thumbnail.js +++ b/core/mixins/thumbnail.js @@ -3,13 +3,20 @@ import { getThumbnailPath as _thumbnailHelper } from '@vue-storefront/core/helpe export const thumbnail = { methods: { /** - * Return thumbnail URL for specific base url - * @param {String} relativeUrl - * @param {Int} width - * @param {Int} height + * Return thumbnail URL for specific base url and path + * @param {string} relativeUrl + * @param {number} width + * @param {number} height + * @param {string} pathType */ - getThumbnail (relativeUrl, width, height) { - return _thumbnailHelper(relativeUrl, width, height) - } + getThumbnail: (relativeUrl, width, height, pathType) => _thumbnailHelper(relativeUrl, width, height, pathType), + + /** + * Return thumbnail URL for specific base url using media path + * @param {string} relativeUrl + * @param {number} width + * @param {number} height + */ + getMediaThumbnail: (relativeUrl, width, height) => _thumbnailHelper(relativeUrl, width, height, 'media') } } diff --git a/docs/guide/basics/configuration.md b/docs/guide/basics/configuration.md index cfee3bff8..a51b96746 100644 --- a/docs/guide/basics/configuration.md +++ b/docs/guide/basics/configuration.md @@ -547,11 +547,19 @@ The `stock` section configures how the Vue Storefront behaves when the product i ```json "images": { "baseUrl": "https://demo.vuestorefront.io/img/", - "productPlaceholder": "/assets/placeholder.jpg" + "productPlaceholder": "/assets/placeholder.jpg", + "useExactUrlsNoProxy": false, + "useSpecificImagePaths": false, + "paths": { + "media": "", + "product": "/catalog/product" + } }, ``` -This section is to set the default base URL of product images. This should be a `vue-storefront-api` URL, pointing to its `/api/img` handler. The Vue Storefront API is in charge of downloading the local image cache from the Magento/Pimcore backend and does the resize/crop/scale operations to optimize the images for mobile devices and the UI. +This section is to set the default base URL of images. This should be a `vue-storefront-api` URL, pointing to its `/api/img` handler. The Vue Storefront API is in charge of downloading the local image cache from the Magento/Pimcore backend and does the resize/crop/scale operations to optimize the images for mobile devices and the UI. + +If you wan't to also show non-product image thumbnails you must set `useSpecificImagePaths` to `true` and remove `/catalog/product` from the end of your API `magento1.imgUrl` or `magento2.imgUrl` setting in your API's config file – e.g.: `http://magento-demo.local/media`. After that you can use the `pathType` parameter of the `getThumbnail()` mixin method to traverse other images than product ones. ## Install From ab41cc2759a647c2dea53212ae553e9a35ad76e2 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Wed, 10 Jul 2019 13:43:52 +0200 Subject: [PATCH 0255/1227] fix tests --- core/modules/cart/test/unit/store/actions.spec.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/modules/cart/test/unit/store/actions.spec.ts b/core/modules/cart/test/unit/store/actions.spec.ts index eb11613bf..54bb9d7ce 100644 --- a/core/modules/cart/test/unit/store/actions.spec.ts +++ b/core/modules/cart/test/unit/store/actions.spec.ts @@ -54,6 +54,11 @@ describe('Cart actions', () => { jest.clearAllMocks(); (rootStore as any).state = {}; Object.keys(config).forEach((key) => { delete config[key]; }); + + config.queues = { + maxNetworkTaskAttempts: 1, + maxCartBypassAttempts: 1 + } }); it('disconnect clears cart token', () => { From 7071b2a9ee27ae62c77d3e8f267a6993502091ff Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Wed, 10 Jul 2019 13:56:13 +0200 Subject: [PATCH 0256/1227] remove unused files --- .../claims/hooks/beforeRegistration.ts | 15 -------- src/modules/claims/store/actions.ts | 35 ------------------- 2 files changed, 50 deletions(-) delete mode 100644 src/modules/claims/hooks/beforeRegistration.ts delete mode 100644 src/modules/claims/store/actions.ts diff --git a/src/modules/claims/hooks/beforeRegistration.ts b/src/modules/claims/hooks/beforeRegistration.ts deleted file mode 100644 index aeebd6429..000000000 --- a/src/modules/claims/hooks/beforeRegistration.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as localForage from 'localforage' -import UniversalStorage from '@vue-storefront/core/store/lib/storage' -import { currentStoreView } from '@vue-storefront/core/lib/multistore' -import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' - -export function beforeRegistration ({ Vue, config, store, isServer }) { - const storeView = currentStoreView() - const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - - StorageManager.set('claimsCollection', new UniversalStorage(localForage.createInstance({ - name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', - storeName: 'claims', - driver: localForage[config.localForage.defaultDrivers['claims']] - }))) -} diff --git a/src/modules/claims/store/actions.ts b/src/modules/claims/store/actions.ts deleted file mode 100644 index 953fe01b0..000000000 --- a/src/modules/claims/store/actions.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ActionTree } from 'vuex' -import RootState from '@vue-storefront/core/types/RootState' -import ClaimsState from '../types/ClaimsState' -import { Logger } from '@vue-storefront/core/lib/logger' -import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' - -const actions: ActionTree = { - set (context, { claimCode, value, description }) { - const claimCollection = StorageManager.get('claimsCollection') - claimCollection.setItem(claimCode, { - code: claimCode, - created_at: new Date(), - value: value, - description: description - }).catch((reason) => { - Logger.error(reason) // it doesn't work on SSR - }) - }, - - unset (context, { claimCode }) { - const claimCollection = StorageManager.get('claimsCollection') - claimCollection.removeItem(claimCode).catch((reason) => { - Logger.error(reason) // it doesn't work on SSR - }) - }, - - check (context, { claimCode }) { - const claimCollection = StorageManager.get('claimsCollection') - return claimCollection.getItem(claimCode).catch((reason) => { - Logger.error(reason) // it doesn't work on SSR - }) - } -} - -export default actions From ac2f53f231099d7c6a2a62050b2bd9ac1b5f0bad Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Wed, 10 Jul 2019 14:02:20 +0200 Subject: [PATCH 0257/1227] merge claimCollection into storageManager --- src/themes/default/index.js | 2 +- src/themes/default/store/claims.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/themes/default/index.js b/src/themes/default/index.js index d5435b50f..593d6e03d 100644 --- a/src/themes/default/index.js +++ b/src/themes/default/index.js @@ -26,7 +26,7 @@ function initTheme (app, router, store, config, ssrContext) { setupMultistoreRoutes(config, router, routes) RouterManager.addRoutes(routes, router) - Vue.prototype.$db.claimsCollection = initCacheStorage('claims'); + initCacheStorage('claimCollection'); store.registerModule('claims', claimsStore); store.registerModule('homepage', homepageStore); store.registerModule('ui', uiStore); diff --git a/src/themes/default/store/claims.ts b/src/themes/default/store/claims.ts index 902de94a5..69a0597ba 100644 --- a/src/themes/default/store/claims.ts +++ b/src/themes/default/store/claims.ts @@ -1,11 +1,11 @@ -import Vue from 'vue' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' import { Logger } from '@vue-storefront/core/lib/logger' export const claimsStore = { namespaced: true, actions: { set (context, { claimCode, value, description }) { - const claimCollection = Vue.prototype.$db.claimsCollection + const claimCollection = StorageManager.get('claimCollection') claimCollection.setItem(claimCode, { code: claimCode, created_at: new Date(), @@ -17,14 +17,14 @@ export const claimsStore = { }, unset (context, { claimCode }) { - const claimCollection = Vue.prototype.$db.claimsCollection + const claimCollection = StorageManager.get('claimCollection') claimCollection.removeItem(claimCode).catch((reason) => { Logger.error(reason) // it doesn't work on SSR }) }, check (context, { claimCode }) { - const claimCollection = Vue.prototype.$db.claimsCollection + const claimCollection = StorageManager.get('claimCollection') return claimCollection.getItem(claimCode).catch((reason) => { Logger.error(reason) // it doesn't work on SSR }) From ded109aa631079bc35d26fea01d1743650bcd27b Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 10 Jul 2019 16:51:47 +0200 Subject: [PATCH 0258/1227] proper moduel npm packe and preparation for per-module hooks --- core/package.json | 5 +++-- packages/cli/boilerplates/module/package.json | 16 ++++++++++------ packages/cli/boilerplates/module/src/index.ts | 11 ++++++----- packages/cli/boilerplates/module/src/store.ts | 2 +- .../cli/boilerplates/module/webpack.config.js | 8 +++++++- packages/module/index.ts | 2 +- packages/module/package.json | 3 ++- src/modules/index.ts | 1 - 8 files changed, 30 insertions(+), 18 deletions(-) diff --git a/core/package.json b/core/package.json index b7fd3f3a8..676c2ca95 100644 --- a/core/package.json +++ b/core/package.json @@ -8,6 +8,7 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { + "@vue-storefront/module": "^0.0.6", "bodybuilder": "2.2.13", "config": "^1.30.0", "express": "^4.14.0", @@ -19,6 +20,7 @@ "redis-tag-cache": "^1.2.1", "remove-accents": "^0.4.2", "uuid": "^3.3.2", + "vsf-g": "../vsf-g", "vue": "^2.6.6", "vue-carousel": "^0.6.9", "vue-i18n": "^8.0.0", @@ -30,8 +32,7 @@ "vue-server-renderer": "^2.6.6", "vuelidate": "^0.6.2", "vuex": "^3.0.1", - "vuex-router-sync": "^5.0.0", - "@vue-storefront/module": "^0.0.4" + "vuex-router-sync": "^5.0.0" }, "devDependencies": { "@vue/test-utils": "^1.0.0-beta.19", diff --git a/packages/cli/boilerplates/module/package.json b/packages/cli/boilerplates/module/package.json index 726852365..1899cda2e 100644 --- a/packages/cli/boilerplates/module/package.json +++ b/packages/cli/boilerplates/module/package.json @@ -1,22 +1,26 @@ { "name": "vsf-package", - "version": "1.0.0", + "version": "1.0.11", "description": "", "main": "dist/main.js", "scripts": { "build": "webpack", "prePublishOnly": "yarn build" }, - "keywords": [], + "keywords": ["vue-storefront"], "author": "", - "license": "ISC", - "dependencies": { - "@vue-storefront/module": "^0.0.3" - }, + "license": "MIT", + "dependencies": {}, "devDependencies": { + "@vue-storefront/module": "^0.0.6", + "@vue-storefront/core": "^1.11.0-rc.1", "ts-loader": "^6.0.4", "typescript": "^3.5.2", "webpack": "^4.35.2", "webpack-cli": "^3.3.5" + }, + "peerDependencies": { + "@vue-storefront/core": "^1.11.0-rc.1", + "@vue-storefront/module": "^0.0.6" } } diff --git a/packages/cli/boilerplates/module/src/index.ts b/packages/cli/boilerplates/module/src/index.ts index b363e336a..d021daff9 100644 --- a/packages/cli/boilerplates/module/src/index.ts +++ b/packages/cli/boilerplates/module/src/index.ts @@ -1,13 +1,14 @@ +import { StorefrontModule } from '@vue-storefront/module' import { afterAppInit } from '@vue-storefront/module/hooks' import { extendStore } from '@vue-storefront/module/helpers' -import { StorefrontModule } from "@vue-storefront/module" -import { ExampleStore } from './store' +import { ExampleStore, ExtendProductStore } from './store' -export const ExampleModule: StorefrontModule = function (app, store, router, config, appConfig) { - // You can access config passed to registerModule via config variable - console.info('From module config: ', config.message) +export const ExampleModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { + // You can access config passed to registerModule via moduleConfig variable // This is how you register new Vuex modules store.registerModule('example', ExampleStore) + // This is how you override properties of currently existing Vuex modules + extendStore('product', ExtendProductStore) // This is how you can hook into various palces of the application afterAppInit(() => console.log('Do something when application is initialized!')) } diff --git a/packages/cli/boilerplates/module/src/store.ts b/packages/cli/boilerplates/module/src/store.ts index 56bd623e2..ba44c5f5c 100644 --- a/packages/cli/boilerplates/module/src/store.ts +++ b/packages/cli/boilerplates/module/src/store.ts @@ -4,7 +4,7 @@ export const ExampleStore = { } } -export const ExtendCart = { +export const ExtendProductStore = { actions: { state: { newprop: null diff --git a/packages/cli/boilerplates/module/webpack.config.js b/packages/cli/boilerplates/module/webpack.config.js index 2f26fa8c4..672e831ff 100644 --- a/packages/cli/boilerplates/module/webpack.config.js +++ b/packages/cli/boilerplates/module/webpack.config.js @@ -1,5 +1,10 @@ module.exports = { + mode: 'production', entry: './src/index.ts', + output: { + libraryTarget: 'umd', + globalObject: 'typeof self !== \'undefined\' ? self : this' + }, resolve: { extensions: ['.ts', '.js', '.json'] }, @@ -7,5 +12,6 @@ module.exports = { rules: [ { test: /\.ts$/, use: ['ts-loader'], exclude: /node_modules/ } ] - } + }, + externals: ['@vue-storefront/module', '@vue-storefront/core'] } diff --git a/packages/module/index.ts b/packages/module/index.ts index 61f226e8a..ce8af4679 100644 --- a/packages/module/index.ts +++ b/packages/module/index.ts @@ -11,7 +11,7 @@ export interface StorefrontModule { ( // because config can't be shared as peer dependency let refs: any = {} -let registeredModules: StorefrontModule[] = [] +let registeredModules: any = [] function injectReferences (app: any, store: Store, router: VueRouter, config: any): void { refs.app = app diff --git a/packages/module/package.json b/packages/module/package.json index 1f1750d26..582b83e5d 100644 --- a/packages/module/package.json +++ b/packages/module/package.json @@ -1,7 +1,7 @@ { "name": "@vue-storefront/module", "sideEffects": "false", - "version": "0.0.4", + "version": "0.0.6", "description": "Vue Storefront modules source", "main": "index.js", "typings": "index.d.ts", @@ -19,6 +19,7 @@ "license": "MIT", "dependencies": { "lodash-es": "^4.17.11", + "vue": "^2.6.10", "vue-router": "^3.0.6", "vuex": "^3.1.1" } diff --git a/src/modules/index.ts b/src/modules/index.ts index 1bdc34feb..5728b2a39 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -27,7 +27,6 @@ import { InstantCheckout } from './instant-checkout' import { OrderHistory } from './order-history' // import { Example } from './module-template' import { registerModule } from '@vue-storefront/module' - // TODO:distributed across proper pages BEFORE 1.11 export function registerNewModules () { registerModule(CatalogModule) From 0c7d9dc486704c9b3a58f2aa53a0d62a5cbf8337 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 10 Jul 2019 17:14:10 +0200 Subject: [PATCH 0259/1227] update signatures --- packages/module/hooks.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/module/hooks.ts b/packages/module/hooks.ts index 5e692292e..21251a82b 100644 --- a/packages/module/hooks.ts +++ b/packages/module/hooks.ts @@ -64,11 +64,11 @@ export const afterAppInitExecutor = afterAppInitGen.executor /** Hook is fired directly before sending order to the server, after all client-side validations * @param orderMutator Inside this function you have access to order object that you can access and modify. It should return order object. */ -export const beforePlaceOrder: (orderMutator: (order: {}) => {}) => void = beforePlaceOrderGen.hook +export const beforePlaceOrder: (orderMutator: (order: any) => any) => void = beforePlaceOrderGen.hook export const beforePlaceOrderExecutor = beforePlaceOrderGen.executor /** Hook is fired right after order has been sent to server */ -export const afterPlaceOrder: (orderListener: ({ order: {}, task: {} }) => void) => void = afterPlaceOrderGen.hook +export const afterPlaceOrder: (orderListener: (order: any) => void) => void = afterPlaceOrderGen.hook export const afterPlaceOrderExecutor = afterPlaceOrderGen.executor export const beforeStoreViewChange: (storeViewMutator: (storeView: {}) => {}) => void = beforeStoreViewChangeGen.hook From 3f4462f8bd0cdea0c59f144397ced6bfa8bcb129 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 10 Jul 2019 17:37:55 +0200 Subject: [PATCH 0260/1227] update modules to use StorageManager --- core/modules/cart/index.ts | 2 +- core/modules/catalog/index.ts | 11 ++++++----- core/modules/checkout/index.ts | 10 +++++----- yarn.lock | 12 +++++++++++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/core/modules/cart/index.ts b/core/modules/cart/index.ts index 9fe68b3f3..1856c31f9 100644 --- a/core/modules/cart/index.ts +++ b/core/modules/cart/index.ts @@ -6,7 +6,7 @@ import Vue from 'vue' import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' export const CartModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { - Vue.prototype.$db.cartsCollection = initCacheStorage('carts') + initCacheStorage('carts') store.registerModule('cart', cartStore) diff --git a/core/modules/catalog/index.ts b/core/modules/catalog/index.ts index 876f4f873..fd9a93b3c 100644 --- a/core/modules/catalog/index.ts +++ b/core/modules/catalog/index.ts @@ -9,20 +9,21 @@ import UniversalStorage from '@vue-storefront/core/store/lib/storage' import { currentStoreView } from '@vue-storefront/core/lib/multistore' import Vue from 'vue' import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export const CatalogModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - Vue.prototype.$db.categoriesCollection = initCacheStorage('categories') - Vue.prototype.$db.attributesCollection = initCacheStorage('attributes') - Vue.prototype.$db.productsCollection = initCacheStorage('products') + initCacheStorage('categories') + initCacheStorage('attributes') + initCacheStorage('products') - Vue.prototype.$db.elasticCacheCollection = new UniversalStorage(localForage.createInstance({ + StorageManager.set('elasticCacheCollection', new UniversalStorage(localForage.createInstance({ name: dbNamePrefix + 'shop', storeName: 'elasticCache', driver: localForage[appConfig.localForage.defaultDrivers['elasticCache']] - }), true, appConfig.server.elasticCacheQuota) + }), true, appConfig.server.elasticCacheQuota)) store.registerModule('product', productModule) store.registerModule('attribute', attributeModule) diff --git a/core/modules/checkout/index.ts b/core/modules/checkout/index.ts index 19c1781f1..7ddd6a5a1 100644 --- a/core/modules/checkout/index.ts +++ b/core/modules/checkout/index.ts @@ -2,12 +2,12 @@ import { StorefrontModule } from '@vue-storefront/module' import { checkoutModule } from './store/checkout' import { paymentModule } from './store/payment' import { shippingModule } from './store/shipping' -import Vue from 'vue' import * as types from './store/checkout/mutation-types' import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export const CheckoutModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { - Vue.prototype.$db.checkoutFieldsCollection = initCacheStorage('checkoutFieldValues') + initCacheStorage('checkoutFieldValues') store.registerModule('shipping', shippingModule) store.registerModule('payment', paymentModule) @@ -19,7 +19,7 @@ export const CheckoutModule: StorefrontModule = function (app, store, router, mo if ( type.endsWith(types.CHECKOUT_SAVE_PERSONAL_DETAILS) ) { - Vue.prototype.$db.checkoutFieldsCollection.setItem('personal-details', state.checkout.personalDetails).catch((reason) => { + StorageManager.get('checkoutFieldsCollection').setItem('personal-details', state.checkout.personalDetails).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } @@ -27,7 +27,7 @@ export const CheckoutModule: StorefrontModule = function (app, store, router, mo if ( type.endsWith(types.CHECKOUT_SAVE_SHIPPING_DETAILS) ) { - Vue.prototype.$db.checkoutFieldsCollection.setItem('shipping-details', state.checkout.shippingDetails).catch((reason) => { + StorageManager.get('checkoutFieldsCollection').setItem('shipping-details', state.checkout.shippingDetails).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } @@ -35,7 +35,7 @@ export const CheckoutModule: StorefrontModule = function (app, store, router, mo if ( type.endsWith(types.CHECKOUT_SAVE_PAYMENT_DETAILS) ) { - Vue.prototype.$db.checkoutFieldsCollection.setItem('payment-details', state.checkout.paymentDetails).catch((reason) => { + StorageManager.get('checkoutFieldsCollection').setItem('payment-details', state.checkout.paymentDetails).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } diff --git a/yarn.lock b/yarn.lock index a6915d632..69966508d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8698,6 +8698,11 @@ lodash-es@^4.17.10: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.11.tgz#145ab4a7ac5c5e52a3531fb4f310255a152b4be0" +lodash-es@^4.17.11: + version "4.17.14" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.14.tgz#12a95a963cc5955683cee3b74e85458954f37ecc" + integrity sha512-7zchRrGa8UZXjD/4ivUWP1867jDkhzTG2c/uj739utSd7O/pFFdxspCemIFKEEjErbcqRzn8nKnGsi7mvTgRPA== + lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -12954,6 +12959,11 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" +vsf-g@../vsf-g: + version "1.0.10" + dependencies: + vuex "^3.1.1" + vue-analytics@^5.16.1: version "5.16.4" resolved "https://registry.yarnpkg.com/vue-analytics/-/vue-analytics-5.16.4.tgz#7f9e197cbc64afac96884a05214b17efaf8e9d09" @@ -13104,7 +13114,7 @@ vue-template-es2015-compiler@^1.6.0, vue-template-es2015-compiler@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825" -vue@^2.5.16, vue@^2.6.6: +vue@^2.5.16, vue@^2.6.10, vue@^2.6.6: version "2.6.10" resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637" From 7c53b70348b6aa2b71c44594f309ebb872179328 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 10 Jul 2019 18:30:01 +0200 Subject: [PATCH 0261/1227] hooks distributed across modules --- core/app.ts | 4 +-- core/hooks.ts | 41 ++++++++++++++++++++++++++ core/lib/multistore.ts | 6 ++-- core/modules/order/hooks.ts | 33 +++++++++++++++++++++ core/modules/order/store/actions.ts | 8 ++--- packages/module/hooks.ts | 45 +++++++++-------------------- 6 files changed, 97 insertions(+), 40 deletions(-) create mode 100644 core/hooks.ts create mode 100644 core/modules/order/hooks.ts diff --git a/core/app.ts b/core/app.ts index cfb38ac62..415d7ca42 100755 --- a/core/app.ts +++ b/core/app.ts @@ -37,7 +37,7 @@ import { registerExtensions as extensions } from 'src/extensions' import globalConfig from 'config' import { injectReferences } from '@vue-storefront/module' -import { afterAppInitExecutor } from '@vue-storefront/module/hooks' +import { coreHooksExecutors } from '@vue-storefront/core/hooks' import { registerNewModules } from 'src/modules'; function createRouter (): VueRouter { @@ -122,7 +122,7 @@ const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vu registerExtensions(extensions, app, router, store, config, ssrContext) registerTheme(globalConfig.theme, app, router, store, globalConfig, ssrContext) - afterAppInitExecutor() + coreHooksExecutors.afterAppInit() // @depreciate will be depreciated in 2,0 EventBus.$emit('application-after-init', app) diff --git a/core/hooks.ts b/core/hooks.ts new file mode 100644 index 000000000..503174402 --- /dev/null +++ b/core/hooks.ts @@ -0,0 +1,41 @@ +import { createListenerHook, createMutatorHook } from '@vue-storefront/module/hooks' + +const { hook: beforeStoreViewChangeHook, executor: beforeStoreViewChangeExecutor }: { + hook: (storeViewMutator: (storeView: any) => any) => void, + executor: any +} = createMutatorHook() + +const { hook: afterStoreViewChangeHook, executor: afterStoreViewChangeExecutor } : { + hook: (storeViewListener: (storeView?: any) => void) => void, + executor: any +} = createListenerHook() + +const { hook: afterAppInitHook, executor: afterAppInitExecutor } : { + hook: (appInitListener: () => void) => void, + executor: any +} = createListenerHook() + +/** Only for internal usage in core */ +const coreHooksExecutors = { + afterAppInit: afterAppInitExecutor, + beforeStoreViewChange: beforeStoreViewChangeExecutor, + afterStoreViewChange: afterStoreViewChangeExecutor +} + +const coreHooks = { + /** Hook is fired right after whole application is initialized. Modules are registered and theme setted up */ + afterAppInit: afterAppInitHook, + /** Hook is fired directly before sending order to the server, after all client-side validations + * @param orderMutator Inside this function you have access to order object that you can access and modify. It should return order object. + */ + beforeStoreViewChange: beforeStoreViewChangeHook, + /** Hook is fired right after order has been sent to server + * @param result `{ order, task }` task is a result of sending order to backend and order is order that has been sent there + */ + afterStoreViewChange: afterStoreViewChangeHook +} + +export { + coreHooks, + coreHooksExecutors +} \ No newline at end of file diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index cf6b9d884..519bb5f38 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -8,7 +8,7 @@ import merge from 'lodash-es/merge' import { RouterManager } from '@vue-storefront/core/lib/router-manager' import VueRouter, { RouteConfig, RawLocation } from 'vue-router' import config from 'config' -import { afterStoreViewChangeExecutor } from '@vue-storefront/module/hooks' +import { coreHooksExecutors } from '@vue-storefront/core/hooks' import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export interface LocalizedRoute { @@ -98,14 +98,14 @@ export function prepareStoreView (storeCode: string): StoreView { loadLanguageAsync(storeView.i18n.defaultLocale) if (storeViewHasChanged) { - // storeView = beforeStoreViewChangeExecutor(storeView) + storeView = coreHooksExecutors.beforeStoreViewChange(storeView) rootStore.state.storeView = storeView } if (storeViewHasChanged || StorageManager.currentStoreCode !== storeCode) { initializeSyncTaskStorage() StorageManager.currentStoreCode = storeView.storeCode } - afterStoreViewChangeExecutor(storeView) + coreHooksExecutors.afterStoreViewChange(storeView) return storeView } diff --git a/core/modules/order/hooks.ts b/core/modules/order/hooks.ts new file mode 100644 index 000000000..0bd8ac327 --- /dev/null +++ b/core/modules/order/hooks.ts @@ -0,0 +1,33 @@ +import { createListenerHook, createMutatorHook } from '@vue-storefront/module/hooks' + +const { hook: beforePlaceOrderHook, executor: beforePlaceOrderExecutor }: { + hook: (orderMutator: (order: any) => any) => void, + executor: any +} = createMutatorHook() + +const { hook: afterPlaceOrderHook, executor: afterPlaceOrdeExecutor } : { + hook: (orderListener: (result: { order: any; task: any }) => void) => void, + executor: any +} = createListenerHook() + +/** Only for internal usage in this module */ +const orderHooksExecutors = { + beforePlaceOrder: beforePlaceOrderExecutor, + afterPlaceOrder: afterPlaceOrdeExecutor +} + +const orderHooks = { + /** Hook is fired directly before sending order to the server, after all client-side validations + * @param orderMutator Inside this function you have access to order object that you can access and modify. It should return order object. + */ + beforePlaceOrder: beforePlaceOrderHook, + /** Hook is fired right after order has been sent to server + * @param result `{ order, task }` task is a result of sending order to backend and order is order that has been sent there + */ + afterPlaceOrder: afterPlaceOrderHook +} + +export { + orderHooks, + orderHooksExecutors +} \ No newline at end of file diff --git a/core/modules/order/store/actions.ts b/core/modules/order/store/actions.ts index f43479b42..cb8cd10f5 100644 --- a/core/modules/order/store/actions.ts +++ b/core/modules/order/store/actions.ts @@ -11,7 +11,7 @@ import { TaskQueue } from '@vue-storefront/core/lib/sync' import { sha3_224 } from 'js-sha3' import { Logger } from '@vue-storefront/core/lib/logger' import config from 'config' -import { beforePlaceOrderExecutor, afterPlaceOrderExecutor } from '@vue-storefront/module/hooks' +import { orderHooksExecutors } from '../hooks' const actions: ActionTree = { /** * Place order - send it to service worker queue @@ -31,11 +31,11 @@ const actions: ActionTree = { } EventBus.$emit('order-before-placed', { order: order }) - order = beforePlaceOrderExecutor(order) + order = orderHooksExecutors.beforePlaceOrder(order) if (!config.orders.directBackendSync || !isOnline()) { commit(types.ORDER_PLACE_ORDER, order) EventBus.$emit('order-after-placed', { order: order }) - afterPlaceOrderExecutor({ order, task: { resultCode: 200 } }) + orderHooksExecutors.beforePlaceOrder({ order, task: { resultCode: 200 } }) return { resultCode: 200 } @@ -56,7 +56,7 @@ const actions: ActionTree = { order.transmited = true commit(types.ORDER_PLACE_ORDER, order) // archive this order but not trasmit it second time commit(types.ORDER_LAST_ORDER_WITH_CONFIRMATION, { order: order, confirmation: task.result }) - afterPlaceOrderExecutor({ order, task }) + orderHooksExecutors.afterPlaceOrder({ order, task }) EventBus.$emit('order-after-placed', { order: order, confirmation: task.result }) return task diff --git a/packages/module/hooks.ts b/packages/module/hooks.ts index 21251a82b..4f71015ab 100644 --- a/packages/module/hooks.ts +++ b/packages/module/hooks.ts @@ -38,11 +38,15 @@ function createMutatorHook () { } function executor (rawOutput: any) { - let modifiedOutput = null - mutators.forEach(fn => { - modifiedOutput = fn(rawOutput) - }) - return modifiedOutput + if (mutators.length > 0) { + let modifiedOutput = null + mutators.forEach(fn => { + modifiedOutput = fn(rawOutput) + }) + return modifiedOutput + } else { + return rawOutput + } } return { @@ -51,30 +55,9 @@ function createMutatorHook () { } } -const afterAppInitGen = createListenerHook() -const beforePlaceOrderGen = createMutatorHook() -const afterPlaceOrderGen = createListenerHook() -const beforeStoreViewChangeGen = createMutatorHook() -const afterStoreViewChangeGen = createListenerHook() - -/** Hook is fired right after whole application is initialized. Modules are registered and theme setted up */ -export const afterAppInit = afterAppInitGen.hook -export const afterAppInitExecutor = afterAppInitGen.executor - -/** Hook is fired directly before sending order to the server, after all client-side validations - * @param orderMutator Inside this function you have access to order object that you can access and modify. It should return order object. -*/ -export const beforePlaceOrder: (orderMutator: (order: any) => any) => void = beforePlaceOrderGen.hook -export const beforePlaceOrderExecutor = beforePlaceOrderGen.executor - -/** Hook is fired right after order has been sent to server */ -export const afterPlaceOrder: (orderListener: (order: any) => void) => void = afterPlaceOrderGen.hook -export const afterPlaceOrderExecutor = afterPlaceOrderGen.executor - -export const beforeStoreViewChange: (storeViewMutator: (storeView: {}) => {}) => void = beforeStoreViewChangeGen.hook -export const beforeStoreViewChangeExecutor = beforeStoreViewChangeGen.executor - -export const afterStoreViewChange: (storeViewListener: (storeView: {}) => {}) => void = afterStoreViewChangeGen.hook -export const afterStoreViewChangeExecutor = afterStoreViewChangeGen.executor +export { + createListenerHook, + createMutatorHook +} -// Client entry, replaceState, shopping cart loaded, user logged \ No newline at end of file +// TODO: Hooks for Client entry, replaceState (can be part of client entry), shopping cart loaded, user logged \ No newline at end of file From c064b29d3907aee94c9951ad40012ba15bc591bd Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 10 Jul 2019 18:31:06 +0200 Subject: [PATCH 0262/1227] exlint fix --- core/hooks.ts | 22 +++++++++++----------- core/modules/order/hooks.ts | 20 ++++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/core/hooks.ts b/core/hooks.ts index 503174402..1046f3f44 100644 --- a/core/hooks.ts +++ b/core/hooks.ts @@ -2,17 +2,17 @@ import { createListenerHook, createMutatorHook } from '@vue-storefront/module/ho const { hook: beforeStoreViewChangeHook, executor: beforeStoreViewChangeExecutor }: { hook: (storeViewMutator: (storeView: any) => any) => void, - executor: any + executor: any } = createMutatorHook() -const { hook: afterStoreViewChangeHook, executor: afterStoreViewChangeExecutor } : { +const { hook: afterStoreViewChangeHook, executor: afterStoreViewChangeExecutor }: { hook: (storeViewListener: (storeView?: any) => void) => void, - executor: any + executor: any } = createListenerHook() -const { hook: afterAppInitHook, executor: afterAppInitExecutor } : { +const { hook: afterAppInitHook, executor: afterAppInitExecutor }: { hook: (appInitListener: () => void) => void, - executor: any + executor: any } = createListenerHook() /** Only for internal usage in core */ @@ -25,17 +25,17 @@ const coreHooksExecutors = { const coreHooks = { /** Hook is fired right after whole application is initialized. Modules are registered and theme setted up */ afterAppInit: afterAppInitHook, - /** Hook is fired directly before sending order to the server, after all client-side validations + /** Hook is fired directly before sending order to the server, after all client-side validations * @param orderMutator Inside this function you have access to order object that you can access and modify. It should return order object. */ - beforeStoreViewChange: beforeStoreViewChangeHook, - /** Hook is fired right after order has been sent to server + beforeStoreViewChange: beforeStoreViewChangeHook, + /** Hook is fired right after order has been sent to server * @param result `{ order, task }` task is a result of sending order to backend and order is order that has been sent there */ afterStoreViewChange: afterStoreViewChangeHook } export { - coreHooks, - coreHooksExecutors -} \ No newline at end of file + coreHooks, + coreHooksExecutors +} diff --git a/core/modules/order/hooks.ts b/core/modules/order/hooks.ts index 0bd8ac327..4cc1ce9ea 100644 --- a/core/modules/order/hooks.ts +++ b/core/modules/order/hooks.ts @@ -2,12 +2,12 @@ import { createListenerHook, createMutatorHook } from '@vue-storefront/module/ho const { hook: beforePlaceOrderHook, executor: beforePlaceOrderExecutor }: { hook: (orderMutator: (order: any) => any) => void, - executor: any + executor: any } = createMutatorHook() -const { hook: afterPlaceOrderHook, executor: afterPlaceOrdeExecutor } : { - hook: (orderListener: (result: { order: any; task: any }) => void) => void, - executor: any +const { hook: afterPlaceOrderHook, executor: afterPlaceOrdeExecutor }: { + hook: (orderListener: (result: { order: any, task: any }) => void) => void, + executor: any } = createListenerHook() /** Only for internal usage in this module */ @@ -17,17 +17,17 @@ const orderHooksExecutors = { } const orderHooks = { - /** Hook is fired directly before sending order to the server, after all client-side validations + /** Hook is fired directly before sending order to the server, after all client-side validations * @param orderMutator Inside this function you have access to order object that you can access and modify. It should return order object. */ - beforePlaceOrder: beforePlaceOrderHook, - /** Hook is fired right after order has been sent to server + beforePlaceOrder: beforePlaceOrderHook, + /** Hook is fired right after order has been sent to server * @param result `{ order, task }` task is a result of sending order to backend and order is order that has been sent there */ afterPlaceOrder: afterPlaceOrderHook } export { - orderHooks, - orderHooksExecutors -} \ No newline at end of file + orderHooks, + orderHooksExecutors +} From 3551b2b3ab47c795b2efecf1a17004d50f228a0b Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 10 Jul 2019 18:46:32 +0200 Subject: [PATCH 0263/1227] add descriptions for storeView --- core/hooks.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/hooks.ts b/core/hooks.ts index 1046f3f44..ea93b003d 100644 --- a/core/hooks.ts +++ b/core/hooks.ts @@ -25,12 +25,12 @@ const coreHooksExecutors = { const coreHooks = { /** Hook is fired right after whole application is initialized. Modules are registered and theme setted up */ afterAppInit: afterAppInitHook, - /** Hook is fired directly before sending order to the server, after all client-side validations - * @param orderMutator Inside this function you have access to order object that you can access and modify. It should return order object. + /** Hook is fired directly before changing current storeView (multistrore) + * @param storeView Inside this function you have access to order object that you can access and modify. It should return order object. */ beforeStoreViewChange: beforeStoreViewChangeHook, - /** Hook is fired right after order has been sent to server - * @param result `{ order, task }` task is a result of sending order to backend and order is order that has been sent there + /** Hook is fired right after storeView (multistore) is changed + * @param storeVire current storeVire */ afterStoreViewChange: afterStoreViewChangeHook } From e788ebd4f675a54273b954c807f66c6958560150 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 10 Jul 2019 18:47:07 +0200 Subject: [PATCH 0264/1227] typo fix ;) --- core/hooks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/hooks.ts b/core/hooks.ts index ea93b003d..26cb21d89 100644 --- a/core/hooks.ts +++ b/core/hooks.ts @@ -30,7 +30,7 @@ const coreHooks = { */ beforeStoreViewChange: beforeStoreViewChangeHook, /** Hook is fired right after storeView (multistore) is changed - * @param storeVire current storeVire + * @param storeView current storeVire */ afterStoreViewChange: afterStoreViewChangeHook } From 4288063cdac798eb768784d6ac84eb55d847a15f Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 10 Jul 2019 18:47:22 +0200 Subject: [PATCH 0265/1227] typo fix ;) --- core/hooks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/hooks.ts b/core/hooks.ts index 26cb21d89..f9c23218d 100644 --- a/core/hooks.ts +++ b/core/hooks.ts @@ -30,7 +30,7 @@ const coreHooks = { */ beforeStoreViewChange: beforeStoreViewChangeHook, /** Hook is fired right after storeView (multistore) is changed - * @param storeView current storeVire + * @param storeView current storeView */ afterStoreViewChange: afterStoreViewChangeHook } From bff1e424e076dbd77ab87b727703c27d72095861 Mon Sep 17 00:00:00 2001 From: Przemyslaw Spaczek Date: Wed, 10 Jul 2019 20:18:43 +0200 Subject: [PATCH 0266/1227] images aspect ratio fix poc --- .../default/components/core/ProductImage.vue | 66 +++++++++++-------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/themes/default/components/core/ProductImage.vue b/src/themes/default/components/core/ProductImage.vue index a72f9e231..cf2196f39 100644 --- a/src/themes/default/components/core/ProductImage.vue +++ b/src/themes/default/components/core/ProductImage.vue @@ -1,13 +1,15 @@ @@ -58,7 +55,15 @@ export default { lowerQualityImage: false, lowerQualityImageError: false, highQualityImage: false, - highQualityImageError: false + highQualityImageError: false, + basic: true + } + }, + watch: { + lowerQualityImage (state) { + if (state) { + this.basic = this.$refs.lQ.naturalWidth < this.$refs.lQ.naturalHeight; + } } }, computed: { @@ -71,6 +76,10 @@ export default { showHighQuality () { return this.highQualityImage }, + imageRatio () { + const {width, height} = this.$store.state.config.products.gallery + return `${height / (width / 100)}%` + }, isOnline (value) { return onlineHelper.isOnline } @@ -85,25 +94,30 @@ export default { diff --git a/src/themes/default/components/core/blocks/Microcart/Product.vue b/src/themes/default/components/core/blocks/Microcart/Product.vue index 59644a65d..fc70a6f50 100644 --- a/src/themes/default/components/core/blocks/Microcart/Product.vue +++ b/src/themes/default/components/core/blocks/Microcart/Product.vue @@ -1,9 +1,7 @@ @@ -202,20 +196,20 @@ $color-white: color(white); font-size: 12px; } -.product-cover{ +.product-cover { overflow: hidden; max-height: 300px; - &__thumb{ + &__thumb { padding-bottom: calc(143.88% / (164.5 / 100)); - @media screen and (min-width: 768px){ + @media screen and (min-width: 768px) { padding-bottom: calc(300% / (276.5 / 100)); } - opacity: .8; + opacity: 0.8; will-change: opacity, transform; - transition: .3s opacity $motion-main, .3s transform $motion-main; + transition: 0.3s opacity $motion-main, 0.3s transform $motion-main; } - &:hover{ - .product-cover__thumb{ + &:hover { + .product-cover__thumb { opacity: 1; transform: scale(1.1); } @@ -224,7 +218,7 @@ $color-white: color(white); opacity: 0.8; } } - &.sale{ + &.sale { &::after { @extend %label; content: 'Sale'; From b4dbc2e2e7a62bd95f037d5b1fd366daab147af6 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 16 Jul 2019 13:08:51 +0200 Subject: [PATCH 0322/1227] rewrite breadcrumbs module to new format --- core/modules-entry.ts | 2 -- core/modules/breadcrumbs/index.ts | 15 +++++------ core/modules/breadcrumbs/store/index.ts | 2 +- src/modules/index.ts | 5 ++-- .../components/ExtensionComponent.ts | 26 ------------------- .../hooks/afterRegistration.ts | 6 ----- .../hooks/beforeRegistration.ts | 18 ------------- src/modules/module-template/index.ts | 20 -------------- .../module-template/pages/ExtensionPage.vue | 18 ------------- .../module-template/queries/exampleQuery.ts | 12 --------- .../module-template/router/afterEach.ts | 8 ------ .../module-template/router/beforeEach.ts | 10 ------- src/modules/module-template/store/actions.ts | 21 --------------- src/modules/module-template/store/getters.ts | 4 --- src/modules/module-template/store/index.ts | 14 ---------- .../module-template/store/mutation-types.ts | 2 -- .../module-template/store/mutations.ts | 11 -------- src/modules/module-template/store/plugin.ts | 10 ------- src/modules/module-template/store/state.ts | 5 ---- .../module-template/types/ExampleState.ts | 5 ---- 20 files changed, 10 insertions(+), 204 deletions(-) delete mode 100644 src/modules/module-template/components/ExtensionComponent.ts delete mode 100644 src/modules/module-template/hooks/afterRegistration.ts delete mode 100644 src/modules/module-template/hooks/beforeRegistration.ts delete mode 100644 src/modules/module-template/index.ts delete mode 100644 src/modules/module-template/pages/ExtensionPage.vue delete mode 100644 src/modules/module-template/queries/exampleQuery.ts delete mode 100644 src/modules/module-template/router/afterEach.ts delete mode 100644 src/modules/module-template/router/beforeEach.ts delete mode 100644 src/modules/module-template/store/actions.ts delete mode 100644 src/modules/module-template/store/getters.ts delete mode 100644 src/modules/module-template/store/index.ts delete mode 100644 src/modules/module-template/store/mutation-types.ts delete mode 100644 src/modules/module-template/store/mutations.ts delete mode 100644 src/modules/module-template/store/plugin.ts delete mode 100644 src/modules/module-template/store/state.ts delete mode 100644 src/modules/module-template/types/ExampleState.ts diff --git a/core/modules-entry.ts b/core/modules-entry.ts index 8908445e7..ef5ade955 100644 --- a/core/modules-entry.ts +++ b/core/modules-entry.ts @@ -4,11 +4,9 @@ import { Cms } from './modules/cms' import { Order } from './modules/order' import { User } from './modules/user' import { registerModules } from 'src/modules' -import { Breadcrumbs } from './modules/breadcrumbs' // @deprecated from 2.0, use registerModule instead export const enabledModules: VueStorefrontModule[] = [ - Breadcrumbs, Cms, Order, User, diff --git a/core/modules/breadcrumbs/index.ts b/core/modules/breadcrumbs/index.ts index 6530e8cad..e85c2585d 100644 --- a/core/modules/breadcrumbs/index.ts +++ b/core/modules/breadcrumbs/index.ts @@ -1,10 +1,7 @@ -import { module } from './store' -import { createModule } from '@vue-storefront/core/lib/module' +import { breadcrumbsStore } from './store' +import { StorefrontModule } from '@vue-storefront/module' -export const KEY = 'breadcrumbs' -export const Breadcrumbs = createModule({ - key: KEY, - store: { modules: [ - { key: KEY, module: module } - ] } -}) + +export const BreadcrumbsModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { + store.registerModule('breadcrumbs', breadcrumbsStore) +} diff --git a/core/modules/breadcrumbs/store/index.ts b/core/modules/breadcrumbs/store/index.ts index c29ec4e40..b18501a71 100644 --- a/core/modules/breadcrumbs/store/index.ts +++ b/core/modules/breadcrumbs/store/index.ts @@ -1,5 +1,5 @@ -export const module = { +export const breadcrumbsStore = { namespaced: true, state: { routes: [], diff --git a/src/modules/index.ts b/src/modules/index.ts index 1c8e30fbb..147600776 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -1,4 +1,3 @@ -// import { extendModule } from '@vue-storefront/core/lib/module' import { VueStorefrontModule } from '@vue-storefront/core/lib/module' import { CatalogModule } from '@vue-storefront/core/modules/catalog' import { CatalogNextModule } from '@vue-storefront/core/modules/catalog-next' @@ -12,6 +11,7 @@ import { NewsletterModule } from '@vue-storefront/core/modules/newsletter' import { NotificationModule } from '@vue-storefront/core/modules/notification' import { RecentlyViewedModule } from '@vue-storefront/core/modules/recently-viewed' import { UrlModule } from '@vue-storefront/core/modules/url' +import { BreadcrumbsModule } from '@vue-storefront/core/modules/breadcrumbs' // import { GoogleAnalyticsModule } from './google-analytics'; // import { HotjarModule } from './hotjar'; import { GoogleTagManagerModule } from './google-tag-manager'; @@ -20,8 +20,8 @@ import { PaymentBackendMethodsModule } from './payment-backend-methods'; import { PaymentCashOnDeliveryModule } from './payment-cash-on-delivery'; import { RawOutputExampleModule } from './raw-output-example' import { InstantCheckoutModule } from './instant-checkout' -// import { Example } from './module-template' import { registerModule } from '@vue-storefront/module' + // TODO:distributed across proper pages BEFORE 1.11 export function registerNewModules () { registerModule(CatalogModule) @@ -44,6 +44,7 @@ export function registerNewModules () { registerModule(UrlModule) registerModule(CatalogNextModule) registerModule(CompareModule) + registerModule(BreadcrumbsModule) } // Deprecated API, will be removed in 2.0 diff --git a/src/modules/module-template/components/ExtensionComponent.ts b/src/modules/module-template/components/ExtensionComponent.ts deleted file mode 100644 index 85f287fe2..000000000 --- a/src/modules/module-template/components/ExtensionComponent.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * User list component example. Try to document components like this. You can also export .vue files if you want to provide baseline template. - * - * #### Data - * - `users: String[]` - list of users - * - * #### Methods - * - `addUser(name: Function, success?: Function, failure?: Function)` adds new user to the list, calls failure if user with the same name is already on list - */ -export const ExtensionComponent = { - name: 'ExtensionComponent', - computed: { - users () { - return this.$store.state.example.user - } - }, - methods: { - addUser (user: Record, success: (res: Record) => void, failure: (err: Error) => void): void { - this.$store.dispatch('example/addUser', user).then(res => { - success(res) - }).catch(err => { - failure(err) - }) - } - } -} diff --git a/src/modules/module-template/hooks/afterRegistration.ts b/src/modules/module-template/hooks/afterRegistration.ts deleted file mode 100644 index 8179bdb1a..000000000 --- a/src/modules/module-template/hooks/afterRegistration.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Logger } from '@vue-storefront/core/lib/logger' - -// This function will be fired both on server and client side context after registering other parts of the module -export function afterRegistration ({ Vue, config, store, isServer }) { - if (isServer) Logger.info('This will be called after extension registration and only on client side')() -} diff --git a/src/modules/module-template/hooks/beforeRegistration.ts b/src/modules/module-template/hooks/beforeRegistration.ts deleted file mode 100644 index cb495b3a0..000000000 --- a/src/modules/module-template/hooks/beforeRegistration.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { AsyncDataLoader } from '@vue-storefront/core/lib/async-data-loader' - -// This function will be fired both on server and client side context before registering other parts of the module -export function beforeRegistration ({ Vue, config, store, isServer }) { - if (!isServer) console.info('This will be called before extension registration and only on client side') - AsyncDataLoader.push({ // this is an example showing how to call data loader from another module - execute: ({ route, store, context }) => { - return new Promise((resolve, reject) => { - if (route.name === 'configurable-product') { - store.state.exampleDataFetchedByLoader = 'this is just example data fetched by loader on configurable product page' - } else { - store.state.exampleDataFetchedByLoader = 'this is just example data fetched by loader on any page' - } - resolve(null) - }) - } - }) -} diff --git a/src/modules/module-template/index.ts b/src/modules/module-template/index.ts deleted file mode 100644 index 3c3216bc8..000000000 --- a/src/modules/module-template/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Read more about modules: https://github.com/DivanteLtd/vue-storefront/blob/master/doc/api-modules/about-modules.md -import { module } from './store' -import { plugin } from './store/plugin' -import { beforeRegistration } from './hooks/beforeRegistration' -import { afterRegistration } from './hooks/afterRegistration' -import { createModule } from '@vue-storefront/core/lib/module' -import { beforeEach } from './router/beforeEach' -import { afterEach } from './router/afterEach' -import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' - -export const KEY = 'example' -export const cacheStorage = initCacheStorage(KEY) -export const Example = createModule({ - key: KEY, - store: { modules: [{ key: KEY, module }], plugin }, - beforeRegistration, - afterRegistration, - router: { beforeEach, afterEach } -} -) diff --git a/src/modules/module-template/pages/ExtensionPage.vue b/src/modules/module-template/pages/ExtensionPage.vue deleted file mode 100644 index 25f7f0299..000000000 --- a/src/modules/module-template/pages/ExtensionPage.vue +++ /dev/null @@ -1,18 +0,0 @@ - - - - - diff --git a/src/modules/module-template/queries/exampleQuery.ts b/src/modules/module-template/queries/exampleQuery.ts deleted file mode 100644 index 3dcc12ab7..000000000 --- a/src/modules/module-template/queries/exampleQuery.ts +++ /dev/null @@ -1,12 +0,0 @@ -// GraphQL and ES queries exposed by this module -import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' - -export function exampleQuery (queryText, queryFilter) { - let exampleQuery = new SearchQuery() - - exampleQuery = exampleQuery - .setSearchText(queryText) - .applyFilter(queryFilter) - - return exampleQuery -} diff --git a/src/modules/module-template/router/afterEach.ts b/src/modules/module-template/router/afterEach.ts deleted file mode 100644 index 5d1689035..000000000 --- a/src/modules/module-template/router/afterEach.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This function will be executed after entering each route. -// See https://router.vuejs.org/guide/advanced/navigation-guards.html#global-after-hooks -import { Route } from 'vue-router' -import { Logger } from '@vue-storefront/core/lib/logger' - -export function afterEach (to: Route, from: Route) { - Logger.info(`We have just entered ${to.name} from ${from.name}.`)() -} diff --git a/src/modules/module-template/router/beforeEach.ts b/src/modules/module-template/router/beforeEach.ts deleted file mode 100644 index 325247fe4..000000000 --- a/src/modules/module-template/router/beforeEach.ts +++ /dev/null @@ -1,10 +0,0 @@ -// This function will be executed before entering each route. -// It's important to have 'next()'. It enables navigation to new route. -// See https://router.vuejs.org/guide/advanced/navigation-guards.html#global-guards -import { Route } from 'vue-router' -import { Logger } from '@vue-storefront/core/lib/logger' - -export function beforeEach (to: Route, from: Route, next) { - Logger.info('We are going to visit' + to.name)() - next() -} diff --git a/src/modules/module-template/store/actions.ts b/src/modules/module-template/store/actions.ts deleted file mode 100644 index f5fe08ba0..000000000 --- a/src/modules/module-template/store/actions.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ExampleState } from '../types/ExampleState' -import { ActionTree } from 'vuex'; -import * as types from './mutation-types' -// you can use this storage if you want to enable offline capabilities -import { cacheStorage } from '../' - -// it's a good practice for all actions to return Promises with effect of their execution -export const actions: ActionTree = { - // if you want to use cache in your module you can load cached data like this - async loadUsers ({ commit }) { - const userData = cacheStorage.getItem('user') - commit(types.SET_USERS, userData) - return userData - }, - // if you are using cache in your module it's a good practice to allow develoeprs to choose either to use it or not - async addUser ({ commit }, { user, useCache = false }) { - commit(types.ADD_USER, user) - if (useCache) cacheStorage.setItem('user', user) - return user - } -} diff --git a/src/modules/module-template/store/getters.ts b/src/modules/module-template/store/getters.ts deleted file mode 100644 index d04186614..000000000 --- a/src/modules/module-template/store/getters.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { ExampleState } from '../types/ExampleState' -import { GetterTree } from 'vuex'; - -export const getters: GetterTree = {} diff --git a/src/modules/module-template/store/index.ts b/src/modules/module-template/store/index.ts deleted file mode 100644 index 463e2f3ba..000000000 --- a/src/modules/module-template/store/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Module } from 'vuex' -import { ExampleState } from '../types/ExampleState' -import { mutations } from './mutations' -import { getters } from './getters' -import { actions } from './actions' -import { state } from './state' - -export const module: Module = { - namespaced: true, - mutations, - actions, - getters, - state -} diff --git a/src/modules/module-template/store/mutation-types.ts b/src/modules/module-template/store/mutation-types.ts deleted file mode 100644 index 508f944d8..000000000 --- a/src/modules/module-template/store/mutation-types.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const SET_USERS = 'TEMPLATE/SET_USERS' -export const ADD_USER = 'TEMPLATE/SET_USER' diff --git a/src/modules/module-template/store/mutations.ts b/src/modules/module-template/store/mutations.ts deleted file mode 100644 index e837caccc..000000000 --- a/src/modules/module-template/store/mutations.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { MutationTree } from 'vuex' -import * as types from './mutation-types' - -export const mutations: MutationTree = { - [types.SET_USERS] (state, payload) { - state.users = payload - }, - [types.ADD_USER] (state, payload) { - state.users.push(payload) - } -} diff --git a/src/modules/module-template/store/plugin.ts b/src/modules/module-template/store/plugin.ts deleted file mode 100644 index b3e3bd29e..000000000 --- a/src/modules/module-template/store/plugin.ts +++ /dev/null @@ -1,10 +0,0 @@ -import * as types from './mutation-types' -import { Logger } from '@vue-storefront/core/lib/logger' - -export function plugin (mutation, state) { - if (types[mutation.type]) { - Logger.info('performed mutation from this store with type' + mutation.type)() - } else { - Logger.info('performed mutation from other store with type' + mutation.type)() - } -} diff --git a/src/modules/module-template/store/state.ts b/src/modules/module-template/store/state.ts deleted file mode 100644 index 3f92fa923..000000000 --- a/src/modules/module-template/store/state.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleState } from '../types/ExampleState' - -export const state: ExampleState = { - users: null -} diff --git a/src/modules/module-template/types/ExampleState.ts b/src/modules/module-template/types/ExampleState.ts deleted file mode 100644 index bb9b5a2bb..000000000 --- a/src/modules/module-template/types/ExampleState.ts +++ /dev/null @@ -1,5 +0,0 @@ -// This object should represent structure of your modules Vuex state -// It's a good practice is to name this interface accordingly to the KET (for example mailchimpState) -export interface ExampleState { - users: string[] -} From ddfde6ef3daf887234148a20fbc23eca16df02ac Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Tue, 16 Jul 2019 13:36:26 +0200 Subject: [PATCH 0323/1227] Add doc comments to thumbail.js --- core/mixins/thumbnail.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/mixins/thumbnail.js b/core/mixins/thumbnail.js index e57f9248a..0ffff030f 100644 --- a/core/mixins/thumbnail.js +++ b/core/mixins/thumbnail.js @@ -8,6 +8,7 @@ export const thumbnail = { * @param {number} width * @param {number} height * @param {string} pathType + * @returns {string} */ getThumbnail: (relativeUrl, width, height, pathType) => getThumbnailPath(relativeUrl, width, height, pathType), @@ -16,6 +17,7 @@ export const thumbnail = { * @param {string} relativeUrl * @param {number} width * @param {number} height + * @returns {string} */ getMediaThumbnail: (relativeUrl, width, height) => getThumbnailPath(relativeUrl, width, height, 'media') } From c4d73696e036c644dfad5a035cd2608e3e820c6d Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Tue, 16 Jul 2019 13:36:35 +0200 Subject: [PATCH 0324/1227] Add doc comments to index.ts --- core/helpers/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/helpers/index.ts b/core/helpers/index.ts index c096ec25a..654f6b8b0 100644 --- a/core/helpers/index.ts +++ b/core/helpers/index.ts @@ -32,7 +32,7 @@ export function slugify (text) { * @param {number} width * @param {number} height * @param {string} pathType - * @returns {*} + * @returns {string} */ export function getThumbnailPath (relativeUrl: string, width: number = 0, height: number = 0, pathType: string = 'product'): string { if (config.images.useExactUrlsNoProxy) { From 8b950d4e14f9e65e74a190424bb86805b180803e Mon Sep 17 00:00:00 2001 From: patzick Date: Tue, 16 Jul 2019 13:53:20 +0200 Subject: [PATCH 0325/1227] merge release branch --- core/lib/search/adapter/api/searchAdapter.ts | 8 ++++---- core/lib/search/adapter/graphql/searchAdapter.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/lib/search/adapter/api/searchAdapter.ts b/core/lib/search/adapter/api/searchAdapter.ts index 4f566dea6..93d9c02ab 100644 --- a/core/lib/search/adapter/api/searchAdapter.ts +++ b/core/lib/search/adapter/api/searchAdapter.ts @@ -80,10 +80,10 @@ export class SearchAdapter { }, body: config.elasticsearch.queryMethod === 'POST' ? JSON.stringify(ElasticsearchQueryBody) : null }) - .then(resp => { return resp.json() }) - .catch(error => { - throw new Error('FetchError in request to ES: ' + error.toString()) - }) + .then(resp => { return resp.json() }) + .catch(error => { + throw new Error('FetchError in request to ES: ' + error.toString()) + }) } public handleResult (resp, type, start = 0, size = 50): SearchResponse { diff --git a/core/lib/search/adapter/graphql/searchAdapter.ts b/core/lib/search/adapter/graphql/searchAdapter.ts index acc573ad9..55822decd 100644 --- a/core/lib/search/adapter/graphql/searchAdapter.ts +++ b/core/lib/search/adapter/graphql/searchAdapter.ts @@ -57,12 +57,12 @@ export class SearchAdapter { }, body: gqlQueryBody }) - .then(resp => { - return resp.json() - }) - .catch(error => { - throw new Error('FetchError in request to ES: ' + error.toString()) - }) + .then(resp => { + return resp.json() + }) + .catch(error => { + throw new Error('FetchError in request to ES: ' + error.toString()) + }) } /** From bf87737fd274662c1ab2e02abd62f2e09b973a59 Mon Sep 17 00:00:00 2001 From: sshibalov Date: Tue, 16 Jul 2019 16:28:45 +0300 Subject: [PATCH 0326/1227] Bugfix --- core/lib/module/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/lib/module/index.ts b/core/lib/module/index.ts index 9d1323d1e..42ce2eed5 100644 --- a/core/lib/module/index.ts +++ b/core/lib/module/index.ts @@ -55,7 +55,7 @@ class VueStorefrontModule { } private _extendModule (extendedConfig: VueStorefrontModuleConfig): void { - const mergedStore = { modules: [] }; + const mergedStore = { modules: [], plugin: null } const key = this._c.key const originalStore = this._c.store const extendedStore = extendedConfig.store @@ -63,6 +63,7 @@ class VueStorefrontModule { delete extendedConfig.store this._c = merge(this._c, extendedConfig) mergedStore.modules = mergeStores(originalStore, extendedStore) + mergedStore.plugin = extendedStore.plugin || originalStore.plugin || null this._c.store = mergedStore Logger.info('Module "' + key + '" has been succesfully extended.', 'module')() } From 928e000900aee3a517375586fd61ba30cf9cf098 Mon Sep 17 00:00:00 2001 From: Michal-Dziedzinski Date: Tue, 16 Jul 2019 15:33:07 +0200 Subject: [PATCH 0327/1227] Add pleceholder when getting quantity, change place of calling getQuantity method --- core/modules/catalog/store/stock/actions.ts | 88 ++++++++++----------- core/modules/compare/store/getters.ts | 10 +-- src/themes/default/pages/Product.vue | 17 ++-- 3 files changed, 58 insertions(+), 57 deletions(-) diff --git a/core/modules/catalog/store/stock/actions.ts b/core/modules/catalog/store/stock/actions.ts index 76aaf6ac7..d8a243d30 100644 --- a/core/modules/catalog/store/stock/actions.ts +++ b/core/modules/catalog/store/stock/actions.ts @@ -1,14 +1,14 @@ -import { ActionTree } from 'vuex'; -import i18n from '@vue-storefront/i18n'; +import { ActionTree } from 'vuex' +import i18n from '@vue-storefront/i18n' // requires cart module -import * as types from '@vue-storefront/core/modules/cart/store/mutation-types'; -import RootState from '@vue-storefront/core/types/RootState'; -import StockState from '../../types/StockState'; -import { TaskQueue } from '@vue-storefront/core/lib/sync'; -import { Logger } from '@vue-storefront/core/lib/logger'; -import config from 'config'; -import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus'; -import { processURLAddress } from '@vue-storefront/core/helpers'; +import * as types from '@vue-storefront/core/modules/cart/store/mutation-types' +import RootState from '@vue-storefront/core/types/RootState' +import StockState from '../../types/StockState' +import { TaskQueue } from '@vue-storefront/core/lib/sync' +import { Logger } from '@vue-storefront/core/lib/logger' +import config from 'config' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { processURLAddress } from '@vue-storefront/core/helpers' const actions: ActionTree = { /** @@ -30,7 +30,7 @@ const actions: ActionTree = { is_result_cacheable: true, // store result for the Checkout.js double check product_sku: product.sku, callback_event: 'store:stock/stockAfterCheck' - }); + }) return { qty: product.stock ? product.stock.qty : 0, status: product.stock @@ -39,7 +39,7 @@ const actions: ActionTree = { : 'out_of_stock' : 'ok', onlineCheckTaskId: task.task_id - }; // if online we can return ok because it will be verified anyway + } // if online we can return ok because it will be verified anyway } else { return { qty: product.stock ? product.stock.qty : 0, @@ -48,7 +48,7 @@ const actions: ActionTree = { ? 'ok' : 'out_of_stock' : 'volatile' - }; // if not online, cannot check the source of true here + } // if not online, cannot check the source of true here } }, /** @@ -68,7 +68,7 @@ const actions: ActionTree = { mode: 'cors' }, product_sku: product.sku - }); + }) return { qty: task.result ? task.result.qty : 0, status: task.result @@ -77,7 +77,7 @@ const actions: ActionTree = { : 'out_of_stock' : 'ok', onlineCheckTaskId: task.task_id - }; // if online we can return ok because it will be verified anyway + } // if online we can return ok because it will be verified anyway } else { return { qty: product.stock ? product.stock.qty : 0, @@ -86,13 +86,13 @@ const actions: ActionTree = { ? 'ok' : 'out_of_stock' : 'volatile' - }; // if not online, cannot check the source of true here + } // if not online, cannot check the source of true here } }, /** * Reset current configuration and selected variatnts */ - list (context, { skus }) { + list ({ state }, { skus }) { if (config.stock.synchronize) { try { const task: any = TaskQueue.execute({ @@ -107,36 +107,34 @@ const actions: ActionTree = { mode: 'cors' }, skus: skus - }); + }) if (task.resultCode === 200) { for (const si of task.result) { - context.state.cache[si.product_id] = { + state.cache[si.product_id] = { is_in_stock: si.is_in_stock, qty: si.qty, product_id: si.product_id - }; // TODO: should be moved to mutation + } // TODO: should be moved to mutation } } - return task; // if online we can return ok because it will be verified anyway + return task // if online we can return ok because it will be verified anyway } catch (err) { - Logger.error(err, 'stock')(); - return null; + Logger.error(err, 'stock')() + return null } } else { - return null; // if not online, cannot check the source of true here + return null // if not online, cannot check the source of true here } }, - clearCache (context) { - context.state.cache = {}; + clearCache ({ state }) { + state.cache = {} }, - async stockAfterCheck (context, event) { + async stockAfterCheck ({ dispatch, commit }, event) { setTimeout(async () => { // TODO: Move to cart module - const cartItem: any = await context.dispatch( - 'cart/getItem', - event.product_sku, - { root: true } - ); + const cartItem: any = await dispatch('cart/getItem', event.product_sku, { + root: true + }) if (cartItem && event.result.code !== 'ENOTFOUND') { if (!event.result.is_in_stock) { if (!config.stock.allowOutOfStockInCart && !config.cart.synchronize) { @@ -144,14 +142,14 @@ const actions: ActionTree = { Logger.log( 'Removing product from cart' + event.product_sku, 'stock' - )(); - context.commit( + )() + commit( 'cart/' + types.CART_DEL_ITEM, { product: { sku: event.product_sku } }, { root: true } - ); + ) } else { - context.dispatch( + dispatch( 'cart/updateItem', { product: { @@ -161,10 +159,10 @@ const actions: ActionTree = { } }, { root: true } - ); + ) } } else { - context.dispatch( + dispatch( 'cart/updateItem', { product: { @@ -174,9 +172,9 @@ const actions: ActionTree = { } }, { root: true } - ); + ) } - EventBus.$emit('cart-after-itemchanged', { item: cartItem }); + EventBus.$emit('cart-after-itemchanged', { item: cartItem }) } Logger.debug( 'Stock quantity checked for ' + @@ -185,10 +183,10 @@ const actions: ActionTree = { (event.transmited_at - event.created_at) + ' ms', 'stock' - )(); - Logger.debug(event, 'stock')(); - }, 500); + )() + Logger.debug(event, 'stock')() + }, 500) } -}; +} -export default actions; +export default actions diff --git a/core/modules/compare/store/getters.ts b/core/modules/compare/store/getters.ts index ca2c0d15a..4f09a9ce4 100644 --- a/core/modules/compare/store/getters.ts +++ b/core/modules/compare/store/getters.ts @@ -1,12 +1,12 @@ -import { GetterTree } from 'vuex'; -import RootState from '@vue-storefront/core/types/RootState'; -import CompareState from '../types/CompareState'; +import { GetterTree } from 'vuex' +import RootState from '@vue-storefront/core/types/RootState' +import CompareState from '../types/CompareState' const getters: GetterTree = { isEmpty: state => state.items.length === 0, isOnCompare: state => product => state.items.find(p => p.sku === product.sku), isCompareLoaded: state => state.loaded, getCompareProductsCount: state => state.items.length -}; +} -export default getters; +export default getters diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index 844ddb745..2e9b8d4ca 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -136,7 +136,7 @@ v-if="product.type_id !== 'grouped' && product.type_id !== 'bundle'" >
@@ -252,7 +252,8 @@ export default { data () { return { detailsOpen: false, - quantity: 0 + quantity: 0, + isProductLoading: true } }, computed: { @@ -311,9 +312,6 @@ export default { created () { this.getQuantity() }, - updated () { - this.getQuantity() - }, methods: { showDetails (event) { this.detailsOpen = true @@ -342,17 +340,22 @@ export default { 'filter-changed-product', Object.assign({ attribute_code: variant.type }, variant) ) + this.getQuantity() }, openSizeGuide () { this.$bus.$emit('modal-show', 'modal-sizeguide') }, getQuantity () { + this.isProductLoading = true this.$store .dispatch('stock/check', { product: this.product, qty: this.product.qte }) - .then(res => (this.quantity = res.qty)) + .then(res => { + this.isProductLoading = false + this.quantity = res.qty + }) } }, validations: { From 7523fb70a0187517d9716d46ea9a00f69c95e2ee Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Tue, 16 Jul 2019 16:14:41 +0200 Subject: [PATCH 0328/1227] order store refactor (initial) --- core/modules-entry.ts | 2 - core/modules/breadcrumbs/index.ts | 1 - .../offline-order/components/CancelOrders.ts | 2 +- .../helpers/onNetworkStatusChange.ts | 2 +- .../modules/order/hooks/beforeRegistration.ts | 115 ---------------- core/modules/order/index.ts | 126 ++++++++++++++++-- core/modules/order/store/index.ts | 2 +- core/modules/order/store/mutations.ts | 2 +- docs/guide/core-themes/service-workers.md | 2 +- src/modules/index.ts | 4 + 10 files changed, 125 insertions(+), 133 deletions(-) delete mode 100644 core/modules/order/hooks/beforeRegistration.ts diff --git a/core/modules-entry.ts b/core/modules-entry.ts index ef5ade955..73ff9ea6f 100644 --- a/core/modules-entry.ts +++ b/core/modules-entry.ts @@ -1,14 +1,12 @@ import { VueStorefrontModule } from '@vue-storefront/core/lib/module' import { Cms } from './modules/cms' -import { Order } from './modules/order' import { User } from './modules/user' import { registerModules } from 'src/modules' // @deprecated from 2.0, use registerModule instead export const enabledModules: VueStorefrontModule[] = [ Cms, - Order, User, ...registerModules ] diff --git a/core/modules/breadcrumbs/index.ts b/core/modules/breadcrumbs/index.ts index e85c2585d..96bab71d2 100644 --- a/core/modules/breadcrumbs/index.ts +++ b/core/modules/breadcrumbs/index.ts @@ -1,7 +1,6 @@ import { breadcrumbsStore } from './store' import { StorefrontModule } from '@vue-storefront/module' - export const BreadcrumbsModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { store.registerModule('breadcrumbs', breadcrumbsStore) } diff --git a/core/modules/offline-order/components/CancelOrders.ts b/core/modules/offline-order/components/CancelOrders.ts index 5f733504b..546edf559 100644 --- a/core/modules/offline-order/components/CancelOrders.ts +++ b/core/modules/offline-order/components/CancelOrders.ts @@ -9,7 +9,7 @@ import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' export const CancelOrders = { methods: { cancelOrders () { - const ordersCollection = initCacheStorage('orders', false, true) + const ordersCollection = initCacheStorage('order', false, true) ordersCollection.iterate((order, id, iterationNumber) => { if (!order.transmited) { ordersCollection.removeItem(id) diff --git a/core/modules/offline-order/helpers/onNetworkStatusChange.ts b/core/modules/offline-order/helpers/onNetworkStatusChange.ts index 1e8f0852f..44cd2f1c6 100644 --- a/core/modules/offline-order/helpers/onNetworkStatusChange.ts +++ b/core/modules/offline-order/helpers/onNetworkStatusChange.ts @@ -13,7 +13,7 @@ export function onNetworkStatusChange (store) { EventBus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue } else { const ordersToConfirm = [] - const ordersCollection = initCacheStorage('orders', false, true) + const ordersCollection = initCacheStorage('order', false, true) ordersCollection.iterate((order, id, iterationNumber) => { if (!order.transmited) { diff --git a/core/modules/order/hooks/beforeRegistration.ts b/core/modules/order/hooks/beforeRegistration.ts deleted file mode 100644 index 0f4065608..000000000 --- a/core/modules/order/hooks/beforeRegistration.ts +++ /dev/null @@ -1,115 +0,0 @@ -import * as localForage from 'localforage' -import UniversalStorage from '@vue-storefront/core/store/lib/storage' -import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus/index' -import { Logger } from '@vue-storefront/core/lib/logger' -import rootStore from '@vue-storefront/core/store' -import i18n from '@vue-storefront/i18n' -import { serial, onlineHelper, processURLAddress } from '@vue-storefront/core/helpers' -import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' -import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' - -export function beforeRegistration ({ Vue, config, store, isServer }) { - StorageManager.set('ordersCollection', new UniversalStorage(localForage.createInstance({ - name: 'shop', - storeName: 'orders', - driver: localForage[config.localForage.defaultDrivers['orders']] - }))) - if (!isServer) { - const orderMutex = {} - // TODO: move to external file - EventBus.$on('order/PROCESS_QUEUE', async event => { - if (onlineHelper.isOnline) { - Logger.log('Sending out orders queue to server ...')() - const ordersCollection = initCacheStorage('orders', false, true) - - const fetchQueue = [] - ordersCollection.iterate((order, id) => { - // Resulting key/value pair -- this callback - // will be executed for every item in the - // database. - - if (!order.transmited && !orderMutex[id]) { // not sent to the server yet - orderMutex[id] = true - const config = event.config - const orderData = order - const orderId = id - Logger.log('Pushing out order ' + orderId)() - fetchQueue.push( - /** @todo refactor order synchronisation to proper handling through vuex actions to avoid code duplication */ - fetch(processURLAddress(config.orders.endpoint), - { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(orderData) - }).then(response => { - const contentType = response.headers.get('content-type') - if (contentType && contentType.includes('application/json')) { - return response.json() - } else { - orderMutex[id] = false - Logger.error('Error with response - bad content-type!')() - } - }) - .then(jsonResponse => { - if (jsonResponse) { - Logger.info('Response for: ' + orderId + ' = ' + JSON.stringify(jsonResponse.result))() - orderData.transmited = true // by default don't retry to transmit this order - orderData.transmited_at = new Date() - - if (jsonResponse.code !== 200) { - Logger.error(jsonResponse, 'order-sync')() - - if (jsonResponse.code === 400) { - rootStore.dispatch('notification/spawnNotification', { - type: 'error', - message: i18n.t('Address provided in checkout contains invalid data. Please check if all required fields are filled in and also contact us on {email} to resolve this issue for future. Your order has been canceled.', { email: config.mailer.contactAddress }), - action1: { label: i18n.t('OK') } - }) - } else if (jsonResponse.code === 500 && jsonResponse.result === i18n.t('Error: Error while adding products')) { - rootStore.dispatch('notification/spawnNotification', { - type: 'error', - message: i18n.t('Some products you\'ve ordered are out of stock. Your order has been canceled.'), - action1: { label: i18n.t('OK') } - }) - } else { - orderData.transmited = false // probably some server related error. Enqueue - } - } - - ordersCollection.setItem(orderId.toString(), orderData) - } else { - Logger.error(jsonResponse)() - } - orderMutex[id] = false - }).catch(err => { - if (config.orders.offline_orders.notification.enabled) { - navigator.serviceWorker.ready.then(registration => { - registration.sync.register('orderSync') - .then(() => { - Logger.log('Order sync registered')() - }) - .catch(error => { - Logger.log('Unable to sync', error)() - }) - }) - } - Logger.error('Error sending order: ' + orderId, err)() - orderMutex[id] = false - }) - ) - } - }, (err) => { - if (err) Logger.error(err)() - Logger.log('Iteration has completed')() - - // execute them serially - serial(fetchQueue) - Logger.info('Processing orders queue has finished')() - }).catch(err => { - // This code runs if there were any errors - Logger.log(err)() - }) - } - }) - } -} diff --git a/core/modules/order/index.ts b/core/modules/order/index.ts index 9060e4e61..d361a2e61 100644 --- a/core/modules/order/index.ts +++ b/core/modules/order/index.ts @@ -1,10 +1,116 @@ -import { createModule } from '@vue-storefront/core/lib/module' -import { module } from './store' -import { beforeRegistration } from './hooks/beforeRegistration' - -export const KEY = 'order' -export const Order = createModule({ - key: KEY, - store: { modules: [{ key: KEY, module }] }, - beforeRegistration -}) +import { orderStore } from './store' +import * as localForage from 'localforage' +import UniversalStorage from '@vue-storefront/core/store/lib/storage' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus/index' +import { Logger } from '@vue-storefront/core/lib/logger' +import rootStore from '@vue-storefront/core/store' +import i18n from '@vue-storefront/i18n' +import { serial, onlineHelper, processURLAddress } from '@vue-storefront/core/helpers' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' +import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' +import { isServer } from '@vue-storefront/core/helpers' +import { StorefrontModule } from '@vue-storefront/module'; + +export const OrderModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { + StorageManager.init('order') + + if (!isServer) { + const orderMutex = {} + // TODO: move to external file + EventBus.$on('order/PROCESS_QUEUE', async event => { + if (onlineHelper.isOnline) { + Logger.log('Sending out orders queue to server ...')() + const ordersCollection = initCacheStorage('order', false, true) + + const fetchQueue = [] + ordersCollection.iterate((order, id) => { + // Resulting key/value pair -- this callback + // will be executed for every item in the + // database. + + if (!order.transmited && !orderMutex[id]) { // not sent to the server yet + orderMutex[id] = true + const config = event.config + const orderData = order + const orderId = id + Logger.log('Pushing out order ' + orderId)() + fetchQueue.push( + /** @todo refactor order synchronisation to proper handling through vuex actions to avoid code duplication */ + fetch(processURLAddress(config.orders.endpoint), + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(orderData) + }).then(response => { + const contentType = response.headers.get('content-type') + if (contentType && contentType.includes('application/json')) { + return response.json() + } else { + orderMutex[id] = false + Logger.error('Error with response - bad content-type!')() + } + }) + .then(jsonResponse => { + if (jsonResponse) { + Logger.info('Response for: ' + orderId + ' = ' + JSON.stringify(jsonResponse.result))() + orderData.transmited = true // by default don't retry to transmit this order + orderData.transmited_at = new Date() + + if (jsonResponse.code !== 200) { + Logger.error(jsonResponse, 'order-sync')() + + if (jsonResponse.code === 400) { + rootStore.dispatch('notification/spawnNotification', { + type: 'error', + message: i18n.t('Address provided in checkout contains invalid data. Please check if all required fields are filled in and also contact us on {email} to resolve this issue for future. Your order has been canceled.', { email: config.mailer.contactAddress }), + action1: { label: i18n.t('OK') } + }) + } else if (jsonResponse.code === 500 && jsonResponse.result === i18n.t('Error: Error while adding products')) { + rootStore.dispatch('notification/spawnNotification', { + type: 'error', + message: i18n.t('Some products you\'ve ordered are out of stock. Your order has been canceled.'), + action1: { label: i18n.t('OK') } + }) + } else { + orderData.transmited = false // probably some server related error. Enqueue + } + } + + ordersCollection.setItem(orderId.toString(), orderData) + } else { + Logger.error(jsonResponse)() + } + orderMutex[id] = false + }).catch(err => { + if (config.orders.offline_orders.notification.enabled) { + navigator.serviceWorker.ready.then(registration => { + registration.sync.register('orderSync') + .then(() => { + Logger.log('Order sync registered')() + }) + .catch(error => { + Logger.log('Unable to sync', error)() + }) + }) + } + Logger.error('Error sending order: ' + orderId, err)() + orderMutex[id] = false + }) + ) + } + }, (err) => { + if (err) Logger.error(err)() + Logger.log('Iteration has completed')() + + // execute them serially + serial(fetchQueue) + Logger.info('Processing orders queue has finished')() + }).catch(err => { + // This code runs if there were any errors + Logger.log(err)() + }) + } + }) + } + store.registerModule('order', orderStore) +} diff --git a/core/modules/order/store/index.ts b/core/modules/order/store/index.ts index 4962392ff..51e22f6e1 100644 --- a/core/modules/order/store/index.ts +++ b/core/modules/order/store/index.ts @@ -5,7 +5,7 @@ import getters from './getters' import RootState from '@vue-storefront/core/types/RootState' import OrderState from '../types/OrderState' -export const module: Module = { +export const orderStore: Module = { namespaced: true, state: { last_order_confirmation: null, diff --git a/core/modules/order/store/mutations.ts b/core/modules/order/store/mutations.ts index 917b8146f..a4ab0e4c0 100644 --- a/core/modules/order/store/mutations.ts +++ b/core/modules/order/store/mutations.ts @@ -13,7 +13,7 @@ const mutations: MutationTree = { * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md */ [types.ORDER_PLACE_ORDER] (state, order) { - const ordersCollection = StorageManager.get('ordersCollection') + const ordersCollection = StorageManager.get('order') const orderId = entities.uniqueEntityId(order) // timestamp as a order id is not the best we can do but it's enough order.order_id = orderId.toString() order.created_at = new Date() diff --git a/docs/guide/core-themes/service-workers.md b/docs/guide/core-themes/service-workers.md index f1f54dd29..36402d2be 100644 --- a/docs/guide/core-themes/service-workers.md +++ b/docs/guide/core-themes/service-workers.md @@ -46,7 +46,7 @@ It allows you to send data to the Service Worker. For example, when the order is * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md */ [types.CHECKOUT_PLACE_ORDER] (state, order) { - const ordersCollection = StorageManager.get('ordersCollection') + const ordersCollection = StorageManager.get('order') const orderId = entities.uniqueEntityId(order) // timestamp as a order id is not the best we can do but it's enough order.id = orderId.toString() order.transmited = false diff --git a/src/modules/index.ts b/src/modules/index.ts index 147600776..7c07753ed 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -12,6 +12,8 @@ import { NotificationModule } from '@vue-storefront/core/modules/notification' import { RecentlyViewedModule } from '@vue-storefront/core/modules/recently-viewed' import { UrlModule } from '@vue-storefront/core/modules/url' import { BreadcrumbsModule } from '@vue-storefront/core/modules/breadcrumbs' +import { OrderModule } from '@vue-storefront/core/modules/order' + // import { GoogleAnalyticsModule } from './google-analytics'; // import { HotjarModule } from './hotjar'; import { GoogleTagManagerModule } from './google-tag-manager'; @@ -20,6 +22,7 @@ import { PaymentBackendMethodsModule } from './payment-backend-methods'; import { PaymentCashOnDeliveryModule } from './payment-cash-on-delivery'; import { RawOutputExampleModule } from './raw-output-example' import { InstantCheckoutModule } from './instant-checkout' + import { registerModule } from '@vue-storefront/module' // TODO:distributed across proper pages BEFORE 1.11 @@ -45,6 +48,7 @@ export function registerNewModules () { registerModule(CatalogNextModule) registerModule(CompareModule) registerModule(BreadcrumbsModule) + registerModule(OrderModule) } // Deprecated API, will be removed in 2.0 From 3ccf17470239308783fe164c03b98e233524feaa Mon Sep 17 00:00:00 2001 From: sshibalov Date: Tue, 16 Jul 2019 17:31:18 +0300 Subject: [PATCH 0329/1227] Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bc7c1511..cda1f6a51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed eslint warning in Product Page, removed v-if from v-for node - @przspa (#3181) - Fixed aspect ratio in ProductImage component - @przspa (#3187) - Fixed AMP Product page - @przspa (#3227) +- Fixed when store has updated, but plugin didn`t called - @serzilo (#3238) ### Changed / Improved - Shipping address is saved as default when not logged in user chooses to create account during checkout - @iwonapiotrowska (#2636) From 2048a3df6014cbecba5b5a2566d1a7a73b1785d2 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Tue, 16 Jul 2019 16:55:28 +0200 Subject: [PATCH 0330/1227] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cda1f6a51..d3baa952d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed eslint warning in Product Page, removed v-if from v-for node - @przspa (#3181) - Fixed aspect ratio in ProductImage component - @przspa (#3187) - Fixed AMP Product page - @przspa (#3227) -- Fixed when store has updated, but plugin didn`t called - @serzilo (#3238) +- Fixed when store has updated, but plugin didn't called - @serzilo (#3238) ### Changed / Improved - Shipping address is saved as default when not logged in user chooses to create account during checkout - @iwonapiotrowska (#2636) From 9a186e790caa5895bd319a05fdfdf8dd717546d0 Mon Sep 17 00:00:00 2001 From: Michal-Dziedzinski Date: Wed, 17 Jul 2019 09:19:22 +0200 Subject: [PATCH 0331/1227] Change find to some in wishlist and compare getters --- core/modules/compare/components/IsOnCompare.ts | 2 -- core/modules/compare/store/getters.ts | 2 +- core/modules/wishlist/store/getters.ts | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/core/modules/compare/components/IsOnCompare.ts b/core/modules/compare/components/IsOnCompare.ts index 4f6d37cad..0a627a224 100644 --- a/core/modules/compare/components/IsOnCompare.ts +++ b/core/modules/compare/components/IsOnCompare.ts @@ -1,5 +1,3 @@ -// import { IsOnCompare } from './IsOnCompare'; -// import { mapGetters } from 'vuex' import { Compare as CompareModule } from '..' import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin' diff --git a/core/modules/compare/store/getters.ts b/core/modules/compare/store/getters.ts index 4f09a9ce4..e69ffaa07 100644 --- a/core/modules/compare/store/getters.ts +++ b/core/modules/compare/store/getters.ts @@ -4,7 +4,7 @@ import CompareState from '../types/CompareState' const getters: GetterTree = { isEmpty: state => state.items.length === 0, - isOnCompare: state => product => state.items.find(p => p.sku === product.sku), + isOnCompare: state => product => state.items.some(p => p.sku === product.sku), isCompareLoaded: state => state.loaded, getCompareProductsCount: state => state.items.length } diff --git a/core/modules/wishlist/store/getters.ts b/core/modules/wishlist/store/getters.ts index 5d03b1b7c..f7708ca2a 100644 --- a/core/modules/wishlist/store/getters.ts +++ b/core/modules/wishlist/store/getters.ts @@ -4,7 +4,7 @@ import WishlistState from '../types/WishlistState' const getters: GetterTree = { isOnWishlist: state => product => - state.items.find(p => p.sku === product.sku), + state.items.some(p => p.sku === product.sku), isWishlistLoaded: state => state.loaded, getWishlistItemsCount: state => state.items.length } From 1ed87531c49362336587f25d3a48f996b55e6f9d Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 11:14:52 +0200 Subject: [PATCH 0332/1227] rename order to orders --- core/modules/offline-order/components/CancelOrders.ts | 7 +------ .../offline-order/helpers/onNetworkStatusChange.ts | 2 +- core/modules/order/index.ts | 6 +++--- core/modules/order/store/actions.ts | 2 +- core/modules/order/store/mutation-types.ts | 2 +- core/modules/order/store/mutations.ts | 8 ++++---- docs/guide/core-themes/service-workers.md | 2 +- docs/guide/vuex/sync-store.md | 2 +- 8 files changed, 13 insertions(+), 18 deletions(-) diff --git a/core/modules/offline-order/components/CancelOrders.ts b/core/modules/offline-order/components/CancelOrders.ts index 546edf559..22609570c 100644 --- a/core/modules/offline-order/components/CancelOrders.ts +++ b/core/modules/offline-order/components/CancelOrders.ts @@ -1,15 +1,10 @@ -import * as localForage from 'localforage' -import store from '@vue-storefront/core/store' - -import UniversalStorage from '@vue-storefront/core/store/lib/storage' import { Logger } from '@vue-storefront/core/lib/logger' -import config from 'config' import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' export const CancelOrders = { methods: { cancelOrders () { - const ordersCollection = initCacheStorage('order', false, true) + const ordersCollection = initCacheStorage('orders', false, true) ordersCollection.iterate((order, id, iterationNumber) => { if (!order.transmited) { ordersCollection.removeItem(id) diff --git a/core/modules/offline-order/helpers/onNetworkStatusChange.ts b/core/modules/offline-order/helpers/onNetworkStatusChange.ts index 44cd2f1c6..1e8f0852f 100644 --- a/core/modules/offline-order/helpers/onNetworkStatusChange.ts +++ b/core/modules/offline-order/helpers/onNetworkStatusChange.ts @@ -13,7 +13,7 @@ export function onNetworkStatusChange (store) { EventBus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue } else { const ordersToConfirm = [] - const ordersCollection = initCacheStorage('order', false, true) + const ordersCollection = initCacheStorage('orders', false, true) ordersCollection.iterate((order, id, iterationNumber) => { if (!order.transmited) { diff --git a/core/modules/order/index.ts b/core/modules/order/index.ts index d361a2e61..5897f8cdb 100644 --- a/core/modules/order/index.ts +++ b/core/modules/order/index.ts @@ -12,7 +12,7 @@ import { isServer } from '@vue-storefront/core/helpers' import { StorefrontModule } from '@vue-storefront/module'; export const OrderModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { - StorageManager.init('order') + StorageManager.init('orders') if (!isServer) { const orderMutex = {} @@ -20,7 +20,7 @@ export const OrderModule: StorefrontModule = function (app, store, router, modul EventBus.$on('order/PROCESS_QUEUE', async event => { if (onlineHelper.isOnline) { Logger.log('Sending out orders queue to server ...')() - const ordersCollection = initCacheStorage('order', false, true) + const ordersCollection = initCacheStorage('orders', false, true) const fetchQueue = [] ordersCollection.iterate((order, id) => { @@ -112,5 +112,5 @@ export const OrderModule: StorefrontModule = function (app, store, router, modul } }) } - store.registerModule('order', orderStore) + store.registerModule('orders', orderStore) } diff --git a/core/modules/order/store/actions.ts b/core/modules/order/store/actions.ts index cb8cd10f5..bfaf23f12 100644 --- a/core/modules/order/store/actions.ts +++ b/core/modules/order/store/actions.ts @@ -63,7 +63,7 @@ const actions: ActionTree = { } else if (task.resultCode === 400) { commit(types.ORDER_REMOVE_SESSION_ORDER_HASH, currentOrderHash) - Logger.error('Internal validation error; Order entity is not compliant with the schema: ' + JSON.stringify(task.result), 'order')() + Logger.error('Internal validation error; Order entity is not compliant with the schema: ' + JSON.stringify(task.result), 'orders')() dispatch('notification/spawnNotification', { type: 'error', message: i18n.t('Internal validation error. Please check if all required fields are filled in. Please contact us on {email}', { email: config.mailer.contactAddress }), diff --git a/core/modules/order/store/mutation-types.ts b/core/modules/order/store/mutation-types.ts index d253a4273..221bcc83e 100644 --- a/core/modules/order/store/mutation-types.ts +++ b/core/modules/order/store/mutation-types.ts @@ -1,4 +1,4 @@ -export const SN_ORDER = 'order' +export const SN_ORDER = 'orders' export const ORDER_PLACE_ORDER = SN_ORDER + '/PLACE_ORDER' export const ORDER_PROCESS_QUEUE = SN_ORDER + '/PROCESS_QUEUE' export const ORDER_LAST_ORDER_WITH_CONFIRMATION = SN_ORDER + '/LAST_ORDER_CONFIRMATION' diff --git a/core/modules/order/store/mutations.ts b/core/modules/order/store/mutations.ts index a4ab0e4c0..28dd43d4d 100644 --- a/core/modules/order/store/mutations.ts +++ b/core/modules/order/store/mutations.ts @@ -13,20 +13,20 @@ const mutations: MutationTree = { * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md */ [types.ORDER_PLACE_ORDER] (state, order) { - const ordersCollection = StorageManager.get('order') + const ordersCollection = StorageManager.get('orders') const orderId = entities.uniqueEntityId(order) // timestamp as a order id is not the best we can do but it's enough order.order_id = orderId.toString() order.created_at = new Date() order.updated_at = new Date() ordersCollection.setItem(orderId.toString(), order, (err, resp) => { - if (err) Logger.error(err, 'order')() + if (err) Logger.error(err, 'orders')() if (!order.transmited) { EventBus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue } - Logger.info('Order placed, orderId = ' + orderId, 'order')() + Logger.info('Order placed, orderId = ' + orderId, 'orders')() }).catch((reason) => { - Logger.error(reason, 'order') // it doesn't work on SSR + Logger.error(reason, 'orders') // it doesn't work on SSR }) // populate cache }, [types.ORDER_LAST_ORDER_WITH_CONFIRMATION] (state, payload) { diff --git a/docs/guide/core-themes/service-workers.md b/docs/guide/core-themes/service-workers.md index 36402d2be..5a3a05ff7 100644 --- a/docs/guide/core-themes/service-workers.md +++ b/docs/guide/core-themes/service-workers.md @@ -46,7 +46,7 @@ It allows you to send data to the Service Worker. For example, when the order is * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md */ [types.CHECKOUT_PLACE_ORDER] (state, order) { - const ordersCollection = StorageManager.get('order') + const ordersCollection = StorageManager.get('orders') const orderId = entities.uniqueEntityId(order) // timestamp as a order id is not the best we can do but it's enough order.id = orderId.toString() order.transmited = false diff --git a/docs/guide/vuex/sync-store.md b/docs/guide/vuex/sync-store.md index 142dbc37f..4052b8092 100644 --- a/docs/guide/vuex/sync-store.md +++ b/docs/guide/vuex/sync-store.md @@ -46,7 +46,7 @@ The `url` can contain two dynamic variable placeholders that will be expanded to An example URL with variables: `http://localhost:8080/api/cart/totals?token={{token}}&cartId={{cartId}}` :::tip Note -The task object and then the results are stored within the `tasksCollection` indexedDb data table under the key of `task.task_id` +The task object and then the results are stored within the `syncTasks` indexedDb/Local storage data table under the key of `task.task_id` ::: ![syncTasks local collection stores the tasks and the results](../images/syncTasks-example.png) From 23cb6b944f249538647abf9e1d2f14f5d391eb93 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 11:51:16 +0200 Subject: [PATCH 0333/1227] cache cleanup --- core/lib/search.ts | 2 +- core/modules/cart/store/actions.ts | 2 +- core/modules/catalog/index.ts | 2 +- core/modules/catalog/store/attribute/mutations.ts | 2 +- core/modules/catalog/store/product/actions.ts | 4 ++-- core/modules/catalog/store/tax/mutations.ts | 2 +- core/modules/checkout/store/checkout/actions.ts | 2 +- core/modules/user/hooks/afterRegistration.ts | 8 ++++---- core/modules/user/hooks/beforeRegistration.ts | 8 +------- core/modules/user/store/actions.ts | 8 ++++---- 10 files changed, 17 insertions(+), 23 deletions(-) diff --git a/core/lib/search.ts b/core/lib/search.ts index 7e9d99167..6b31e49bc 100644 --- a/core/lib/search.ts +++ b/core/lib/search.ts @@ -53,7 +53,7 @@ export const quickSearchByQuery = async ({ query = {}, start = 0, size = 50, ent Request.groupId = rootStore.state.user.groupId } - const cache = StorageManager.get('elasticCacheCollection') // switch to appcache? + const cache = StorageManager.get('elasticCache') // switch to appcache? let servedFromCache = false const cacheKey = sha3_224(JSON.stringify(Request)) const benchmarkTime = new Date() diff --git a/core/modules/cart/store/actions.ts b/core/modules/cart/store/actions.ts index b65615301..476c65118 100644 --- a/core/modules/cart/store/actions.ts +++ b/core/modules/cart/store/actions.ts @@ -503,7 +503,7 @@ const actions: ActionTree = { }, /** authorize the cart after user got logged in using the current cart token */ authorize ({ dispatch }) { - StorageManager.get('usersCollection').getItem('last-cart-bypass-ts', (err, lastCartBypassTs) => { + StorageManager.get('user').getItem('last-cart-bypass-ts', (err, lastCartBypassTs) => { if (err) { Logger.error(err, 'cart')() } diff --git a/core/modules/catalog/index.ts b/core/modules/catalog/index.ts index 3c4c7b6d4..624963405 100644 --- a/core/modules/catalog/index.ts +++ b/core/modules/catalog/index.ts @@ -10,7 +10,7 @@ export const CatalogModule: StorefrontModule = function (app, store, router, mod StorageManager.init('categories') StorageManager.init('attributes') StorageManager.init('products') - StorageManager.init('elasticCacheCollection', true, appConfig.server.elasticCacheQuota) + StorageManager.init('elasticCache', true, appConfig.server.elasticCacheQuota) store.registerModule('product', productModule) store.registerModule('attribute', attributeModule) diff --git a/core/modules/catalog/store/attribute/mutations.ts b/core/modules/catalog/store/attribute/mutations.ts index c88bbf6ab..08efcc92c 100644 --- a/core/modules/catalog/store/attribute/mutations.ts +++ b/core/modules/catalog/store/attribute/mutations.ts @@ -22,7 +22,7 @@ const mutations: MutationTree = { attrHashByCode[attr.attribute_code] = attr attrHashById[attr.attribute_id] = attr - const attrCollection = StorageManager.get('attributesCollection') + const attrCollection = StorageManager.get('attributes') try { attrCollection.setItem(entityKeyName('attribute_code', attr.attribute_code.toLowerCase()), attr).catch((reason) => { Logger.error(reason, 'mutations') // it doesn't work on SSR diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts index 2dee2da2e..ebc638c56 100644 --- a/core/modules/catalog/store/product/actions.ts +++ b/core/modules/catalog/store/product/actions.ts @@ -326,7 +326,7 @@ const actions: ActionTree = { } return calculateTaxes(resp.items, context).then((updatedProducts) => { // handle cache - const cache = StorageManager.get('elasticCacheCollection') + const cache = StorageManager.get('elasticCache') for (let prod of resp.items) { // we store each product separately in cache to have offline access to products/single method if (prod.configurable_children) { for (let configurableChild of prod.configurable_children) { @@ -408,7 +408,7 @@ const actions: ActionTree = { return new Promise((resolve, reject) => { const benchmarkTime = new Date() - const cache = StorageManager.get('elasticCacheCollection') + const cache = StorageManager.get('elasticCache') const setupProduct = (prod) => { // set product quantity to 1 diff --git a/core/modules/catalog/store/tax/mutations.ts b/core/modules/catalog/store/tax/mutations.ts index 8c362360b..20b167bbe 100644 --- a/core/modules/catalog/store/tax/mutations.ts +++ b/core/modules/catalog/store/tax/mutations.ts @@ -7,7 +7,7 @@ import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' const mutations: MutationTree = { [types.TAX_UPDATE_RULES] (state, taxClasses) { - const cache = StorageManager.get('elasticCacheCollection') + const cache = StorageManager.get('elasticCache') for (let tc of taxClasses.items) { // we store each product separately in cache to have offline acces for products/single method const cacheKey = entityKeyName('tc', tc.id) cache.setItem(cacheKey, tc).catch((err) => { diff --git a/core/modules/checkout/store/checkout/actions.ts b/core/modules/checkout/store/checkout/actions.ts index 7b407b399..bb490fa43 100644 --- a/core/modules/checkout/store/checkout/actions.ts +++ b/core/modules/checkout/store/checkout/actions.ts @@ -15,7 +15,7 @@ const actions: ActionTree = { try { const result = await dispatch('order/placeOrder', order, {root: true}) if (!result.resultCode || result.resultCode === 200) { - StorageManager.get('usersCollection').setItem('last-cart-bypass-ts', new Date().getTime()) + StorageManager.get('user').setItem('last-cart-bypass-ts', new Date().getTime()) await dispatch('cart/clear', { recreateAndSyncCart: true }, {root: true}) if (state.personalDetails.createAccount) { commit(types.CHECKOUT_DROP_PASSWORD) diff --git a/core/modules/user/hooks/afterRegistration.ts b/core/modules/user/hooks/afterRegistration.ts index 8fd48b63a..49a8802c5 100644 --- a/core/modules/user/hooks/afterRegistration.ts +++ b/core/modules/user/hooks/afterRegistration.ts @@ -30,7 +30,7 @@ export async function afterRegistration ({ Vue, config, store, isServer }) { if ( type.endsWith(types.USER_INFO_LOADED) ) { - StorageManager.get('usersCollection').setItem('current-user', state.user.current).catch((reason) => { + StorageManager.get('user').setItem('current-user', state.user.current).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } @@ -38,7 +38,7 @@ export async function afterRegistration ({ Vue, config, store, isServer }) { if ( type.endsWith(types.USER_ORDERS_HISTORY_LOADED) ) { - StorageManager.get('ordersHistoryCollection').setItem('orders-history', state.user.orders_history).catch((reason) => { + StorageManager.get('user').setItem('orders-history', state.user.orders_history).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } @@ -46,11 +46,11 @@ export async function afterRegistration ({ Vue, config, store, isServer }) { if ( type.endsWith(types.USER_TOKEN_CHANGED) ) { - StorageManager.get('usersCollection').setItem('current-token', state.user.token).catch((reason) => { + StorageManager.get('user').setItem('current-token', state.user.token).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache if (state.user.refreshToken) { - StorageManager.get('usersCollection').setItem('current-refresh-token', state.user.refreshToken).catch((reason) => { + StorageManager.get('user').setItem('current-refresh-token', state.user.refreshToken).catch((reason) => { console.error(reason) // it doesn't work on SSR }) // populate cache } diff --git a/core/modules/user/hooks/beforeRegistration.ts b/core/modules/user/hooks/beforeRegistration.ts index ac1c35801..0c01095bc 100644 --- a/core/modules/user/hooks/beforeRegistration.ts +++ b/core/modules/user/hooks/beforeRegistration.ts @@ -7,15 +7,9 @@ export function beforeRegistration ({ Vue, config, store, isServer }) { const storeView = currentStoreView() const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - StorageManager.set('usersCollection', new UniversalStorage(localForage.createInstance({ + StorageManager.set('user', new UniversalStorage(localForage.createInstance({ name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', storeName: 'user', driver: localForage[config.localForage.defaultDrivers['user']] }))) - - StorageManager.set('ordersHistoryCollection', new UniversalStorage(localForage.createInstance({ - name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', - storeName: 'ordersHistory', - driver: localForage[config.localForage.defaultDrivers['ordersHistory']] - }))) } diff --git a/core/modules/user/store/actions.ts b/core/modules/user/store/actions.ts index e642003e3..7377b7a41 100644 --- a/core/modules/user/store/actions.ts +++ b/core/modules/user/store/actions.ts @@ -24,7 +24,7 @@ const actions: ActionTree = { } context.commit(types.USER_START_SESSION) - const cache = StorageManager.get('usersCollection') + const cache = StorageManager.get('user') cache.getItem('current-token', (err, res) => { if (err) { Logger.error(err, 'user')() @@ -118,7 +118,7 @@ const actions: ActionTree = { */ refresh (context) { return new Promise((resolve, reject) => { - const usersCollection = StorageManager.get('usersCollection') + const usersCollection = StorageManager.get('user') usersCollection.getItem('current-refresh-token', (err, refreshToken) => { if (err) { Logger.error(err, 'user')() @@ -172,7 +172,7 @@ const actions: ActionTree = { Logger.warn('No User token, user unauthorized', 'user')() return resolve(null) } - const cache = StorageManager.get('usersCollection') + const cache = StorageManager.get('user') let resolvedFromCache = false if (useCache === true) { // after login for example we shouldn't use cache to be sure we're loading currently logged in user @@ -313,7 +313,7 @@ const actions: ActionTree = { Logger.debug('No User token, user unathorized', 'user')() return resolve(null) } - const cache = StorageManager.get('ordersHistoryCollection') + const cache = StorageManager.get('user') let resolvedFromCache = false if (useCache === true) { // after login for example we shouldn't use cache to be sure we're loading currently logged in user From 60dec2ef78d4f45f904a8807e97c1e30969a6cc4 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 11:58:15 +0200 Subject: [PATCH 0334/1227] categoriesCollection renamed to categories --- core/modules/catalog/store/category/actions.ts | 2 +- core/modules/catalog/store/category/mutations.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/modules/catalog/store/category/actions.ts b/core/modules/catalog/store/category/actions.ts index 820edbe5e..c8f2a096e 100644 --- a/core/modules/catalog/store/category/actions.ts +++ b/core/modules/catalog/store/category/actions.ts @@ -194,7 +194,7 @@ const actions: ActionTree = { if (skipCache || isServer) { fetchCat({ key, value }) } else { - const catCollection = StorageManager.get('categoriesCollection') + const catCollection = StorageManager.get('categories') // Check if category does not exist in the store AND we haven't recursively reached Default category (id=1) catCollection.getItem(entityKeyName(key, value), setcat) } diff --git a/core/modules/catalog/store/category/mutations.ts b/core/modules/catalog/store/category/mutations.ts index 198b82a8d..c8e5efce0 100644 --- a/core/modules/catalog/store/category/mutations.ts +++ b/core/modules/catalog/store/category/mutations.ts @@ -32,7 +32,7 @@ const mutations: MutationTree = { } catSlugSetter(category) if (categories.includeFields == null) { - const catCollection = StorageManager.get('categoriesCollection') + const catCollection = StorageManager.get('categories') try { catCollection.setItem(entityKeyName('slug', category.slug.toLowerCase()), category).catch((reason) => { Logger.error(reason, 'category') // it doesn't work on SSR From 6f9a13a130180560b49577ecbd2c305c3632137e Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Wed, 17 Jul 2019 12:38:54 +0200 Subject: [PATCH 0335/1227] Fixed bug around first setup of storeView state The problem was that when you had set a defaultStoreCode it would be used but he would not load the store Config of this store. Which is fixed by this commit. --- core/lib/multistore.ts | 13 +- core/lib/test/unit/multistore.spec.ts | 612 +++++++++++++++++++++++++- test/unit/jest.conf.js | 3 +- 3 files changed, 616 insertions(+), 12 deletions(-) diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 519bb5f38..6fa736ef0 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -80,20 +80,15 @@ export function prepareStoreView (storeCode: string): StoreView { tax: config.tax, i18n: config.i18n, elasticsearch: config.elasticsearch, - storeCode: '', + storeCode: storeCode || config.defaultStoreCode || '', storeId: config.defaultStoreCode && config.defaultStoreCode !== '' ? config.storeViews[config.defaultStoreCode].storeId : 1 } const storeViewHasChanged = !rootStore.state.storeView || rootStore.state.storeView.storeCode !== storeCode - if (storeCode) { // current store code - if ((config.storeViews[storeCode])) { - rootStore.state.user.current_storecode = storeCode - storeView = merge(storeView, getExtendedStoreviewConfig(config.storeViews[storeCode])) - } - } else { - storeView.storeCode = config.defaultStoreCode || '' - rootStore.state.user.current_storecode = config.defaultStoreCode || '' + if (storeView.storeCode && config.storeViews[storeView.storeCode]) { + storeView = merge(storeView, getExtendedStoreviewConfig(config.storeViews[storeView.storeCode])) } + rootStore.state.user.current_storecode = storeView.storeCode loadLanguageAsync(storeView.i18n.defaultLocale) diff --git a/core/lib/test/unit/multistore.spec.ts b/core/lib/test/unit/multistore.spec.ts index 813a70c20..93a5f7ecb 100644 --- a/core/lib/test/unit/multistore.spec.ts +++ b/core/lib/test/unit/multistore.spec.ts @@ -1,5 +1,7 @@ -import { storeCodeFromRoute } from '../../multistore' +import { storeCodeFromRoute, prepareStoreView } from '@vue-storefront/core/lib/multistore' import config from 'config' +import rootStore from '@vue-storefront/core/store'; + jest.mock('@vue-storefront/core/app', () => ({ createApp: jest.fn() })) jest.mock('../../../store', () => ({})) jest.mock('@vue-storefront/i18n', () => ({loadLanguageAsync: jest.fn()})) @@ -19,7 +21,8 @@ jest.mock('config', () => ({})) describe('Multistore', () => { beforeEach(() => { - jest.clearAllMocks() + jest.clearAllMocks(); + (rootStore as any).state = {}; Object.keys(config).forEach((key) => { delete config[key]; }); }) @@ -130,4 +133,609 @@ describe('Multistore', () => { expect(storeCodeFromRoute('')).toBe('') }) }) + + describe('prepareStoreView', () => { + it('return default storeView', () => { + rootStore.state.storeView = {} + rootStore.state.user = {} + + config.tax = { + defaultCountry: 'US', + defaultRegion: '', + sourcePriceIncludesTax: false, + calculateServerSide: true + } + + config.i18n = { + defaultCountry: 'US', + defaultLanguage: 'EN', + availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], + defaultLocale: 'en-US', + currencyCode: 'USD', + currencySign: '$', + currencySignPlacement: 'preppend', + dateFormat: 'HH:mm D/M/YYYY', + fullCountryName: 'United States', + fullLanguageName: 'English', + bundleAllStoreviewLanguages: true + } + + config.elasticsearch = { + httpAuth: '', + host: '/api/catalog', + index: 'vue_storefront_catalog', + min_score: 0.02, + csrTimeout: 5000, + ssrTimeout: 1000, + queryMethod: 'GET', + disablePersistentQueriesCache: true, + searchScoring: { + attributes: { + attribute_code: { + scoreValues: { attribute_value: { weight: 1 } } + } + }, + fuzziness: 2, + cutoff_frequency: 0.01, + max_expansions: 3, + minimum_should_match: '75%', + prefix_length: 2, + boost_mode: 'multiply', + score_mode: 'multiply', + max_boost: 100, + function_min_score: 1 + }, + searchableAttributes: { + name: { + boost: 4 + }, + sku: { + boost: 2 + }, + 'category.name': { + boost: 1 + } + } + } + config.defaultStoreCode = '' + + expect(prepareStoreView(null)).toStrictEqual({ + tax: { + defaultCountry: 'US', + defaultRegion: '', + sourcePriceIncludesTax: false, + calculateServerSide: true + }, + i18n: { + defaultCountry: 'US', + defaultLanguage: 'EN', + availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], + defaultLocale: 'en-US', + currencyCode: 'USD', + currencySign: '$', + currencySignPlacement: 'preppend', + dateFormat: 'HH:mm D/M/YYYY', + fullCountryName: 'United States', + fullLanguageName: 'English', + bundleAllStoreviewLanguages: true + }, + elasticsearch: { + httpAuth: '', + host: '/api/catalog', + index: 'vue_storefront_catalog', + min_score: 0.02, + csrTimeout: 5000, + ssrTimeout: 1000, + queryMethod: 'GET', + disablePersistentQueriesCache: true, + searchScoring: { + attributes: { + attribute_code: { + scoreValues: { attribute_value: { weight: 1 } } + } + }, + fuzziness: 2, + cutoff_frequency: 0.01, + max_expansions: 3, + minimum_should_match: '75%', + prefix_length: 2, + boost_mode: 'multiply', + score_mode: 'multiply', + max_boost: 100, + function_min_score: 1 + }, + searchableAttributes: { + name: { + boost: 4 + }, + sku: { + boost: 2 + }, + 'category.name': { + boost: 1 + } + } + }, + storeId: 1, + storeCode: '' + }) + }) + + it('return default storeView with Store Code de', () => { + rootStore.state.storeView = {} + rootStore.state.user = {} + + config.storeViews = { + de: { + storeId: 1 + } + } + + config.tax = { + defaultCountry: 'US', + defaultRegion: '', + sourcePriceIncludesTax: false, + calculateServerSide: true + } + + config.i18n = { + defaultCountry: 'US', + defaultLanguage: 'EN', + availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], + defaultLocale: 'en-US', + currencyCode: 'USD', + currencySign: '$', + currencySignPlacement: 'preppend', + dateFormat: 'HH:mm D/M/YYYY', + fullCountryName: 'United States', + fullLanguageName: 'English', + bundleAllStoreviewLanguages: true + } + + config.elasticsearch = { + httpAuth: '', + host: '/api/catalog', + index: 'vue_storefront_catalog', + min_score: 0.02, + csrTimeout: 5000, + ssrTimeout: 1000, + queryMethod: 'GET', + disablePersistentQueriesCache: true, + searchScoring: { + attributes: { + attribute_code: { + scoreValues: { attribute_value: { weight: 1 } } + } + }, + fuzziness: 2, + cutoff_frequency: 0.01, + max_expansions: 3, + minimum_should_match: '75%', + prefix_length: 2, + boost_mode: 'multiply', + score_mode: 'multiply', + max_boost: 100, + function_min_score: 1 + }, + searchableAttributes: { + name: { + boost: 4 + }, + sku: { + boost: 2 + }, + 'category.name': { + boost: 1 + } + } + } + config.defaultStoreCode = 'de' + + expect(prepareStoreView(null)).toStrictEqual({ + tax: { + defaultCountry: 'US', + defaultRegion: '', + sourcePriceIncludesTax: false, + calculateServerSide: true + }, + i18n: { + defaultCountry: 'US', + defaultLanguage: 'EN', + availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], + defaultLocale: 'en-US', + currencyCode: 'USD', + currencySign: '$', + currencySignPlacement: 'preppend', + dateFormat: 'HH:mm D/M/YYYY', + fullCountryName: 'United States', + fullLanguageName: 'English', + bundleAllStoreviewLanguages: true + }, + elasticsearch: { + httpAuth: '', + host: '/api/catalog', + index: 'vue_storefront_catalog', + min_score: 0.02, + csrTimeout: 5000, + ssrTimeout: 1000, + queryMethod: 'GET', + disablePersistentQueriesCache: true, + searchScoring: { + attributes: { + attribute_code: { + scoreValues: { attribute_value: { weight: 1 } } + } + }, + fuzziness: 2, + cutoff_frequency: 0.01, + max_expansions: 3, + minimum_should_match: '75%', + prefix_length: 2, + boost_mode: 'multiply', + score_mode: 'multiply', + max_boost: 100, + function_min_score: 1 + }, + searchableAttributes: { + name: { + boost: 4 + }, + sku: { + boost: 2 + }, + 'category.name': { + boost: 1 + } + } + }, + storeId: 1, + storeCode: 'de' + }) + }) + + it('return default storeView with Store Code de with merged values from store de', () => { + rootStore.state.storeView = {} + rootStore.state.user = {} + + config.storeViews = { + de: { + storeCode: 'de', + disabled: true, + storeId: 3, + name: 'German Store', + url: '/de', + appendStoreCode: true, + elasticsearch: { + host: '/api/catalog', + index: 'vue_storefront_catalog_de' + }, + tax: { + sourcePriceIncludesTax: false, + defaultCountry: 'DE', + defaultRegion: '', + calculateServerSide: true + }, + i18n: { + fullCountryName: 'Germany', + fullLanguageName: 'German', + defaultLanguage: 'DE', + defaultCountry: 'DE', + defaultLocale: 'de-DE', + currencyCode: 'EUR', + currencySign: 'EUR', + dateFormat: 'HH:mm D-M-YYYY' + } + } + } + + config.tax = { + defaultCountry: 'US', + defaultRegion: '', + sourcePriceIncludesTax: false, + calculateServerSide: true + } + + config.i18n = { + defaultCountry: 'US', + defaultLanguage: 'EN', + availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], + defaultLocale: 'en-US', + currencyCode: 'USD', + currencySign: '$', + currencySignPlacement: 'preppend', + dateFormat: 'HH:mm D/M/YYYY', + fullCountryName: 'United States', + fullLanguageName: 'English', + bundleAllStoreviewLanguages: true + } + + config.elasticsearch = { + httpAuth: '', + host: '/api/catalog', + index: 'vue_storefront_catalog', + min_score: 0.02, + csrTimeout: 5000, + ssrTimeout: 1000, + queryMethod: 'GET', + disablePersistentQueriesCache: true, + searchScoring: { + attributes: { + attribute_code: { + scoreValues: { attribute_value: { weight: 1 } } + } + }, + fuzziness: 2, + cutoff_frequency: 0.01, + max_expansions: 3, + minimum_should_match: '75%', + prefix_length: 2, + boost_mode: 'multiply', + score_mode: 'multiply', + max_boost: 100, + function_min_score: 1 + }, + searchableAttributes: { + name: { + boost: 4 + }, + sku: { + boost: 2 + }, + 'category.name': { + boost: 1 + } + } + } + config.defaultStoreCode = 'de' + + expect(prepareStoreView(null)).toStrictEqual({ + tax: { + sourcePriceIncludesTax: false, + defaultCountry: 'DE', + defaultRegion: '', + calculateServerSide: true + }, + i18n: { + fullCountryName: 'Germany', + fullLanguageName: 'German', + defaultLanguage: 'DE', + defaultCountry: 'DE', + defaultLocale: 'de-DE', + currencyCode: 'EUR', + currencySign: 'EUR', + dateFormat: 'HH:mm D-M-YYYY', + availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], + currencySignPlacement: 'preppend', + bundleAllStoreviewLanguages: true + }, + elasticsearch: { + httpAuth: '', + host: '/api/catalog', + index: 'vue_storefront_catalog_de', + min_score: 0.02, + csrTimeout: 5000, + ssrTimeout: 1000, + queryMethod: 'GET', + disablePersistentQueriesCache: true, + searchScoring: { + attributes: { + attribute_code: { + scoreValues: { attribute_value: { weight: 1 } } + } + }, + fuzziness: 2, + cutoff_frequency: 0.01, + max_expansions: 3, + minimum_should_match: '75%', + prefix_length: 2, + boost_mode: 'multiply', + score_mode: 'multiply', + max_boost: 100, + function_min_score: 1 + }, + searchableAttributes: { + name: { + boost: 4 + }, + sku: { + boost: 2 + }, + 'category.name': { + boost: 1 + } + } + }, + storeId: 3, + name: 'German Store', + appendStoreCode: true, + disabled: true, + url: '/de', + storeCode: 'de' + }) + }) + + it('return default storeView with Store Code it with merged values from store it', () => { + rootStore.state.storeView = {} + rootStore.state.user = {} + + config.storeViews = { + de: { + storeCode: 'de', + disabled: true, + storeId: 3, + name: 'German Store', + url: '/de', + appendStoreCode: true, + elasticsearch: { + host: '/api/catalog', + index: 'vue_storefront_catalog_de' + }, + tax: { + sourcePriceIncludesTax: false, + defaultCountry: 'DE', + defaultRegion: '', + calculateServerSide: true + }, + i18n: { + fullCountryName: 'Germany', + fullLanguageName: 'German', + defaultLanguage: 'DE', + defaultCountry: 'DE', + defaultLocale: 'de-DE', + currencyCode: 'EUR', + currencySign: 'EUR', + dateFormat: 'HH:mm D-M-YYYY' + } + }, + it: { + extend: 'de', + storeCode: 'it', + disabled: true, + storeId: 4, + name: 'Italian Store', + url: '/it', + elasticsearch: { + host: '/api/catalog', + index: 'vue_storefront_catalog_it' + }, + tax: { + defaultCountry: 'IT' + }, + i18n: { + fullCountryName: 'Italy', + fullLanguageName: 'Italian', + defaultCountry: 'IT', + defaultLanguage: 'IT', + defaultLocale: 'it-IT' + } + } + } + + config.tax = { + defaultCountry: 'US', + defaultRegion: '', + sourcePriceIncludesTax: false, + calculateServerSide: true + } + + config.i18n = { + defaultCountry: 'US', + defaultLanguage: 'EN', + availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], + defaultLocale: 'en-US', + currencyCode: 'USD', + currencySign: '$', + currencySignPlacement: 'preppend', + dateFormat: 'HH:mm D/M/YYYY', + fullCountryName: 'United States', + fullLanguageName: 'English', + bundleAllStoreviewLanguages: true + } + + config.elasticsearch = { + httpAuth: '', + host: '/api/catalog', + index: 'vue_storefront_catalog', + min_score: 0.02, + csrTimeout: 5000, + ssrTimeout: 1000, + queryMethod: 'GET', + disablePersistentQueriesCache: true, + searchScoring: { + attributes: { + attribute_code: { + scoreValues: { attribute_value: { weight: 1 } } + } + }, + fuzziness: 2, + cutoff_frequency: 0.01, + max_expansions: 3, + minimum_should_match: '75%', + prefix_length: 2, + boost_mode: 'multiply', + score_mode: 'multiply', + max_boost: 100, + function_min_score: 1 + }, + searchableAttributes: { + name: { + boost: 4 + }, + sku: { + boost: 2 + }, + 'category.name': { + boost: 1 + } + } + } + config.defaultStoreCode = 'it' + + expect(prepareStoreView(null)).toStrictEqual({ + tax: { + sourcePriceIncludesTax: false, + defaultCountry: 'IT', + defaultRegion: '', + calculateServerSide: true + }, + i18n: { + fullCountryName: 'Italy', + fullLanguageName: 'Italian', + defaultCountry: 'IT', + defaultLanguage: 'IT', + defaultLocale: 'it-IT', + currencyCode: 'EUR', + currencySign: 'EUR', + dateFormat: 'HH:mm D-M-YYYY', + availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], + currencySignPlacement: 'preppend', + bundleAllStoreviewLanguages: true + }, + elasticsearch: { + httpAuth: '', + host: '/api/catalog', + index: 'vue_storefront_catalog_it', + min_score: 0.02, + csrTimeout: 5000, + ssrTimeout: 1000, + queryMethod: 'GET', + disablePersistentQueriesCache: true, + searchScoring: { + attributes: { + attribute_code: { + scoreValues: { attribute_value: { weight: 1 } } + } + }, + fuzziness: 2, + cutoff_frequency: 0.01, + max_expansions: 3, + minimum_should_match: '75%', + prefix_length: 2, + boost_mode: 'multiply', + score_mode: 'multiply', + max_boost: 100, + function_min_score: 1 + }, + searchableAttributes: { + name: { + boost: 4 + }, + sku: { + boost: 2 + }, + 'category.name': { + boost: 1 + } + } + }, + storeId: 4, + extend: 'de', + name: 'Italian Store', + appendStoreCode: true, + disabled: true, + url: '/it', + storeCode: 'it' + }) + }) + }) }) diff --git a/test/unit/jest.conf.js b/test/unit/jest.conf.js index 644a93ffd..8d823adf7 100644 --- a/test/unit/jest.conf.js +++ b/test/unit/jest.conf.js @@ -32,7 +32,8 @@ module.exports = { '^.+\\.(css|less)$': '/test/unit/cssStub.js' }, transformIgnorePatterns: [ - '/node_modules/(?!lodash)' + '/node_modules/(?!lodash)', + '/node_modules/(?!lodash-es/.*)' ], setupFiles: [ '/test/unit/setupTestEnvironment.js' From 372559c427a5fdf81b102e0b01ecbd20e2116dae Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 12:39:41 +0200 Subject: [PATCH 0336/1227] refactor cms module to new format --- core/modules-entry.ts | 2 -- core/modules/cms/hooks/beforeRegistration.ts | 14 ----------- core/modules/cms/index.ts | 25 ++++++++----------- core/modules/user/hooks/beforeRegistration.ts | 12 +-------- src/modules/index.ts | 5 ++-- 5 files changed, 14 insertions(+), 44 deletions(-) delete mode 100644 core/modules/cms/hooks/beforeRegistration.ts diff --git a/core/modules-entry.ts b/core/modules-entry.ts index 73ff9ea6f..f14b3079c 100644 --- a/core/modules-entry.ts +++ b/core/modules-entry.ts @@ -1,12 +1,10 @@ import { VueStorefrontModule } from '@vue-storefront/core/lib/module' -import { Cms } from './modules/cms' import { User } from './modules/user' import { registerModules } from 'src/modules' // @deprecated from 2.0, use registerModule instead export const enabledModules: VueStorefrontModule[] = [ - Cms, User, ...registerModules ] diff --git a/core/modules/cms/hooks/beforeRegistration.ts b/core/modules/cms/hooks/beforeRegistration.ts deleted file mode 100644 index 4ef3eb891..000000000 --- a/core/modules/cms/hooks/beforeRegistration.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as localForage from 'localforage' -import UniversalStorage from '@vue-storefront/core/store/lib/storage' -import { currentStoreView } from '@vue-storefront/core/lib/multistore' -import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' - -export function beforeRegistration ({ Vue, config, store, isServer }) { - const storeView = currentStoreView() - const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - - StorageManager.set('cmsData', new UniversalStorage(localForage.createInstance({ - name: dbNamePrefix + 'shop', - storeName: 'cms' - }))) -} diff --git a/core/modules/cms/index.ts b/core/modules/cms/index.ts index 737e3935f..62dfb11a6 100644 --- a/core/modules/cms/index.ts +++ b/core/modules/cms/index.ts @@ -1,20 +1,15 @@ import { cmsPageModule } from './store/page' import { cmsBlockModule } from './store/block' import { cmsHierarchyModule } from './store/hierarchy' -import { createModule } from '@vue-storefront/core/lib/module' -import { beforeRegistration } from './hooks/beforeRegistration' import { plugin } from './store/plugin' -import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage'; +import { StorefrontModule } from '@vue-storefront/module'; +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' -export const KEY = 'cms' -export const cacheStorage = initCacheStorage(KEY) -export const Cms = createModule({ - key: KEY, - store: { modules: [ - { key: 'cmsPage', module: cmsPageModule }, - { key: 'cmsBlock', module: cmsBlockModule }, - { key: 'cmsHierarchy', module: cmsHierarchyModule } - ], - plugin }, - beforeRegistration -}) +export const cacheStorage = StorageManager.init('cms') + +export const CmsModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { + store.registerModule('cmsPage', cmsPageModule) + store.registerModule('cmsBlock', cmsBlockModule) + store.registerModule('cmsHierarchy', cmsHierarchyModule) + store.subscribe(plugin) +} diff --git a/core/modules/user/hooks/beforeRegistration.ts b/core/modules/user/hooks/beforeRegistration.ts index 0c01095bc..bb197011a 100644 --- a/core/modules/user/hooks/beforeRegistration.ts +++ b/core/modules/user/hooks/beforeRegistration.ts @@ -1,15 +1,5 @@ -import * as localForage from 'localforage' -import UniversalStorage from '@vue-storefront/core/store/lib/storage' -import { currentStoreView } from '@vue-storefront/core/lib/multistore' import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export function beforeRegistration ({ Vue, config, store, isServer }) { - const storeView = currentStoreView() - const dbNamePrefix = storeView.storeCode ? storeView.storeCode + '-' : '' - - StorageManager.set('user', new UniversalStorage(localForage.createInstance({ - name: (config.storeViews.commonCache ? '' : dbNamePrefix) + 'shop', - storeName: 'user', - driver: localForage[config.localForage.defaultDrivers['user']] - }))) + StorageManager.init('user') } diff --git a/src/modules/index.ts b/src/modules/index.ts index 7c07753ed..d8486017f 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -13,7 +13,7 @@ import { RecentlyViewedModule } from '@vue-storefront/core/modules/recently-view import { UrlModule } from '@vue-storefront/core/modules/url' import { BreadcrumbsModule } from '@vue-storefront/core/modules/breadcrumbs' import { OrderModule } from '@vue-storefront/core/modules/order' - +import { CmsModule } from '@vue-storefront/core/modules/cms' // import { GoogleAnalyticsModule } from './google-analytics'; // import { HotjarModule } from './hotjar'; import { GoogleTagManagerModule } from './google-tag-manager'; @@ -27,6 +27,7 @@ import { registerModule } from '@vue-storefront/module' // TODO:distributed across proper pages BEFORE 1.11 export function registerNewModules () { + registerModule(UrlModule) registerModule(CatalogModule) registerModule(CheckoutModule) registerModule(CartModule) @@ -44,11 +45,11 @@ export function registerNewModules () { registerModule(RawOutputExampleModule) registerModule(AmpRendererModule) registerModule(InstantCheckoutModule) - registerModule(UrlModule) registerModule(CatalogNextModule) registerModule(CompareModule) registerModule(BreadcrumbsModule) registerModule(OrderModule) + registerModule(CmsModule) } // Deprecated API, will be removed in 2.0 From 8b1fc6d0748ea33577887ee0133ef8e7033f2039 Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Wed, 17 Jul 2019 13:00:27 +0200 Subject: [PATCH 0337/1227] Added changelog entry for pr #3244 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3baa952d..630bf1bb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed aspect ratio in ProductImage component - @przspa (#3187) - Fixed AMP Product page - @przspa (#3227) - Fixed when store has updated, but plugin didn't called - @serzilo (#3238) +- Fixed first call of prepareStoreView when SSR - @resubaka (#3244) ### Changed / Improved - Shipping address is saved as default when not logged in user chooses to create account during checkout - @iwonapiotrowska (#2636) From a0c48f460e446cae282822dd5761a71c362925f5 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 13:02:59 +0200 Subject: [PATCH 0338/1227] refactor user module to new format --- core/modules-entry.ts | 2 - core/modules/user/index.ts | 79 ++++++++++++++++++++++++++------ core/modules/user/store/index.ts | 2 +- src/modules/index.ts | 13 ++++-- 4 files changed, 74 insertions(+), 22 deletions(-) diff --git a/core/modules-entry.ts b/core/modules-entry.ts index f14b3079c..73d69ec35 100644 --- a/core/modules-entry.ts +++ b/core/modules-entry.ts @@ -1,10 +1,8 @@ import { VueStorefrontModule } from '@vue-storefront/core/lib/module' -import { User } from './modules/user' import { registerModules } from 'src/modules' // @deprecated from 2.0, use registerModule instead export const enabledModules: VueStorefrontModule[] = [ - User, ...registerModules ] diff --git a/core/modules/user/index.ts b/core/modules/user/index.ts index ea5f0ba79..9caf97857 100644 --- a/core/modules/user/index.ts +++ b/core/modules/user/index.ts @@ -1,15 +1,66 @@ -import { module } from './store' -import { createModule } from '@vue-storefront/core/lib/module' +import { userStore } from './store' import { beforeEach } from './router/beforeEach' -import { beforeRegistration } from './hooks/beforeRegistration' -import { afterRegistration } from './hooks/afterRegistration' - -export const KEY = 'user' - -export const User = createModule({ - key: KEY, - store: { modules: [{ key: KEY, module }] }, - beforeRegistration, - afterRegistration, - router: { beforeEach } -}) +import { StorefrontModule } from '@vue-storefront/module' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' +import { isServer } from '@vue-storefront/core/helpers' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import * as types from './store/mutation-types' + +export const UserModule: StorefrontModule = async function (app, store, router, moduleConfig, appConfig) { + StorageManager.init('user') + store.registerModule('user', userStore) + router.beforeEach(beforeEach) + if (!isServer) { + await store.dispatch('user/startSession') + + EventBus.$on('user-before-logout', () => { + store.dispatch('user/logout', { silent: false }) + // TODO: Move it to theme + store.commit('ui/setSubmenu', { + depth: 0 + }) + }) + + EventBus.$on('user-after-loggedin', receivedData => { + // TODO: Make independent of checkout module + store.dispatch('checkout/savePersonalDetails', { + firstName: receivedData.firstname, + lastName: receivedData.lastname, + emailAddress: receivedData.email + }) + }) + } + + store.subscribe((mutation, state) => { + const type = mutation.type + + if ( + type.endsWith(types.USER_INFO_LOADED) + ) { + StorageManager.get('user').setItem('current-user', state.user.current).catch((reason) => { + console.error(reason) // it doesn't work on SSR + }) // populate cache + } + + if ( + type.endsWith(types.USER_ORDERS_HISTORY_LOADED) + ) { + StorageManager.get('user').setItem('orders-history', state.user.orders_history).catch((reason) => { + console.error(reason) // it doesn't work on SSR + }) // populate cache + } + + if ( + type.endsWith(types.USER_TOKEN_CHANGED) + ) { + StorageManager.get('user').setItem('current-token', state.user.token).catch((reason) => { + console.error(reason) // it doesn't work on SSR + }) // populate cache + if (state.user.refreshToken) { + StorageManager.get('user').setItem('current-refresh-token', state.user.refreshToken).catch((reason) => { + console.error(reason) // it doesn't work on SSR + }) // populate cache + } + } + }) +} diff --git a/core/modules/user/store/index.ts b/core/modules/user/store/index.ts index 94101758c..eca304504 100644 --- a/core/modules/user/store/index.ts +++ b/core/modules/user/store/index.ts @@ -5,7 +5,7 @@ import mutations from './mutations' import RootState from '@vue-storefront/core/types/RootState' import UserState from '../types/UserState' -export const module: Module = { +export const userStore: Module = { namespaced: true, state: { token: '', diff --git a/src/modules/index.ts b/src/modules/index.ts index d8486017f..782a6d37c 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -14,6 +14,7 @@ import { UrlModule } from '@vue-storefront/core/modules/url' import { BreadcrumbsModule } from '@vue-storefront/core/modules/breadcrumbs' import { OrderModule } from '@vue-storefront/core/modules/order' import { CmsModule } from '@vue-storefront/core/modules/cms' +import { UserModule }from '@vue-storefront/core/modules/user' // import { GoogleAnalyticsModule } from './google-analytics'; // import { HotjarModule } from './hotjar'; import { GoogleTagManagerModule } from './google-tag-manager'; @@ -36,6 +37,12 @@ export function registerNewModules () { registerModule(WishlistModule) registerModule(NewsletterModule) registerModule(NotificationModule) + registerModule(UserModule) + registerModule(CatalogNextModule) + registerModule(CompareModule) + registerModule(BreadcrumbsModule) + registerModule(OrderModule) + registerModule(CmsModule) registerModule(RecentlyViewedModule) registerModule(GoogleTagManagerModule) // registerModule(GoogleAnalyticsModule) @@ -45,11 +52,7 @@ export function registerNewModules () { registerModule(RawOutputExampleModule) registerModule(AmpRendererModule) registerModule(InstantCheckoutModule) - registerModule(CatalogNextModule) - registerModule(CompareModule) - registerModule(BreadcrumbsModule) - registerModule(OrderModule) - registerModule(CmsModule) + } // Deprecated API, will be removed in 2.0 From 27ded4380bd8f26d796adbb86faf6a11945378d2 Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Wed, 17 Jul 2019 13:30:58 +0200 Subject: [PATCH 0339/1227] cleanup prepareStoreView tests --- core/lib/test/unit/multistore.spec.ts | 459 ++------------------------ 1 file changed, 32 insertions(+), 427 deletions(-) diff --git a/core/lib/test/unit/multistore.spec.ts b/core/lib/test/unit/multistore.spec.ts index 93a5f7ecb..804aaed63 100644 --- a/core/lib/test/unit/multistore.spec.ts +++ b/core/lib/test/unit/multistore.spec.ts @@ -7,8 +7,8 @@ jest.mock('../../../store', () => ({})) jest.mock('@vue-storefront/i18n', () => ({loadLanguageAsync: jest.fn()})) jest.mock('../../sync/task', () => ({initializeSyncTaskStorage: jest.fn()})) jest.mock('@vue-storefront/core/hooks', () => ({ coreHooksExecutors: { - beforeStoreViewChange: jest.fn(), - afterStoreViewChange: jest.fn() + beforeStoreViewChange: jest.fn(args => args), + afterStoreViewChange: jest.fn(args => args) }})) jest.mock('query-string', () => jest.fn()) jest.mock('@vue-storefront/core/lib/router-manager', () => ({ @@ -140,121 +140,31 @@ describe('Multistore', () => { rootStore.state.user = {} config.tax = { - defaultCountry: 'US', - defaultRegion: '', - sourcePriceIncludesTax: false, - calculateServerSide: true + defaultCountry: 'US' } config.i18n = { - defaultCountry: 'US', - defaultLanguage: 'EN', - availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], defaultLocale: 'en-US', - currencyCode: 'USD', - currencySign: '$', - currencySignPlacement: 'preppend', - dateFormat: 'HH:mm D/M/YYYY', fullCountryName: 'United States', - fullLanguageName: 'English', - bundleAllStoreviewLanguages: true + fullLanguageName: 'English' } config.elasticsearch = { - httpAuth: '', - host: '/api/catalog', - index: 'vue_storefront_catalog', - min_score: 0.02, - csrTimeout: 5000, - ssrTimeout: 1000, - queryMethod: 'GET', - disablePersistentQueriesCache: true, - searchScoring: { - attributes: { - attribute_code: { - scoreValues: { attribute_value: { weight: 1 } } - } - }, - fuzziness: 2, - cutoff_frequency: 0.01, - max_expansions: 3, - minimum_should_match: '75%', - prefix_length: 2, - boost_mode: 'multiply', - score_mode: 'multiply', - max_boost: 100, - function_min_score: 1 - }, - searchableAttributes: { - name: { - boost: 4 - }, - sku: { - boost: 2 - }, - 'category.name': { - boost: 1 - } - } + index: 'vue_storefront_catalog' } config.defaultStoreCode = '' expect(prepareStoreView(null)).toStrictEqual({ tax: { - defaultCountry: 'US', - defaultRegion: '', - sourcePriceIncludesTax: false, - calculateServerSide: true + defaultCountry: 'US' }, i18n: { - defaultCountry: 'US', - defaultLanguage: 'EN', - availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], defaultLocale: 'en-US', - currencyCode: 'USD', - currencySign: '$', - currencySignPlacement: 'preppend', - dateFormat: 'HH:mm D/M/YYYY', fullCountryName: 'United States', - fullLanguageName: 'English', - bundleAllStoreviewLanguages: true + fullLanguageName: 'English' }, elasticsearch: { - httpAuth: '', - host: '/api/catalog', - index: 'vue_storefront_catalog', - min_score: 0.02, - csrTimeout: 5000, - ssrTimeout: 1000, - queryMethod: 'GET', - disablePersistentQueriesCache: true, - searchScoring: { - attributes: { - attribute_code: { - scoreValues: { attribute_value: { weight: 1 } } - } - }, - fuzziness: 2, - cutoff_frequency: 0.01, - max_expansions: 3, - minimum_should_match: '75%', - prefix_length: 2, - boost_mode: 'multiply', - score_mode: 'multiply', - max_boost: 100, - function_min_score: 1 - }, - searchableAttributes: { - name: { - boost: 4 - }, - sku: { - boost: 2 - }, - 'category.name': { - boost: 1 - } - } + index: 'vue_storefront_catalog' }, storeId: 1, storeCode: '' @@ -267,128 +177,38 @@ describe('Multistore', () => { config.storeViews = { de: { - storeId: 1 + storeId: 4 } } config.tax = { - defaultCountry: 'US', - defaultRegion: '', - sourcePriceIncludesTax: false, - calculateServerSide: true + defaultCountry: 'US' } config.i18n = { - defaultCountry: 'US', - defaultLanguage: 'EN', - availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], defaultLocale: 'en-US', - currencyCode: 'USD', - currencySign: '$', - currencySignPlacement: 'preppend', - dateFormat: 'HH:mm D/M/YYYY', fullCountryName: 'United States', - fullLanguageName: 'English', - bundleAllStoreviewLanguages: true + fullLanguageName: 'English' } config.elasticsearch = { - httpAuth: '', - host: '/api/catalog', - index: 'vue_storefront_catalog', - min_score: 0.02, - csrTimeout: 5000, - ssrTimeout: 1000, - queryMethod: 'GET', - disablePersistentQueriesCache: true, - searchScoring: { - attributes: { - attribute_code: { - scoreValues: { attribute_value: { weight: 1 } } - } - }, - fuzziness: 2, - cutoff_frequency: 0.01, - max_expansions: 3, - minimum_should_match: '75%', - prefix_length: 2, - boost_mode: 'multiply', - score_mode: 'multiply', - max_boost: 100, - function_min_score: 1 - }, - searchableAttributes: { - name: { - boost: 4 - }, - sku: { - boost: 2 - }, - 'category.name': { - boost: 1 - } - } + index: 'vue_storefront_catalog' } config.defaultStoreCode = 'de' expect(prepareStoreView(null)).toStrictEqual({ tax: { - defaultCountry: 'US', - defaultRegion: '', - sourcePriceIncludesTax: false, - calculateServerSide: true + defaultCountry: 'US' }, i18n: { - defaultCountry: 'US', - defaultLanguage: 'EN', - availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], defaultLocale: 'en-US', - currencyCode: 'USD', - currencySign: '$', - currencySignPlacement: 'preppend', - dateFormat: 'HH:mm D/M/YYYY', fullCountryName: 'United States', - fullLanguageName: 'English', - bundleAllStoreviewLanguages: true + fullLanguageName: 'English' }, elasticsearch: { - httpAuth: '', - host: '/api/catalog', - index: 'vue_storefront_catalog', - min_score: 0.02, - csrTimeout: 5000, - ssrTimeout: 1000, - queryMethod: 'GET', - disablePersistentQueriesCache: true, - searchScoring: { - attributes: { - attribute_code: { - scoreValues: { attribute_value: { weight: 1 } } - } - }, - fuzziness: 2, - cutoff_frequency: 0.01, - max_expansions: 3, - minimum_should_match: '75%', - prefix_length: 2, - boost_mode: 'multiply', - score_mode: 'multiply', - max_boost: 100, - function_min_score: 1 - }, - searchableAttributes: { - name: { - boost: 4 - }, - sku: { - boost: 2 - }, - 'category.name': { - boost: 1 - } - } + index: 'vue_storefront_catalog' }, - storeId: 1, + storeId: 4, storeCode: 'de' }) }) @@ -400,156 +220,51 @@ describe('Multistore', () => { config.storeViews = { de: { storeCode: 'de', - disabled: true, storeId: 3, name: 'German Store', - url: '/de', - appendStoreCode: true, elasticsearch: { - host: '/api/catalog', index: 'vue_storefront_catalog_de' }, tax: { - sourcePriceIncludesTax: false, - defaultCountry: 'DE', - defaultRegion: '', - calculateServerSide: true + defaultCountry: 'DE' }, i18n: { fullCountryName: 'Germany', fullLanguageName: 'German', - defaultLanguage: 'DE', - defaultCountry: 'DE', - defaultLocale: 'de-DE', - currencyCode: 'EUR', - currencySign: 'EUR', - dateFormat: 'HH:mm D-M-YYYY' + defaultLocale: 'de-DE' } } } config.tax = { - defaultCountry: 'US', - defaultRegion: '', - sourcePriceIncludesTax: false, - calculateServerSide: true + defaultCountry: 'US' } config.i18n = { - defaultCountry: 'US', - defaultLanguage: 'EN', - availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], defaultLocale: 'en-US', - currencyCode: 'USD', - currencySign: '$', - currencySignPlacement: 'preppend', - dateFormat: 'HH:mm D/M/YYYY', fullCountryName: 'United States', - fullLanguageName: 'English', - bundleAllStoreviewLanguages: true + fullLanguageName: 'English' } config.elasticsearch = { - httpAuth: '', - host: '/api/catalog', - index: 'vue_storefront_catalog', - min_score: 0.02, - csrTimeout: 5000, - ssrTimeout: 1000, - queryMethod: 'GET', - disablePersistentQueriesCache: true, - searchScoring: { - attributes: { - attribute_code: { - scoreValues: { attribute_value: { weight: 1 } } - } - }, - fuzziness: 2, - cutoff_frequency: 0.01, - max_expansions: 3, - minimum_should_match: '75%', - prefix_length: 2, - boost_mode: 'multiply', - score_mode: 'multiply', - max_boost: 100, - function_min_score: 1 - }, - searchableAttributes: { - name: { - boost: 4 - }, - sku: { - boost: 2 - }, - 'category.name': { - boost: 1 - } - } + index: 'vue_storefront_catalog' } config.defaultStoreCode = 'de' expect(prepareStoreView(null)).toStrictEqual({ tax: { - sourcePriceIncludesTax: false, - defaultCountry: 'DE', - defaultRegion: '', - calculateServerSide: true + defaultCountry: 'DE' }, i18n: { fullCountryName: 'Germany', fullLanguageName: 'German', - defaultLanguage: 'DE', - defaultCountry: 'DE', - defaultLocale: 'de-DE', - currencyCode: 'EUR', - currencySign: 'EUR', - dateFormat: 'HH:mm D-M-YYYY', - availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], - currencySignPlacement: 'preppend', - bundleAllStoreviewLanguages: true + defaultLocale: 'de-DE' }, elasticsearch: { - httpAuth: '', - host: '/api/catalog', - index: 'vue_storefront_catalog_de', - min_score: 0.02, - csrTimeout: 5000, - ssrTimeout: 1000, - queryMethod: 'GET', - disablePersistentQueriesCache: true, - searchScoring: { - attributes: { - attribute_code: { - scoreValues: { attribute_value: { weight: 1 } } - } - }, - fuzziness: 2, - cutoff_frequency: 0.01, - max_expansions: 3, - minimum_should_match: '75%', - prefix_length: 2, - boost_mode: 'multiply', - score_mode: 'multiply', - max_boost: 100, - function_min_score: 1 - }, - searchableAttributes: { - name: { - boost: 4 - }, - sku: { - boost: 2 - }, - 'category.name': { - boost: 1 - } - } + index: 'vue_storefront_catalog_de' }, storeId: 3, name: 'German Store', - appendStoreCode: true, - disabled: true, - url: '/de', storeCode: 'de' }) }) @@ -561,41 +276,26 @@ describe('Multistore', () => { config.storeViews = { de: { storeCode: 'de', - disabled: true, storeId: 3, name: 'German Store', - url: '/de', - appendStoreCode: true, elasticsearch: { - host: '/api/catalog', index: 'vue_storefront_catalog_de' }, tax: { - sourcePriceIncludesTax: false, - defaultCountry: 'DE', - defaultRegion: '', - calculateServerSide: true + defaultCountry: 'DE' }, i18n: { fullCountryName: 'Germany', fullLanguageName: 'German', - defaultLanguage: 'DE', - defaultCountry: 'DE', - defaultLocale: 'de-DE', - currencyCode: 'EUR', - currencySign: 'EUR', - dateFormat: 'HH:mm D-M-YYYY' + defaultLocale: 'de-DE' } }, it: { extend: 'de', storeCode: 'it', - disabled: true, storeId: 4, name: 'Italian Store', - url: '/it', elasticsearch: { - host: '/api/catalog', index: 'vue_storefront_catalog_it' }, tax: { @@ -604,136 +304,41 @@ describe('Multistore', () => { i18n: { fullCountryName: 'Italy', fullLanguageName: 'Italian', - defaultCountry: 'IT', - defaultLanguage: 'IT', defaultLocale: 'it-IT' } } } config.tax = { - defaultCountry: 'US', - defaultRegion: '', - sourcePriceIncludesTax: false, - calculateServerSide: true + defaultCountry: 'US' } config.i18n = { - defaultCountry: 'US', - defaultLanguage: 'EN', - availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], defaultLocale: 'en-US', - currencyCode: 'USD', - currencySign: '$', - currencySignPlacement: 'preppend', - dateFormat: 'HH:mm D/M/YYYY', fullCountryName: 'United States', - fullLanguageName: 'English', - bundleAllStoreviewLanguages: true + fullLanguageName: 'English' } config.elasticsearch = { - httpAuth: '', - host: '/api/catalog', - index: 'vue_storefront_catalog', - min_score: 0.02, - csrTimeout: 5000, - ssrTimeout: 1000, - queryMethod: 'GET', - disablePersistentQueriesCache: true, - searchScoring: { - attributes: { - attribute_code: { - scoreValues: { attribute_value: { weight: 1 } } - } - }, - fuzziness: 2, - cutoff_frequency: 0.01, - max_expansions: 3, - minimum_should_match: '75%', - prefix_length: 2, - boost_mode: 'multiply', - score_mode: 'multiply', - max_boost: 100, - function_min_score: 1 - }, - searchableAttributes: { - name: { - boost: 4 - }, - sku: { - boost: 2 - }, - 'category.name': { - boost: 1 - } - } + index: 'vue_storefront_catalog' } config.defaultStoreCode = 'it' expect(prepareStoreView(null)).toStrictEqual({ tax: { - sourcePriceIncludesTax: false, - defaultCountry: 'IT', - defaultRegion: '', - calculateServerSide: true + defaultCountry: 'IT' }, i18n: { fullCountryName: 'Italy', fullLanguageName: 'Italian', - defaultCountry: 'IT', - defaultLanguage: 'IT', - defaultLocale: 'it-IT', - currencyCode: 'EUR', - currencySign: 'EUR', - dateFormat: 'HH:mm D-M-YYYY', - availableLocale: ['en-US', 'de-DE', 'fr-FR', 'es-ES', 'nl-NL', 'jp-JP', 'ru-RU', 'it-IT', 'pt-BR', 'pl-PL', 'cs-CZ'], - currencySignPlacement: 'preppend', - bundleAllStoreviewLanguages: true + defaultLocale: 'it-IT' }, elasticsearch: { - httpAuth: '', - host: '/api/catalog', - index: 'vue_storefront_catalog_it', - min_score: 0.02, - csrTimeout: 5000, - ssrTimeout: 1000, - queryMethod: 'GET', - disablePersistentQueriesCache: true, - searchScoring: { - attributes: { - attribute_code: { - scoreValues: { attribute_value: { weight: 1 } } - } - }, - fuzziness: 2, - cutoff_frequency: 0.01, - max_expansions: 3, - minimum_should_match: '75%', - prefix_length: 2, - boost_mode: 'multiply', - score_mode: 'multiply', - max_boost: 100, - function_min_score: 1 - }, - searchableAttributes: { - name: { - boost: 4 - }, - sku: { - boost: 2 - }, - 'category.name': { - boost: 1 - } - } + index: 'vue_storefront_catalog_it' }, storeId: 4, extend: 'de', name: 'Italian Store', - appendStoreCode: true, - disabled: true, - url: '/it', storeCode: 'it' }) }) From 64ef84aa1e57012599840d1491a1380c8a09ee85 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 13:33:53 +0200 Subject: [PATCH 0340/1227] rewrite sample custom gql entity module to new format --- src/modules/index.ts | 3 +- .../sample-custom-entity-graphql/index.ts | 71 ++++++++++++++++--- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/modules/index.ts b/src/modules/index.ts index 782a6d37c..018049cc4 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -14,7 +14,7 @@ import { UrlModule } from '@vue-storefront/core/modules/url' import { BreadcrumbsModule } from '@vue-storefront/core/modules/breadcrumbs' import { OrderModule } from '@vue-storefront/core/modules/order' import { CmsModule } from '@vue-storefront/core/modules/cms' -import { UserModule }from '@vue-storefront/core/modules/user' +import { UserModule } from '@vue-storefront/core/modules/user' // import { GoogleAnalyticsModule } from './google-analytics'; // import { HotjarModule } from './hotjar'; import { GoogleTagManagerModule } from './google-tag-manager'; @@ -52,7 +52,6 @@ export function registerNewModules () { registerModule(RawOutputExampleModule) registerModule(AmpRendererModule) registerModule(InstantCheckoutModule) - } // Deprecated API, will be removed in 2.0 diff --git a/src/modules/sample-custom-entity-graphql/index.ts b/src/modules/sample-custom-entity-graphql/index.ts index 60a4d86a6..1cd664a29 100644 --- a/src/modules/sample-custom-entity-graphql/index.ts +++ b/src/modules/sample-custom-entity-graphql/index.ts @@ -1,8 +1,63 @@ -import { createModule } from '@vue-storefront/core/lib/module' -import { afterRegistration } from './hooks/afterRegistration' - -const KEY = 'sample-custom-entity-gql' -export const SampleCustomEntityGql = createModule({ - key: KEY, - afterRegistration -}) +import { getSearchAdapter } from '@vue-storefront/core/lib/search/adapter/searchAdapterFactory' +import { processESResponseType } from '@vue-storefront/core/lib/search/adapter/graphql/processor/processType' +import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' +import { Logger } from '@vue-storefront/core/lib/logger' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { StorefrontModule } from '@vue-storefront/module' + +const TEST_ENTITY_TYPE = 'testentity' + +export const CustomEntityGqlModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { + EventBus.$on('application-after-init', async () => { + Logger.debug('Example of custom entity graphql extension')() + + // create GraphQL searchAdapter + let searchAdapter = await getSearchAdapter('graphql') + + // register custom entity type using registerEntityTypeByQuery + // different GraphQL servers could be used for different entity types + // resolver for testentity should be implemented on the GraphQL server provided + searchAdapter.registerEntityTypeByQuery(TEST_ENTITY_TYPE, { + url: 'http://localhost:8080/graphql/', + query: require('../queries/testentity.gql'), + queryProcessor: (query) => { + // function that can modify the query each time before it's being executed + return query + }, + resultPorcessor: (resp, start, size) => { + if (resp === null) { + throw new Error('Invalid GraphQL result - null not expected') + } + if (resp.hasOwnProperty('data')) { + return processESResponseType(resp.data.testentity, start, size) + } else { + if (resp.error) { + throw new Error(JSON.stringify(resp.error)) + } else { + throw new Error('Unknown error with GraphQL result in resultProcessor for entity type \'category\'') + } + } + } + }) + + const storeView = currentStoreView() + + // create an empty SearchQuery to get all data for the new custom entity + const searchQuery = new SearchQuery() + + // prepare a SearchRequest object + const Request = { + store: storeView.storeCode, // TODO: add grouped product and bundled product support + type: TEST_ENTITY_TYPE, + searchQuery: searchQuery, + sort: '' + } + + // apply test search + searchAdapter.search(Request).then((resp) => { // we're always trying to populate cache - when online + const res = searchAdapter.entities[Request.type].resultPorcessor(resp, 0, 200) + Logger.log('Testentity response: ', res)() + }) + }) +} From e09f5529f3b7ffeb249bad2912792c2b473cc5fb Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Wed, 17 Jul 2019 13:43:43 +0200 Subject: [PATCH 0341/1227] Added check if mutlistore is enabled before using defaultStoreCode --- core/lib/multistore.ts | 9 ++++- core/lib/test/unit/multistore.spec.ts | 57 +++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 6fa736ef0..2b7d3908e 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -80,9 +80,16 @@ export function prepareStoreView (storeCode: string): StoreView { tax: config.tax, i18n: config.i18n, elasticsearch: config.elasticsearch, - storeCode: storeCode || config.defaultStoreCode || '', + storeCode: null, storeId: config.defaultStoreCode && config.defaultStoreCode !== '' ? config.storeViews[config.defaultStoreCode].storeId : 1 } + + if (config.storeViews.multistore) { + storeView.storeCode = storeCode || config.defaultStoreCode || '' + } else { + storeView.storeCode = storeCode || '' + } + const storeViewHasChanged = !rootStore.state.storeView || rootStore.state.storeView.storeCode !== storeCode if (storeView.storeCode && config.storeViews[storeView.storeCode]) { diff --git a/core/lib/test/unit/multistore.spec.ts b/core/lib/test/unit/multistore.spec.ts index 804aaed63..78e345017 100644 --- a/core/lib/test/unit/multistore.spec.ts +++ b/core/lib/test/unit/multistore.spec.ts @@ -139,6 +139,10 @@ describe('Multistore', () => { rootStore.state.storeView = {} rootStore.state.user = {} + config.storeViews = { + multistore: false + } + config.tax = { defaultCountry: 'US' } @@ -171,11 +175,55 @@ describe('Multistore', () => { }) }) - it('return default storeView with Store Code de', () => { + it('return default storeView with defaultStoreCode set to de and multistore set to false', () => { rootStore.state.storeView = {} rootStore.state.user = {} config.storeViews = { + multistore: false, + de: { + storeId: 4 + } + } + + config.tax = { + defaultCountry: 'US' + } + + config.i18n = { + defaultLocale: 'en-US', + fullCountryName: 'United States', + fullLanguageName: 'English' + } + + config.elasticsearch = { + index: 'vue_storefront_catalog' + } + config.defaultStoreCode = 'de' + + expect(prepareStoreView(null)).toStrictEqual({ + tax: { + defaultCountry: 'US' + }, + i18n: { + defaultLocale: 'en-US', + fullCountryName: 'United States', + fullLanguageName: 'English' + }, + elasticsearch: { + index: 'vue_storefront_catalog' + }, + storeId: 4, + storeCode: '' + }) + }) + + it('return default storeView with defaultStoreCode set to de', () => { + rootStore.state.storeView = {} + rootStore.state.user = {} + + config.storeViews = { + multistore: true, de: { storeId: 4 } @@ -213,11 +261,13 @@ describe('Multistore', () => { }) }) - it('return default storeView with Store Code de with merged values from store de', () => { + + it('return de storeView with merged store config values', () => { rootStore.state.storeView = {} rootStore.state.user = {} config.storeViews = { + multistore: true, de: { storeCode: 'de', storeId: 3, @@ -269,11 +319,12 @@ describe('Multistore', () => { }) }) - it('return default storeView with Store Code it with merged values from store it', () => { + it('return it storeView with merged store config values', () => { rootStore.state.storeView = {} rootStore.state.user = {} config.storeViews = { + multistore: true, de: { storeCode: 'de', storeId: 3, From 5bb31909b71c1940a796463cdc83a0f85629ca9d Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 13:53:09 +0200 Subject: [PATCH 0342/1227] rewrite customentityGql and deprecate extensions --- core/app.ts | 4 -- core/compatibility/lib/extensions.ts | 14 ---- src/extensions/index.ts | 5 -- .../hooks/afterRegistration.ts | 64 ------------------- .../sample-custom-entity-graphql/index.ts | 2 +- .../{queries => }/testentity.gql | 0 6 files changed, 1 insertion(+), 88 deletions(-) delete mode 100644 core/compatibility/lib/extensions.ts delete mode 100644 src/extensions/index.ts delete mode 100644 src/modules/sample-custom-entity-graphql/hooks/afterRegistration.ts rename src/modules/sample-custom-entity-graphql/{queries => }/testentity.gql (100%) diff --git a/core/app.ts b/core/app.ts index 3b1d73135..fe4da6d06 100755 --- a/core/app.ts +++ b/core/app.ts @@ -31,9 +31,6 @@ import store from '@vue-storefront/core/store' import { enabledModules } from './modules-entry' -// Will be deprecated in 2.0 -import { registerExtensions } from '@vue-storefront/core/compatibility/lib/extensions' -import { registerExtensions as extensions } from 'src/extensions' import globalConfig from 'config' import { injectReferences } from '@vue-storefront/module' @@ -119,7 +116,6 @@ const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vu injectReferences(app, store, router, globalConfig) registerNewModules() registerModules(enabledModules, appContext) - registerExtensions(extensions, app, router, store, config, ssrContext) registerTheme(globalConfig.theme, app, router, store, globalConfig, ssrContext) coreHooksExecutors.afterAppInit() diff --git a/core/compatibility/lib/extensions.ts b/core/compatibility/lib/extensions.ts deleted file mode 100644 index 6a2567dfd..000000000 --- a/core/compatibility/lib/extensions.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Logger } from '@vue-storefront/core/lib/logger' - -export function registerExtensions (extensions, app, router, store, config, ssrContext = null) { - for (let extEntryPoint of extensions) { - if (extEntryPoint !== null) { - if (extEntryPoint.default) extEntryPoint = extEntryPoint.default - let extDescriptor = extEntryPoint(app, router, store, config, ssrContext) // register module - if (extDescriptor != null) { - Logger.warn('Extension' + extDescriptor.EXTENSION_KEY + ' registered. Extensions are deprecated and will be removed from VS core. Use modules instead')() - app.$emit('application-after-registerExtensions', extDescriptor) - } - } - } -} diff --git a/src/extensions/index.ts b/src/extensions/index.ts deleted file mode 100644 index 8519f17dc..000000000 --- a/src/extensions/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -/** - * If you have some extensions that are not yet ported to modules you can register them here - * Keep in mind that extensions will be depreciated in next versions of Vue Storefront and replaced by modules - */ -export const registerExtensions = [] diff --git a/src/modules/sample-custom-entity-graphql/hooks/afterRegistration.ts b/src/modules/sample-custom-entity-graphql/hooks/afterRegistration.ts deleted file mode 100644 index 1195b1ec3..000000000 --- a/src/modules/sample-custom-entity-graphql/hooks/afterRegistration.ts +++ /dev/null @@ -1,64 +0,0 @@ - -import { getSearchAdapter } from '@vue-storefront/core/lib/search/adapter/searchAdapterFactory' -import { processESResponseType } from '@vue-storefront/core/lib/search/adapter/graphql/processor/processType' -import { currentStoreView } from '@vue-storefront/core/lib/multistore' -import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' -import { Logger } from '@vue-storefront/core/lib/logger' -import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' - -const EXTENSION_KEY = 'sample-custom-entity-graphql-extension' -const TEST_ENTITY_TYPE = 'testentity' - -export function afterRegistration ({ Vue, config, store, isServer }) { - EventBus.$on('application-after-init', async () => { - Logger.debug('Example of custom entity graphql extension')() - - // create GraphQL searchAdapter - let searchAdapter = await getSearchAdapter('graphql') - - // register custom entity type using registerEntityTypeByQuery - // different GraphQL servers could be used for different entity types - // resolver for testentity should be implemented on the GraphQL server provided - searchAdapter.registerEntityTypeByQuery(TEST_ENTITY_TYPE, { - url: 'http://localhost:8080/graphql/', - query: require('../queries/testentity.gql'), - queryProcessor: (query) => { - // function that can modify the query each time before it's being executed - return query - }, - resultPorcessor: (resp, start, size) => { - if (resp === null) { - throw new Error('Invalid GraphQL result - null not expected') - } - if (resp.hasOwnProperty('data')) { - return processESResponseType(resp.data.testentity, start, size) - } else { - if (resp.error) { - throw new Error(JSON.stringify(resp.error)) - } else { - throw new Error('Unknown error with GraphQL result in resultProcessor for entity type \'category\'') - } - } - } - }) - - const storeView = currentStoreView() - - // create an empty SearchQuery to get all data for the new custom entity - const searchQuery = new SearchQuery() - - // prepare a SearchRequest object - const Request = { - store: storeView.storeCode, // TODO: add grouped product and bundled product support - type: TEST_ENTITY_TYPE, - searchQuery: searchQuery, - sort: '' - } - - // apply test search - searchAdapter.search(Request).then((resp) => { // we're always trying to populate cache - when online - const res = searchAdapter.entities[Request.type].resultPorcessor(resp, 0, 200) - Logger.log('Testentity response: ', res)() - }) - }) -} diff --git a/src/modules/sample-custom-entity-graphql/index.ts b/src/modules/sample-custom-entity-graphql/index.ts index 1cd664a29..f214f91b9 100644 --- a/src/modules/sample-custom-entity-graphql/index.ts +++ b/src/modules/sample-custom-entity-graphql/index.ts @@ -20,7 +20,7 @@ export const CustomEntityGqlModule: StorefrontModule = function (app, store, rou // resolver for testentity should be implemented on the GraphQL server provided searchAdapter.registerEntityTypeByQuery(TEST_ENTITY_TYPE, { url: 'http://localhost:8080/graphql/', - query: require('../queries/testentity.gql'), + query: require('./testentity.gql'), queryProcessor: (query) => { // function that can modify the query each time before it's being executed return query diff --git a/src/modules/sample-custom-entity-graphql/queries/testentity.gql b/src/modules/sample-custom-entity-graphql/testentity.gql similarity index 100% rename from src/modules/sample-custom-entity-graphql/queries/testentity.gql rename to src/modules/sample-custom-entity-graphql/testentity.gql From deef9526cfff1f75d9ac41bcf943ebc29b913e2b Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Wed, 17 Jul 2019 14:05:35 +0200 Subject: [PATCH 0343/1227] Added checks if multistore is active before merging storeViews with default values This is for merging and using the defaultStoreCode --- core/lib/multistore.ts | 4 ++-- core/lib/test/unit/multistore.spec.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 2b7d3908e..4cf0052fa 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -84,7 +84,7 @@ export function prepareStoreView (storeCode: string): StoreView { storeId: config.defaultStoreCode && config.defaultStoreCode !== '' ? config.storeViews[config.defaultStoreCode].storeId : 1 } - if (config.storeViews.multistore) { + if (config.storeViews.multistore === true) { storeView.storeCode = storeCode || config.defaultStoreCode || '' } else { storeView.storeCode = storeCode || '' @@ -92,7 +92,7 @@ export function prepareStoreView (storeCode: string): StoreView { const storeViewHasChanged = !rootStore.state.storeView || rootStore.state.storeView.storeCode !== storeCode - if (storeView.storeCode && config.storeViews[storeView.storeCode]) { + if (storeView.storeCode && config.storeViews.multistore === true && config.storeViews[storeView.storeCode]) { storeView = merge(storeView, getExtendedStoreviewConfig(config.storeViews[storeView.storeCode])) } rootStore.state.user.current_storecode = storeView.storeCode diff --git a/core/lib/test/unit/multistore.spec.ts b/core/lib/test/unit/multistore.spec.ts index 78e345017..eeab0bf14 100644 --- a/core/lib/test/unit/multistore.spec.ts +++ b/core/lib/test/unit/multistore.spec.ts @@ -261,7 +261,6 @@ describe('Multistore', () => { }) }) - it('return de storeView with merged store config values', () => { rootStore.state.storeView = {} rootStore.state.user = {} From ff771af1673b75a7c1a7239767e14d16597e00ff Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Wed, 17 Jul 2019 14:44:41 +0200 Subject: [PATCH 0344/1227] Added userGroupId for checking which tax class should be used for a product This is needed as magento uses both for tax calculation. This does only work on client side tax calculations. --- config/default.json | 3 ++- core/lib/multistore.ts | 3 ++- core/modules/catalog/helpers/tax.ts | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/config/default.json b/config/default.json index 9bde0fa07..11f06b34d 100644 --- a/config/default.json +++ b/config/default.json @@ -388,7 +388,8 @@ "defaultCountry": "US", "defaultRegion": "", "sourcePriceIncludesTax": false, - "calculateServerSide": true + "calculateServerSide": true, + "userGroupId": null }, "shipping": { "methods": [ diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 519bb5f38..cfca14017 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -35,7 +35,8 @@ export interface StoreView { sourcePriceIncludesTax: boolean, defaultCountry: string, defaultRegion: null | string, - calculateServerSide: boolean + calculateServerSide: boolean, + userGroupId?: number }, i18n: { fullCountryName: string, diff --git a/core/modules/catalog/helpers/tax.ts b/core/modules/catalog/helpers/tax.ts index b7ffaa554..d3c44e164 100644 --- a/core/modules/catalog/helpers/tax.ts +++ b/core/modules/catalog/helpers/tax.ts @@ -1,3 +1,7 @@ +import rootStore from '@vue-storefront/core/store' +import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import config from 'config' + function isSpecialPriceActive (fromDate, toDate) { const now = new Date() fromDate = fromDate ? new Date(fromDate) : false @@ -209,7 +213,18 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false, export function calculateProductTax (product, taxClasses, taxCountry = 'PL', taxRegion = '', sourcePriceInclTax = false, deprecatedPriceFieldsSupport = false, finalPriceInclTax = true) { let rateFound = false if (product.tax_class_id > 0) { - let taxClass = taxClasses.find((el) => el.product_tax_class_ids.indexOf(parseInt(product.tax_class_id) >= 0)) + let taxClass + if (typeof currentStoreView().tax.userGroupId === 'number') { + const userGroupId = rootStore.getters['user/isLoggedIn'] === true ? rootStore.state.user.current.group_id : currentStoreView().tax.userGroupId + + taxClass = taxClasses.find((el) => { + return el.product_tax_class_ids.indexOf(parseInt(product.tax_class_id)) >= 0 && + el.customer_tax_class_ids.indexOf(parseInt(userGroupId)) >= 0 + }) + } else { + taxClass = taxClasses.find((el) => el.product_tax_class_ids.indexOf(parseInt(product.tax_class_id) >= 0)) + } + if (taxClass) { for (let rate of taxClass.rates) { // TODO: add check for zip code ranges (!) if (rate.tax_country_id === taxCountry && (rate.region_name === taxRegion || rate.tax_region_id === 0 || !rate.region_name)) { From 8db9530bfba15149ef3b32d676d176baf5c65a9d Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 14:54:56 +0200 Subject: [PATCH 0345/1227] rename initCacheStorage to cache.ts --- core/build/webpack.base.config.ts | 3 ++- core/helpers/{initCacheStorage.ts => cache.ts} | 0 core/modules/cart/test/unit/index.spec.ts | 2 +- core/modules/offline-order/components/CancelOrders.ts | 4 ++-- core/modules/offline-order/helpers/onNetworkStatusChange.ts | 4 ++-- core/modules/order/index.ts | 3 +-- core/store/lib/storage-manager.ts | 5 +++-- src/themes/default/index.js | 4 ++-- 8 files changed, 13 insertions(+), 12 deletions(-) rename core/helpers/{initCacheStorage.ts => cache.ts} (100%) diff --git a/core/build/webpack.base.config.ts b/core/build/webpack.base.config.ts index 72b7f6a2c..88dd15ecd 100644 --- a/core/build/webpack.base.config.ts +++ b/core/build/webpack.base.config.ts @@ -119,7 +119,8 @@ export default { // Backward compatible '@vue-storefront/core/store/lib/multistore': path.resolve(__dirname, '../lib/multistore.ts'), 'src/modules/order-history/components/UserOrders': path.resolve(__dirname, '../../core/modules/order/components/UserOrdersHistory'), - '@vue-storefront/core/modules/social-share/components/WebShare': path.resolve(__dirname, '../../src/themes/default/components/theme/WebShare.vue') + '@vue-storefront/core/modules/social-share/components/WebShare': path.resolve(__dirname, '../../src/themes/default/components/theme/WebShare.vue'), + '@vue-storefront/core/helpers/initCacheStorage': path.resolve(__dirname, '../lib/cache.ts') } }, module: { diff --git a/core/helpers/initCacheStorage.ts b/core/helpers/cache.ts similarity index 100% rename from core/helpers/initCacheStorage.ts rename to core/helpers/cache.ts diff --git a/core/modules/cart/test/unit/index.spec.ts b/core/modules/cart/test/unit/index.spec.ts index 8b0bbd764..def95503d 100644 --- a/core/modules/cart/test/unit/index.spec.ts +++ b/core/modules/cart/test/unit/index.spec.ts @@ -4,7 +4,7 @@ jest.mock('../../store', () => ({})); jest.mock('@vue-storefront/module', () => ({ createModule: jest.fn(() => ({ module: 'cart' })) })); jest.mock('../../helpers/cartCacheHandler', () => ({ cartCacheHandlerFactory: jest.fn() })) jest.mock('@vue-storefront/core/helpers', () => ({ isServer: false })) -jest.mock('@vue-storefront/core/helpers/initCacheStorage', () => ({ initCacheStorage: jest.fn() })); +jest.mock('@vue-storefront/core/helpers/cache', () => ({ initCacheStorage: jest.fn() })); describe('Cart Module', () => { it('can be initialized', () => { diff --git a/core/modules/offline-order/components/CancelOrders.ts b/core/modules/offline-order/components/CancelOrders.ts index 22609570c..4baf2ca0b 100644 --- a/core/modules/offline-order/components/CancelOrders.ts +++ b/core/modules/offline-order/components/CancelOrders.ts @@ -1,10 +1,10 @@ import { Logger } from '@vue-storefront/core/lib/logger' -import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export const CancelOrders = { methods: { cancelOrders () { - const ordersCollection = initCacheStorage('orders', false, true) + const ordersCollection = StorageManager.get('orders') ordersCollection.iterate((order, id, iterationNumber) => { if (!order.transmited) { ordersCollection.removeItem(id) diff --git a/core/modules/offline-order/helpers/onNetworkStatusChange.ts b/core/modules/offline-order/helpers/onNetworkStatusChange.ts index 1e8f0852f..94d38cb31 100644 --- a/core/modules/offline-order/helpers/onNetworkStatusChange.ts +++ b/core/modules/offline-order/helpers/onNetworkStatusChange.ts @@ -1,7 +1,7 @@ import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus/index' import { Logger } from '@vue-storefront/core/lib/logger' import config from 'config' -import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage'; +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' export function onNetworkStatusChange (store) { Logger.log('Are we online: ' + navigator.onLine, 'offline-order')() @@ -13,7 +13,7 @@ export function onNetworkStatusChange (store) { EventBus.$emit('order/PROCESS_QUEUE', { config: config }) // process checkout queue } else { const ordersToConfirm = [] - const ordersCollection = initCacheStorage('orders', false, true) + const ordersCollection = StorageManager.get('orders') ordersCollection.iterate((order, id, iterationNumber) => { if (!order.transmited) { diff --git a/core/modules/order/index.ts b/core/modules/order/index.ts index 5897f8cdb..04e73aea4 100644 --- a/core/modules/order/index.ts +++ b/core/modules/order/index.ts @@ -7,7 +7,6 @@ import rootStore from '@vue-storefront/core/store' import i18n from '@vue-storefront/i18n' import { serial, onlineHelper, processURLAddress } from '@vue-storefront/core/helpers' import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' -import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage' import { isServer } from '@vue-storefront/core/helpers' import { StorefrontModule } from '@vue-storefront/module'; @@ -20,7 +19,7 @@ export const OrderModule: StorefrontModule = function (app, store, router, modul EventBus.$on('order/PROCESS_QUEUE', async event => { if (onlineHelper.isOnline) { Logger.log('Sending out orders queue to server ...')() - const ordersCollection = initCacheStorage('orders', false, true) + const ordersCollection = StorageManager.get('orders') const fetchQueue = [] ordersCollection.iterate((order, id) => { diff --git a/core/store/lib/storage-manager.ts b/core/store/lib/storage-manager.ts index c86781cc4..941477e6c 100644 --- a/core/store/lib/storage-manager.ts +++ b/core/store/lib/storage-manager.ts @@ -1,5 +1,5 @@ import UniversalStorage from '@vue-storefront/core/store/lib/storage' -import { initCacheStorage, prepareCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage'; +import { initCacheStorage, prepareCacheStorage } from '@vue-storefront/core/helpers/cache'; import { Logger } from '@vue-storefront/core/lib/logger' const StorageManager = { @@ -32,7 +32,8 @@ const StorageManager = { return !!this.storageMap[collectionName] }, /** - * Returns the UniversalStorage driver for specific key + * Returns the UniversalStorage driver for specific key. + * If it doesnt exist it creates it with defaults for `init` * @returns UniversalStorage */ get: function (collectionName): UniversalStorage { diff --git a/src/themes/default/index.js b/src/themes/default/index.js index 593d6e03d..7eae4e129 100644 --- a/src/themes/default/index.js +++ b/src/themes/default/index.js @@ -7,11 +7,11 @@ import '@vue-storefront/core/lib/passive-listeners' import { RouterManager } from '@vue-storefront/core/lib/router-manager' import { once } from '@vue-storefront/core/helpers' -import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage'; import { claimsStore } from 'theme/store/claims' import { homepageStore } from 'theme/store/homepage' import { uiStore } from 'theme/store/ui' import { promotedStore } from 'theme/store/promoted-offers' +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' once('__VUE_EXTEND_DROPPOINT_VPB__', () => { Vue.use(VueProgressBar) @@ -26,7 +26,7 @@ function initTheme (app, router, store, config, ssrContext) { setupMultistoreRoutes(config, router, routes) RouterManager.addRoutes(routes, router) - initCacheStorage('claimCollection'); + StorageManager.init('claimCollection'); store.registerModule('claims', claimsStore); store.registerModule('homepage', homepageStore); store.registerModule('ui', uiStore); From d75bb1b9c5a8c08be02df48b5c083ef9815160c7 Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Wed, 17 Jul 2019 15:21:39 +0200 Subject: [PATCH 0346/1227] Added documentation for userGroupId in tax config --- docs/guide/basics/configuration.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/guide/basics/configuration.md b/docs/guide/basics/configuration.md index 924c6164d..96f83c8ed 100644 --- a/docs/guide/basics/configuration.md +++ b/docs/guide/basics/configuration.md @@ -607,11 +607,18 @@ When `demomode` is set to `true`, Vue Storefront will display the "Welcome to Vu "sourcePriceIncludesTax": false, "defaultCountry": "DE", "defaultRegion": "", - "calculateServerSide": true + "calculateServerSide": true, + "userGroupId": null }, ``` -The taxes section is used by the [core/modules/catalog/helpers/tax](https://github.com/DivanteLtd/vue-storefront/tree/master/core/modules/catalog/helpers/tax.ts). When `sourcePricesIncludesTax` is set to `true` it means that the prices indexed in the Elasticsearch already consist of the taxes. If it's set to `false` the taxes will be calculated runtime. +The taxes section is used by the +[core/modules/catalog/helpers/tax](https://github.com/DivanteLtd/vue-storefront/tree/master/core/modules/catalog/helpers/tax.ts). +When `sourcePricesIncludesTax` is set to `true` it means that the prices +indexed in the Elasticsearch already consist of the taxes. If it's set +to `false` the taxes will be calculated runtime. The `userGroupId` +config does only work when you have set `sourcePriceIncludesTax` set to +`false` and `calculateServerSide` is set to `false`. The `defaultCountry` and the `defaultRegion` settings are being used for finding the proper tax rate for the anonymous, unidentified user (which country is not yet set). From 12044e257749c27bc97215fceeeffe7274cf62ac Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Wed, 17 Jul 2019 15:32:19 +0200 Subject: [PATCH 0347/1227] updated changedlog with pr #3245 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3baa952d..1eec14add 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Items count badges for Compare products and wishlist icons at header - @vishal-7037 (#3047) - Get also none product image thumbnails via API - @cewald, @resubaka (#3207) - Added a config option `optimizeShoppingCartOmitFields` - @EmilsM (#3222) +- Added support for tax calculation where the values from customer_tax_class_ids is used - @resubaka (#3245) ### Fixed - Fixed product link in wishlist and microcart - @michasik (#2987) From c05c851846667bcc92760bb39334c077f495e175 Mon Sep 17 00:00:00 2001 From: Michal-Dziedzinski Date: Wed, 17 Jul 2019 15:34:33 +0200 Subject: [PATCH 0348/1227] Fix disabled button --- src/themes/default/pages/Product.vue | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/themes/default/pages/Product.vue b/src/themes/default/pages/Product.vue index 2e9b8d4ca..f425b18b3 100644 --- a/src/themes/default/pages/Product.vue +++ b/src/themes/default/pages/Product.vue @@ -136,7 +136,7 @@ v-if="product.type_id !== 'grouped' && product.type_id !== 'bundle'" >
@@ -307,10 +307,19 @@ export default { }) } return selectedFilters + }, + isSimpleOrConfigurable () { + if ( + this.product.type_id === 'simple' || + this.product.type_id === 'configurable' + ) { return true } + + return false } }, created () { this.getQuantity() + console.log(this.product.type_id) }, methods: { showDetails (event) { From 060c21c4c72163e5c6d6ec60a67c789e2133d3ee Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 15:42:46 +0200 Subject: [PATCH 0349/1227] moved unused modules to sample directory --- core/build/webpack.base.config.ts | 2 +- core/helpers/cache.ts | 35 --- core/store/lib/storage-manager.ts | 41 ++- .../components/DroppointMap.vue | 239 ------------------ src/modules/droppoint-shipping/index.ts | 8 - .../droppoint-shipping/store/actions.ts | 12 - src/modules/droppoint-shipping/store/index.ts | 7 - src/modules/index.ts | 2 - src/modules/payment-cash-on-delivery/index.ts | 21 +- src/modules/raw-output-example/index.ts | 6 - .../raw-output-example/pages/NoJSExample.vue | 33 --- .../pages/NoLayoutAppendPrependExample.vue | 33 --- .../pages/RawOutputExample.vue | 30 --- .../raw-output-example/router/routes.ts | 9 - .../sample-custom-entity-graphql/index.ts | 63 ----- .../testentity.gql | 8 - 16 files changed, 53 insertions(+), 496 deletions(-) delete mode 100644 core/helpers/cache.ts delete mode 100644 src/modules/droppoint-shipping/components/DroppointMap.vue delete mode 100644 src/modules/droppoint-shipping/index.ts delete mode 100644 src/modules/droppoint-shipping/store/actions.ts delete mode 100644 src/modules/droppoint-shipping/store/index.ts delete mode 100644 src/modules/raw-output-example/index.ts delete mode 100755 src/modules/raw-output-example/pages/NoJSExample.vue delete mode 100755 src/modules/raw-output-example/pages/NoLayoutAppendPrependExample.vue delete mode 100755 src/modules/raw-output-example/pages/RawOutputExample.vue delete mode 100644 src/modules/raw-output-example/router/routes.ts delete mode 100644 src/modules/sample-custom-entity-graphql/index.ts delete mode 100644 src/modules/sample-custom-entity-graphql/testentity.gql diff --git a/core/build/webpack.base.config.ts b/core/build/webpack.base.config.ts index 88dd15ecd..8e57d5f8c 100644 --- a/core/build/webpack.base.config.ts +++ b/core/build/webpack.base.config.ts @@ -120,7 +120,7 @@ export default { '@vue-storefront/core/store/lib/multistore': path.resolve(__dirname, '../lib/multistore.ts'), 'src/modules/order-history/components/UserOrders': path.resolve(__dirname, '../../core/modules/order/components/UserOrdersHistory'), '@vue-storefront/core/modules/social-share/components/WebShare': path.resolve(__dirname, '../../src/themes/default/components/theme/WebShare.vue'), - '@vue-storefront/core/helpers/initCacheStorage': path.resolve(__dirname, '../lib/cache.ts') + '@vue-storefront/core/helpers/initCacheStorage': path.resolve(__dirname, '../store/lib/storage-manager.ts') } }, module: { diff --git a/core/helpers/cache.ts b/core/helpers/cache.ts deleted file mode 100644 index b5b5be660..000000000 --- a/core/helpers/cache.ts +++ /dev/null @@ -1,35 +0,0 @@ -import * as localForage from 'localforage' -import UniversalStorage from '@vue-storefront/core/store/lib/storage' -import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' -import { currentStoreView } from '@vue-storefront/core/lib/multistore' -import config from 'config' - -/** create Universal Storage instance */ -export function prepareCacheStorage (key, localised = true, storageQuota = 0) { - const storeView = currentStoreView() - const dbNamePrefix = storeView && storeView.storeCode ? storeView.storeCode + '-' : '' - const cacheDriver = config.localForage && config.localForage.defaultDrivers[key] - ? config.localForage.defaultDrivers[key] - : 'LOCALSTORAGE' - - return new UniversalStorage(localForage.createInstance({ - name: localised ? `${dbNamePrefix}shop` : 'shop', - storeName: key, - driver: localForage[cacheDriver] - }), true, storageQuota) -} - -/** @deprecated, to be removed in 2.0 in favor to `StorageManager` - * Inits cache storage for given module. By default via local storage - * */ -export function initCacheStorage (key, localised = true, registerStorgeManager = true) { - if (registerStorgeManager) { - if (!StorageManager.exists(key)) { - return StorageManager.set(key, prepareCacheStorage(key, localised)) - } else { - return StorageManager.get(key) - } - } else { - return prepareCacheStorage(key, localised) - } -} diff --git a/core/store/lib/storage-manager.ts b/core/store/lib/storage-manager.ts index 941477e6c..d27adc99f 100644 --- a/core/store/lib/storage-manager.ts +++ b/core/store/lib/storage-manager.ts @@ -1,6 +1,8 @@ -import UniversalStorage from '@vue-storefront/core/store/lib/storage' -import { initCacheStorage, prepareCacheStorage } from '@vue-storefront/core/helpers/cache'; import { Logger } from '@vue-storefront/core/lib/logger' +import * as localForage from 'localforage' +import UniversalStorage from '@vue-storefront/core/store/lib/storage' +import { currentStoreView } from '@vue-storefront/core/lib/multistore' +import config from 'config' const StorageManager = { currentStoreCode: '', @@ -12,7 +14,7 @@ const StorageManager = { * @param storageQuota max size of storage, 0 if unlimited (default `0`) */ init: function (collectionName: string, isLocalised = true, storageQuota = 0) { - this.storageMap[collectionName] = prepareCacheStorage(collectionName, isLocalised, storageQuota) + this.storageMap[collectionName] = _prepareCacheStorage(collectionName, isLocalised, storageQuota) return this.storageMap[collectionName] }, /** @@ -32,7 +34,7 @@ const StorageManager = { return !!this.storageMap[collectionName] }, /** - * Returns the UniversalStorage driver for specific key. + * Returns the UniversalStorage driver for specific key. * If it doesnt exist it creates it with defaults for `init` * @returns UniversalStorage */ @@ -46,4 +48,33 @@ const StorageManager = { } } -export { StorageManager } +function _prepareCacheStorage (key, localised = true, storageQuota = 0) { + const storeView = currentStoreView() + const dbNamePrefix = storeView && storeView.storeCode ? storeView.storeCode + '-' : '' + const cacheDriver = config.localForage && config.localForage.defaultDrivers[key] + ? config.localForage.defaultDrivers[key] + : 'LOCALSTORAGE' + + return new UniversalStorage(localForage.createInstance({ + name: localised ? `${dbNamePrefix}shop` : 'shop', + storeName: key, + driver: localForage[cacheDriver] + }), true, storageQuota) +} + +/** + * @deprecated to be removed in 2.0 in favor to `StorageManager` + * */ +function initCacheStorage (key, localised = true, registerStorgeManager = true) { + if (registerStorgeManager) { + if (!StorageManager.exists(key)) { + return StorageManager.set(key, _prepareCacheStorage(key, localised)) + } else { + return StorageManager.get(key) + } + } else { + return _prepareCacheStorage(key, localised) + } +} + +export { StorageManager, initCacheStorage } diff --git a/src/modules/droppoint-shipping/components/DroppointMap.vue b/src/modules/droppoint-shipping/components/DroppointMap.vue deleted file mode 100644 index 8d799e115..000000000 --- a/src/modules/droppoint-shipping/components/DroppointMap.vue +++ /dev/null @@ -1,239 +0,0 @@ - - - - - diff --git a/src/modules/droppoint-shipping/index.ts b/src/modules/droppoint-shipping/index.ts deleted file mode 100644 index 2d3050c1d..000000000 --- a/src/modules/droppoint-shipping/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createModule } from '@vue-storefront/core/lib/module' -import { module } from './store' - -export const KEY = 'droppoint-shipping' -export const DroppointShipping = createModule({ - key: KEY, - store: { modules: [{ key: KEY, module }] } -}) diff --git a/src/modules/droppoint-shipping/store/actions.ts b/src/modules/droppoint-shipping/store/actions.ts deleted file mode 100644 index bc96845fb..000000000 --- a/src/modules/droppoint-shipping/store/actions.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ActionTree } from 'vuex'; -import { execute as taskExecute } from '@vue-storefront/core/lib/sync/task' -import * as entities from '@vue-storefront/core/store/lib/entities' - -// actions -export const actions: ActionTree = { - fetch ({ commit }, request) { - const taskId = entities.uniqueEntityId(request) - request.task_id = taskId.toString() - return taskExecute(request) - } -} diff --git a/src/modules/droppoint-shipping/store/index.ts b/src/modules/droppoint-shipping/store/index.ts deleted file mode 100644 index 50bde5e22..000000000 --- a/src/modules/droppoint-shipping/store/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Module } from 'vuex' -import { actions } from './actions' - -export const module: Module = { - namespaced: true, - actions -} diff --git a/src/modules/index.ts b/src/modules/index.ts index 018049cc4..7d63eaa91 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -21,7 +21,6 @@ import { GoogleTagManagerModule } from './google-tag-manager'; import { AmpRendererModule } from './amp-renderer'; import { PaymentBackendMethodsModule } from './payment-backend-methods'; import { PaymentCashOnDeliveryModule } from './payment-cash-on-delivery'; -import { RawOutputExampleModule } from './raw-output-example' import { InstantCheckoutModule } from './instant-checkout' import { registerModule } from '@vue-storefront/module' @@ -49,7 +48,6 @@ export function registerNewModules () { // registerModule(HotjarModule) registerModule(PaymentBackendMethodsModule) registerModule(PaymentCashOnDeliveryModule) - registerModule(RawOutputExampleModule) registerModule(AmpRendererModule) registerModule(InstantCheckoutModule) } diff --git a/src/modules/payment-cash-on-delivery/index.ts b/src/modules/payment-cash-on-delivery/index.ts index 72aea80ca..f917911ce 100644 --- a/src/modules/payment-cash-on-delivery/index.ts +++ b/src/modules/payment-cash-on-delivery/index.ts @@ -2,33 +2,44 @@ import { StorefrontModule } from '@vue-storefront/module'; import { isServer } from '@vue-storefront/core/helpers' import Vue from 'vue'; import InfoComponent from './components/Info.vue' +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' export const PaymentCashOnDeliveryModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { // Place the order. Payload is empty as we don't have any specific info to add for this payment method '{}' let correctPaymentMethod = false const placeOrder = () => { if (correctPaymentMethod) { - Vue.prototype.$bus.$emit('checkout-do-placeOrder', {}) + EventBus.$emit('checkout-do-placeOrder', {}) } } - + // Update the methods + let paymentMethodConfig = { + 'title': 'Cash on delivery', + 'code': 'cashondelivery', + 'cost': 0, + 'costInclTax': 0, + 'default': true, + 'offline': true, + 'is_server_method': false + } + store.dispatch('payment/addMethod', paymentMethodConfig) if (!isServer) { // Update the methods let paymentMethodConfig = { 'title': 'Cash on delivery', 'code': 'cashondelivery', 'cost': 0, - 'costInclTax': 0, + 'cost_incl_tax': 0, 'default': true, 'offline': true, 'is_server_method': false } store.dispatch('payment/addMethod', paymentMethodConfig) - Vue.prototype.$bus.$on('checkout-before-placeOrder', placeOrder) + EventBus.$on('checkout-before-placeOrder', placeOrder) // Mount the info component when required. - Vue.prototype.$bus.$on('checkout-payment-method-changed', (paymentMethodCode) => { + EventBus.$on('checkout-payment-method-changed', (paymentMethodCode) => { let methods = store.state['payment-backend-methods'].methods if (methods) { let method = methods.find(item => (item.code === paymentMethodCode)) diff --git a/src/modules/raw-output-example/index.ts b/src/modules/raw-output-example/index.ts deleted file mode 100644 index ed8a2ad26..000000000 --- a/src/modules/raw-output-example/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { routes } from './router/routes' -import { StorefrontModule } from '@vue-storefront/module'; - -export const RawOutputExampleModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { - router.addRoutes(routes); -} diff --git a/src/modules/raw-output-example/pages/NoJSExample.vue b/src/modules/raw-output-example/pages/NoJSExample.vue deleted file mode 100755 index 1e09d7088..000000000 --- a/src/modules/raw-output-example/pages/NoJSExample.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - diff --git a/src/modules/raw-output-example/pages/NoLayoutAppendPrependExample.vue b/src/modules/raw-output-example/pages/NoLayoutAppendPrependExample.vue deleted file mode 100755 index ec0ed77d9..000000000 --- a/src/modules/raw-output-example/pages/NoLayoutAppendPrependExample.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - diff --git a/src/modules/raw-output-example/pages/RawOutputExample.vue b/src/modules/raw-output-example/pages/RawOutputExample.vue deleted file mode 100755 index 5033610f6..000000000 --- a/src/modules/raw-output-example/pages/RawOutputExample.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - diff --git a/src/modules/raw-output-example/router/routes.ts b/src/modules/raw-output-example/router/routes.ts deleted file mode 100644 index dc935d3cb..000000000 --- a/src/modules/raw-output-example/router/routes.ts +++ /dev/null @@ -1,9 +0,0 @@ -import NoJSExample from '../pages/NoJSExample.vue' -import RawOutputExample from '../pages/RawOutputExample.vue' -import NoLayoutAppendPrependExample from '../pages/NoLayoutAppendPrependExample.vue' - -export const routes = [ - { path: '/raw-output-example.xml', component: RawOutputExample, meta: { layout: 'empty' } }, - { path: '/append-prepend.html', component: NoLayoutAppendPrependExample, meta: { layout: 'empty' } }, - { path: '/no-js.html', component: NoJSExample, meta: { layout: 'default' } } -] diff --git a/src/modules/sample-custom-entity-graphql/index.ts b/src/modules/sample-custom-entity-graphql/index.ts deleted file mode 100644 index f214f91b9..000000000 --- a/src/modules/sample-custom-entity-graphql/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { getSearchAdapter } from '@vue-storefront/core/lib/search/adapter/searchAdapterFactory' -import { processESResponseType } from '@vue-storefront/core/lib/search/adapter/graphql/processor/processType' -import { currentStoreView } from '@vue-storefront/core/lib/multistore' -import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' -import { Logger } from '@vue-storefront/core/lib/logger' -import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' -import { StorefrontModule } from '@vue-storefront/module' - -const TEST_ENTITY_TYPE = 'testentity' - -export const CustomEntityGqlModule: StorefrontModule = function (app, store, router, moduleConfig, appConfig) { - EventBus.$on('application-after-init', async () => { - Logger.debug('Example of custom entity graphql extension')() - - // create GraphQL searchAdapter - let searchAdapter = await getSearchAdapter('graphql') - - // register custom entity type using registerEntityTypeByQuery - // different GraphQL servers could be used for different entity types - // resolver for testentity should be implemented on the GraphQL server provided - searchAdapter.registerEntityTypeByQuery(TEST_ENTITY_TYPE, { - url: 'http://localhost:8080/graphql/', - query: require('./testentity.gql'), - queryProcessor: (query) => { - // function that can modify the query each time before it's being executed - return query - }, - resultPorcessor: (resp, start, size) => { - if (resp === null) { - throw new Error('Invalid GraphQL result - null not expected') - } - if (resp.hasOwnProperty('data')) { - return processESResponseType(resp.data.testentity, start, size) - } else { - if (resp.error) { - throw new Error(JSON.stringify(resp.error)) - } else { - throw new Error('Unknown error with GraphQL result in resultProcessor for entity type \'category\'') - } - } - } - }) - - const storeView = currentStoreView() - - // create an empty SearchQuery to get all data for the new custom entity - const searchQuery = new SearchQuery() - - // prepare a SearchRequest object - const Request = { - store: storeView.storeCode, // TODO: add grouped product and bundled product support - type: TEST_ENTITY_TYPE, - searchQuery: searchQuery, - sort: '' - } - - // apply test search - searchAdapter.search(Request).then((resp) => { // we're always trying to populate cache - when online - const res = searchAdapter.entities[Request.type].resultPorcessor(resp, 0, 200) - Logger.log('Testentity response: ', res)() - }) - }) -} diff --git a/src/modules/sample-custom-entity-graphql/testentity.gql b/src/modules/sample-custom-entity-graphql/testentity.gql deleted file mode 100644 index 9b23dff99..000000000 --- a/src/modules/sample-custom-entity-graphql/testentity.gql +++ /dev/null @@ -1,8 +0,0 @@ -query testentity ($filter: TestInput) { - testentity( - filter: $filter - ) - { - hits - } -} \ No newline at end of file From 58f1f24bed07565fd7eddb860167b1123a7eec41 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 15:43:02 +0200 Subject: [PATCH 0350/1227] moved unused modules to sample repo --- core/store/lib/storage-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/store/lib/storage-manager.ts b/core/store/lib/storage-manager.ts index d27adc99f..04dbee5aa 100644 --- a/core/store/lib/storage-manager.ts +++ b/core/store/lib/storage-manager.ts @@ -62,7 +62,7 @@ function _prepareCacheStorage (key, localised = true, storageQuota = 0) { }), true, storageQuota) } -/** +/** * @deprecated to be removed in 2.0 in favor to `StorageManager` * */ function initCacheStorage (key, localised = true, registerStorgeManager = true) { From 0fbe55e3d9f5065f752216616dd10d1738f085f4 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 15:48:04 +0200 Subject: [PATCH 0351/1227] remove magento-2-cms module --- src/modules/magento-2-cms/README.md | 52 ------------ .../magento-2-cms/components/CmsData.vue | 82 ------------------- .../magento-2-cms/hooks/afterRegistration.ts | 16 ---- src/modules/magento-2-cms/index.ts | 10 --- src/modules/magento-2-cms/store/index.js | 66 --------------- 5 files changed, 226 deletions(-) delete mode 100644 src/modules/magento-2-cms/README.md delete mode 100644 src/modules/magento-2-cms/components/CmsData.vue delete mode 100644 src/modules/magento-2-cms/hooks/afterRegistration.ts delete mode 100644 src/modules/magento-2-cms/index.ts delete mode 100644 src/modules/magento-2-cms/store/index.js diff --git a/src/modules/magento-2-cms/README.md b/src/modules/magento-2-cms/README.md deleted file mode 100644 index cf230860a..000000000 --- a/src/modules/magento-2-cms/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# CMS Magento 2 data extension - -To display Cms data: - - install `snowdog/module-cms-api` composer module in your Magento 2 instance, [snowdog/module-cms-api on github](https://github.com/SnowdogApps/magento2-cms-api) - - make sure that in `vue-storefront-api` repo the `cms-data` extension is installed - -## Cms Block -To display Cms Block import CmsData component and use it in template: - -`import CmsData from 'src/modules/magento-2-cms/components/CmsData'` - -we have to options to get Cms Block data: -1. by Magento `identifier`: -`` -where `contact-us-info` is a Cms Block `identifier` from Magento 2 instance - -this option handles different `Store Views` - if multistore is enabled, it takes Cms Block by current Store View, if it's disabled, it set default Store View (`0`) - -2. by Magento id -`` -where `5` is a Magento id of Cms Block. -It doesn't handle differents Store Views so please use it only when multistore it's enabled/ - -## Cms Page -To display Cms Page: - -1. Cms page content like a block -* in custom theme create new page with custom route -* import CmsData component and use it in template: -`import CmsData from '@vue-storefront/extension-magento2-cms/components/CmsData'` - -call Cms Page like a Block using either Magento `identifier`: -`` - -or Magento `id` -`` -where `5` is a cms page identifier from Magento 2 instance - -Like Cms Block, the Cms Page by `identifier` handles different Store Views, Cms Page by `id` handles only Default Store View/ - -2. Cms page content as a page component: -- in custom theme `themes//router/index.js` import `CmsData` component, add custom route and define props: `{identifier: :pageIdentifier, type: 'Page', sync: true}`, example: -``` -import CmsData from '@vue-storefront/extension-magento2-cms/components/CmsData' - -const routes = [ - // ... theme routes - { name: 'cms-page-sync', path: '/cms-page-sync', component: CmsData, props: {identifier: 'about-us', type: 'Page', sync: true} } -] -``` -Complete examples of usage and implementation you can find in Default theme: -1. `/cms-page-sync`, `src/themes/default/router/index.js` diff --git a/src/modules/magento-2-cms/components/CmsData.vue b/src/modules/magento-2-cms/components/CmsData.vue deleted file mode 100644 index 370deaac0..000000000 --- a/src/modules/magento-2-cms/components/CmsData.vue +++ /dev/null @@ -1,82 +0,0 @@ - - - diff --git a/src/modules/magento-2-cms/hooks/afterRegistration.ts b/src/modules/magento-2-cms/hooks/afterRegistration.ts deleted file mode 100644 index a707d3d01..000000000 --- a/src/modules/magento-2-cms/hooks/afterRegistration.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' - -export function afterRegistration ({ Vue, config, store, isServer }) { - store.subscribe((mutation, state) => { - const type = mutation.type - - if ( - type.endsWith('setCmsBlock') || - type.endsWith('setCmsPage') - ) { - StorageManager.get('cmsData').setItem('cms-data', state.cms).catch((reason) => { - console.error(reason) - }) - } - }) -} diff --git a/src/modules/magento-2-cms/index.ts b/src/modules/magento-2-cms/index.ts deleted file mode 100644 index 458e9ffed..000000000 --- a/src/modules/magento-2-cms/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createModule } from '@vue-storefront/core/lib/module' -import { store } from './store' -import { afterRegistration } from './hooks/afterRegistration' - -const KEY = 'cms' -export const Magento2CMS = createModule({ - key: KEY, - store: { modules: [{ key: KEY, module: store }] }, - afterRegistration -}) diff --git a/src/modules/magento-2-cms/store/index.js b/src/modules/magento-2-cms/store/index.js deleted file mode 100644 index e3be87850..000000000 --- a/src/modules/magento-2-cms/store/index.js +++ /dev/null @@ -1,66 +0,0 @@ -import fetch from 'isomorphic-fetch' -import { Logger } from '@vue-storefront/core/lib/logger' -import { processURLAddress } from '@vue-storefront/core/helpers' - -const state = { - cmsPages: [], - cmsBlocks: [] -} - -const getters = { - getBlock: (state) => (id) => { - return state.cmsBlocks.find(item => item.id === id) - }, - getBlockIdentifier: (state) => (identifier) => { - return state.cmsBlocks.find(item => item.identifier === identifier) - }, - getPage: (state) => (id) => { - return state.cmsPages.find(item => item.id === id) - }, - getPageIdentifier: (state) => (identifier) => { - return state.cmsPages.find(item => item.identifier === identifier) - } -} - -// actions -const actions = { - loadCms (context, {url, type}) { - fetch(processURLAddress(url), { - method: 'GET', - headers: { 'Content-Type': 'application/json' }, - mode: 'cors' - }) - .then(response => response.json()) - .then(data => { - if (data.code === 200) { - context.commit(`setCms${type}`, data.result) - } - }) - .catch((err) => { - Logger.log(err)() - Logger.error('You need to install a custom Magento module from Snow.dog to make the CMS magic happen. Please go to https://github.com/SnowdogApps/magento2-cms-api and follow the instructions')() - }) - } -} - -// mutations -const mutations = { - setCmsBlock (state, data) { - if (!state.cmsBlocks.filter(e => e.id === data.id).length > 0) { - state.cmsBlocks.push(data) - } - }, - setCmsPage (state, data) { - if (!state.cmsPages.filter(e => e.id === data.id).length > 0) { - state.cmsPages.push(data) - } - } -} - -export const store = { - namespaced: true, - state, - getters, - actions, - mutations -} From afe0dbf7d8a3b5dd55db3c0b83f4abbb881243ea Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 16:18:57 +0200 Subject: [PATCH 0352/1227] update changelog and upgrade notes --- CHANGELOG.md | 2 +- docs/guide/upgrade-notes/README.md | 35 +++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3baa952d..b2da4d8e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added configuration for max attempt task & cart by pass - @cnviradiya (#3193) - Added catching of errors when ES is down - @qiqqq - Added debounce for updating quantity method in the cart - @andrzejewsky (#3191) - +- New modules API and rewrite - @filrak (#3144) ## [1.10.0-rc.2] - UNRELEASED ### Fixed diff --git a/docs/guide/upgrade-notes/README.md b/docs/guide/upgrade-notes/README.md index fbb08c278..fb7d415ef 100644 --- a/docs/guide/upgrade-notes/README.md +++ b/docs/guide/upgrade-notes/README.md @@ -1,7 +1,29 @@ # Upgrade notes We're trying to keep the upgrade process as easy as possible. Unfortunately, sometimes manual code changes are required. Before pulling out the latest version, please take a look at the upgrade notes below: + ## 1.10 -> 1.11 + +This is the last major release of Vue Storefront 1.x before 2.0 therefore more manual updates are required to keep external packages compatible with 1.x as long as possible. + +- All modules were refactored to new API. You can still register modules in previous format until 2.0 +- `DroppointShipping` and `magento-2-cms `modules were deleted +- example modules moved to https://github.com/DivanteLtd/vsf-samples +- `core/helpers/initCacheStorage.ts` merged with `StorageManager.ts` (import path alias for backward compatibility added) +- Old extensions mechanism (before VS 1.4) was finally removed after being deprecated for almost a year (`src/extensions` removal) +- Cache collections were reorganized. In most cases Local Storage keys remained untouched, only collection keys were unified. also they're used only in the core. Posting changes in case someone is using those collections in their modules; + - `syncTaskCollection` renamed to `syncTasks` + - `compareCollection` renamed to `compare` + - `cmsData` renamed to `cms` + - `cartsCollection` renamed to `carts` + - `checkoutFieldValues`, `checkoutFieldsCollection` renamed to `checkout` (`checkoutFieldsCollection` wasn’t used) + - `ordersCollection` and `orders` renamed to just `orders` (`ordersCollection` wasn’t used) + - `elasticCacheCollection` renamed to `elasticCache` + - `usersCollection` `usersData` merged and renamed to `user` + - `attributesCollection`, `attributes` renamed to just `attributes` + - `ordersHistoryCollection` merged to `user` cache where it belongs + - `categoriesCollection` renamed to categories + - Collections in theme like `claimsCollection` (claims modules) remained untouched - `UserOrder` component has been renamed to `UserOrderHistory` and moved from `src/modules/order-history/components/UserOrders` to `@vue-storefront/core/modules/order/components/UserOrdersHistory`. This component was used in `MyOrders` component found here: `src/themes/default/components/core/blocks/MyAccount/MyOrders.vue`. In this file the `import` path has to be updated. - `claims`, `promoted-offers`, `homepage` adn `ui` modules have been moved from `@vue-storefront/src/modules` to `src/themes/default/store/` and reduced to stores only.
Delete those folders:
@@ -10,9 +32,9 @@ Delete those folders:
-- `src/modules/homepage`
-- `src/modules/ui-store`
Copy folder `theme/store/` from `theme default`.
-Register the stores copied in previous step in `src/themes/default/index.js`. To do that, import them along with `initCacheStorage` method, used to replace `claims beforeRegistration hook`. +Register the stores copied in previous step in `src/themes/default/index.js`. To do that, import them along with `StorageManager` method, used to replace `claims beforeRegistration hook`. ```js -import { initCacheStorage } from '@vue-storefront/core/helpers/initCacheStorage'; +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager'; import { store as claimsStore } from 'theme/store/claims' import { store as homeStore } from 'theme/store/homepage' import { store as uiStore } from 'theme/store/ui' @@ -20,7 +42,7 @@ import { store as promotedStore } from 'theme/store/promoted-offers' ``` Next, inside `initTheme` method use `store.registerModule` method to register the stores. ```js -Vue.prototype.$db.claimsCollection = initCacheStorage('claims'); +StorageManager.init('claims'); store.registerModule('claims', claimsStore); store.registerModule('homepage', homeStore); store.registerModule('ui', uiStore); @@ -28,11 +50,8 @@ store.registerModule('promoted', promotedStore); ``` - `WebShare` moved from `@vue-storefront/core/modules/social-share/components/WebShare.vue` to `@vue-storefront/src/themes/default/components/theme/WebShare.vue`. This component was used in `Product` component found here: `src/themes/default/pages/Product.vue`. In this file the `import` path has to be updated. -## 1.10 -> 1.11 -We've fixed the naming strategy for product prices; The following fields were renamed: `special_priceInclTax` -> `special_price_incl_tax`, `priceInclTax` -> `price_incl_tax`, `priceTax` -> `price_tax`; The names have been kept and marked as @deprecated. These fields will be **removed with Vue Storefront 2.0rc-1**. - -We've decreased the `localStorage` quota usage + error handling by introducing new config variables: - +- We've fixed the naming strategy for product prices; The following fields were renamed: `special_priceInclTax` -> `special_price_incl_tax`, `priceInclTax` -> `price_incl_tax`, `priceTax` -> `price_tax`; The names have been kept and marked as @deprecated. These fields will be **removed with Vue Storefront 2.0rc-1**. +- We've decreased the `localStorage` quota usage + error handling by introducing new config variables: - `config.products.disablePersistentProductsCache` to not store products by SKU (by default it's on). Products are cached in ServiceWorker cache anyway so the `product/list` will populate the in-memory cache (`cache.setItem(..., memoryOnly = true)`); - `config.seo.disableUrlRoutesPersistentCache` - to not store the url mappings; they're stored in in-memory cache anyway so no additional requests will be made to the backend for url mapping; however it might cause some issues with url routing in the offline mode (when the offline mode PWA installed on homescreen got reloaded, the in-memory cache will be cleared so there won't potentially be the url mappings; however the same like with `product/list` the ServiceWorker cache SHOULD populate url mappings anyway); - `config.syncTasks.disablePersistentTaskQueue` to not store the network requests queue in service worker. Currently only the stock-check and user-data changes were using this queue. The only downside it introuces can be related to the offline mode and these tasks will not be re-executed after connectivity established, but just in a case when the page got reloaded while offline (yeah it might happen using ServiceWorker; `syncTasks` can't be re-populated in cache from SW) From ab25388d8d39f056666f0b256a703b837b50ff05 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 16:26:57 +0200 Subject: [PATCH 0353/1227] fix test mock --- core/modules/cart/test/unit/index.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modules/cart/test/unit/index.spec.ts b/core/modules/cart/test/unit/index.spec.ts index def95503d..69d90433c 100644 --- a/core/modules/cart/test/unit/index.spec.ts +++ b/core/modules/cart/test/unit/index.spec.ts @@ -4,7 +4,7 @@ jest.mock('../../store', () => ({})); jest.mock('@vue-storefront/module', () => ({ createModule: jest.fn(() => ({ module: 'cart' })) })); jest.mock('../../helpers/cartCacheHandler', () => ({ cartCacheHandlerFactory: jest.fn() })) jest.mock('@vue-storefront/core/helpers', () => ({ isServer: false })) -jest.mock('@vue-storefront/core/helpers/cache', () => ({ initCacheStorage: jest.fn() })); +jest.mock('@vue-storefront/core/store/lib/storage-manager', () => ({ initCacheStorage: jest.fn() })); describe('Cart Module', () => { it('can be initialized', () => { From 3ac6e36ae67d073bacda4d7f1607b2ecf02e57c4 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 22:15:56 +0200 Subject: [PATCH 0354/1227] Update core/store/lib/storage-manager.ts Co-Authored-By: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> --- core/store/lib/storage-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/store/lib/storage-manager.ts b/core/store/lib/storage-manager.ts index 04dbee5aa..9e04bc86a 100644 --- a/core/store/lib/storage-manager.ts +++ b/core/store/lib/storage-manager.ts @@ -14,7 +14,7 @@ const StorageManager = { * @param storageQuota max size of storage, 0 if unlimited (default `0`) */ init: function (collectionName: string, isLocalised = true, storageQuota = 0) { - this.storageMap[collectionName] = _prepareCacheStorage(collectionName, isLocalised, storageQuota) + this.storageMap[collectionName] = _prepareCacheStorage(collectionName, isLocalized, storageQuota) return this.storageMap[collectionName] }, /** From 1414f7ae69642564c69afc11ce9961fd0f26e4be Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 22:16:11 +0200 Subject: [PATCH 0355/1227] Update core/store/lib/storage-manager.ts Co-Authored-By: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> --- core/store/lib/storage-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/store/lib/storage-manager.ts b/core/store/lib/storage-manager.ts index 9e04bc86a..af0b609cd 100644 --- a/core/store/lib/storage-manager.ts +++ b/core/store/lib/storage-manager.ts @@ -13,7 +13,7 @@ const StorageManager = { * @param isLocalized if set to `false` data will be shared between storeViews (default `true`) * @param storageQuota max size of storage, 0 if unlimited (default `0`) */ - init: function (collectionName: string, isLocalised = true, storageQuota = 0) { + init: function (collectionName: string, isLocalized = true, storageQuota = 0) { this.storageMap[collectionName] = _prepareCacheStorage(collectionName, isLocalized, storageQuota) return this.storageMap[collectionName] }, From d0b525b8d7521de2a9ddc490ad2dc1f16bd8771a Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 22:16:26 +0200 Subject: [PATCH 0356/1227] Update core/store/lib/storage-manager.ts Co-Authored-By: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> --- core/store/lib/storage-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/store/lib/storage-manager.ts b/core/store/lib/storage-manager.ts index af0b609cd..29410e49a 100644 --- a/core/store/lib/storage-manager.ts +++ b/core/store/lib/storage-manager.ts @@ -56,7 +56,7 @@ function _prepareCacheStorage (key, localised = true, storageQuota = 0) { : 'LOCALSTORAGE' return new UniversalStorage(localForage.createInstance({ - name: localised ? `${dbNamePrefix}shop` : 'shop', + name: localized ? `${dbNamePrefix}shop` : 'shop', storeName: key, driver: localForage[cacheDriver] }), true, storageQuota) From 7d84abfea1b933c7d3deee2e7ef0de443cad0e28 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Wed, 17 Jul 2019 22:16:32 +0200 Subject: [PATCH 0357/1227] Update core/store/lib/storage-manager.ts Co-Authored-By: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> --- core/store/lib/storage-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/store/lib/storage-manager.ts b/core/store/lib/storage-manager.ts index 29410e49a..498b978f7 100644 --- a/core/store/lib/storage-manager.ts +++ b/core/store/lib/storage-manager.ts @@ -48,7 +48,7 @@ const StorageManager = { } } -function _prepareCacheStorage (key, localised = true, storageQuota = 0) { +function _prepareCacheStorage (key, localized = true, storageQuota = 0) { const storeView = currentStoreView() const dbNamePrefix = storeView && storeView.storeCode ? storeView.storeCode + '-' : '' const cacheDriver = config.localForage && config.localForage.defaultDrivers[key] From f1a4d1c53335c1c2938fee40e888126088718495 Mon Sep 17 00:00:00 2001 From: Filip Rakowski Date: Thu, 18 Jul 2019 08:46:36 +0200 Subject: [PATCH 0358/1227] CR fixes --- CHANGELOG.md | 2 +- src/modules/index.ts | 18 +++++++++--------- src/modules/payment-backend-methods/index.ts | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2da4d8e0..45846bb52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added configuration for max attempt task & cart by pass - @cnviradiya (#3193) - Added catching of errors when ES is down - @qiqqq - Added debounce for updating quantity method in the cart - @andrzejewsky (#3191) -- New modules API and rewrite - @filrak (#3144) +- New modules API and rewrite - @filrak, @JCown (#3144) ## [1.10.0-rc.2] - UNRELEASED ### Fixed diff --git a/src/modules/index.ts b/src/modules/index.ts index 7d63eaa91..047c53f98 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -29,27 +29,27 @@ import { registerModule } from '@vue-storefront/module' export function registerNewModules () { registerModule(UrlModule) registerModule(CatalogModule) - registerModule(CheckoutModule) + registerModule(CheckoutModule) // To Checkout registerModule(CartModule) - registerModule(ReviewModule) - registerModule(MailerModule) - registerModule(WishlistModule) - registerModule(NewsletterModule) + registerModule(ReviewModule) // To Product + registerModule(MailerModule) // load lazily + registerModule(WishlistModule) // Trigger on wishlist icon click + registerModule(NewsletterModule) // Load lazily registerModule(NotificationModule) - registerModule(UserModule) + registerModule(UserModule) // Trigger on user icon click registerModule(CatalogNextModule) registerModule(CompareModule) registerModule(BreadcrumbsModule) registerModule(OrderModule) registerModule(CmsModule) - registerModule(RecentlyViewedModule) + registerModule(RecentlyViewedModule) // To HomePage registerModule(GoogleTagManagerModule) // registerModule(GoogleAnalyticsModule) // registerModule(HotjarModule) registerModule(PaymentBackendMethodsModule) - registerModule(PaymentCashOnDeliveryModule) + registerModule(PaymentCashOnDeliveryModule) // To checkout registerModule(AmpRendererModule) - registerModule(InstantCheckoutModule) + registerModule(InstantCheckoutModule) // Load lazily from Microcart } // Deprecated API, will be removed in 2.0 diff --git a/src/modules/payment-backend-methods/index.ts b/src/modules/payment-backend-methods/index.ts index 62d132b84..f48601c06 100644 --- a/src/modules/payment-backend-methods/index.ts +++ b/src/modules/payment-backend-methods/index.ts @@ -1,7 +1,7 @@ import * as types from './store/mutation-types' import { StorefrontModule } from '@vue-storefront/module'; import { isServer } from '@vue-storefront/core/helpers' -import Vue from 'vue'; +import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' const PaymentBackendMethodsStore = { namespaced: true, @@ -23,20 +23,20 @@ export const PaymentBackendMethodsModule: StorefrontModule = function (app, stor // Place the order. Payload is empty as we don't have any specific info to add for this payment method '{}' const placeOrder = () => { if (correctPaymentMethod) { - Vue.prototype.$bus.$emit('checkout-do-placeOrder', {}) + EventBus.$emit('checkout-do-placeOrder', {}) } } if (!isServer) { // Update the methods - Vue.prototype.$bus.$on('set-unique-payment-methods', methods => { + EventBus.$on('set-unique-payment-methods', methods => { store.commit('payment-backend-methods/' + types.SET_BACKEND_PAYMENT_METHODS, methods) }) - Vue.prototype.$bus.$on('checkout-before-placeOrder', placeOrder) + EventBus.$on('checkout-before-placeOrder', placeOrder) // Mount the info component when required - Vue.prototype.$bus.$on('checkout-payment-method-changed', (paymentMethodCode) => { + EventBus.$on('checkout-payment-method-changed', (paymentMethodCode) => { let methods = store.state['payment-backend-methods'].methods if (methods !== null && methods.find(item => (item.code === paymentMethodCode && item.is_server_method === true))) { correctPaymentMethod = true From 02609ac70e88203a40c8a4106d33ab3b1b7debb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Romanowicz?= <46789227+lukeromanowicz@users.noreply.github.com> Date: Thu, 18 Jul 2019 09:31:20 +0200 Subject: [PATCH 0359/1227] fix unit tests titles --- core/lib/test/unit/multistore.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/lib/test/unit/multistore.spec.ts b/core/lib/test/unit/multistore.spec.ts index eeab0bf14..ff0745f6f 100644 --- a/core/lib/test/unit/multistore.spec.ts +++ b/core/lib/test/unit/multistore.spec.ts @@ -135,7 +135,7 @@ describe('Multistore', () => { }) describe('prepareStoreView', () => { - it('return default storeView', () => { + it('returns default storeView given no storecode', () => { rootStore.state.storeView = {} rootStore.state.user = {} @@ -175,7 +175,7 @@ describe('Multistore', () => { }) }) - it('return default storeView with defaultStoreCode set to de and multistore set to false', () => { + it('returns default storeView without setting defaultStoreCode when multistore mode is disabled', () => { rootStore.state.storeView = {} rootStore.state.user = {} @@ -218,7 +218,7 @@ describe('Multistore', () => { }) }) - it('return default storeView with defaultStoreCode set to de', () => { + it('returns default storeView with defaultStoreCode set when multistore mode is enabled', () => { rootStore.state.storeView = {} rootStore.state.user = {} @@ -261,7 +261,7 @@ describe('Multistore', () => { }) }) - it('return de storeView with merged store config values', () => { + it('returns storeView overwritting default store config values when multistore mode is enabled', () => { rootStore.state.storeView = {} rootStore.state.user = {} @@ -318,7 +318,7 @@ describe('Multistore', () => { }) }) - it('return it storeView with merged store config values', () => { + it('returns storeView extending other storeView in multistore mode', () => { rootStore.state.storeView = {} rootStore.state.user = {} From 9ccce52d7b20e4c09e39c7d3b64e10875f0ade01 Mon Sep 17 00:00:00 2001 From: patzick Date: Thu, 18 Jul 2019 09:41:24 +0200 Subject: [PATCH 0360/1227] fix registering compare module --- core/modules/compare/components/AddToCompare.ts | 5 +++-- core/modules/compare/components/IsOnCompare.ts | 5 +++-- core/modules/compare/components/RemoveFromCompare.ts | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/core/modules/compare/components/AddToCompare.ts b/core/modules/compare/components/AddToCompare.ts index 1d40b8c03..51ee030ac 100644 --- a/core/modules/compare/components/AddToCompare.ts +++ b/core/modules/compare/components/AddToCompare.ts @@ -1,6 +1,7 @@ import Product from '@vue-storefront/core/modules/catalog/types/Product' -import { Compare as CompareModule } from '../' +import { CompareModule } from '../' import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin' +import { registerModule } from '@vue-storefront/module'; export const AddToCompare = { name: 'AddToCompare', @@ -12,7 +13,7 @@ export const AddToCompare = { } }, created () { - CompareModule.register() + registerModule(CompareModule) }, methods: { addToCompare (product: Product) { diff --git a/core/modules/compare/components/IsOnCompare.ts b/core/modules/compare/components/IsOnCompare.ts index 0a627a224..953d775e1 100644 --- a/core/modules/compare/components/IsOnCompare.ts +++ b/core/modules/compare/components/IsOnCompare.ts @@ -1,5 +1,6 @@ -import { Compare as CompareModule } from '..' +import { CompareModule } from '..' import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin' +import { registerModule } from '@vue-storefront/module'; export const IsOnCompare = { name: 'IsOnCompare', @@ -11,7 +12,7 @@ export const IsOnCompare = { } }, created () { - CompareModule.register() + registerModule(CompareModule) }, computed: { isOnCompare () { diff --git a/core/modules/compare/components/RemoveFromCompare.ts b/core/modules/compare/components/RemoveFromCompare.ts index 9e3eff929..4fc06dc96 100644 --- a/core/modules/compare/components/RemoveFromCompare.ts +++ b/core/modules/compare/components/RemoveFromCompare.ts @@ -1,13 +1,14 @@ import Product from '@vue-storefront/core/modules/catalog/types/Product'; -import { Compare as CompareModule } from '..'; +import { CompareModule } from '..'; import compareMountedMixin from '@vue-storefront/core/modules/compare/mixins/compareMountedMixin'; +import { registerModule } from '@vue-storefront/module'; export const RemoveFromCompare = { name: 'RemoveFromCompare', mixins: [compareMountedMixin], methods: { removeFromCompare (product: Product) { - CompareModule.register(); + registerModule(CompareModule) this.$store.dispatch('compare/removeItem', product); } } From de4d24f8c27f3a75bed6de41a8561cf93e9f1c39 Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Thu, 18 Jul 2019 10:18:13 +0200 Subject: [PATCH 0361/1227] #3251 Add ./packages as volume to docker-compose.yml --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index bb75b2ad7..97ade3f72 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,6 +23,7 @@ services: - './package.json:/var/www/package.json' - './src:/var/www/src' - './var:/var/www/var' + - './packages:/var/www/packages' tmpfs: - /var/www/dist ports: From bb21a7cc67058d1c6fc9e3dbc356b37e3b0ab8c0 Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Thu, 18 Jul 2019 10:20:21 +0200 Subject: [PATCH 0362/1227] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3baa952d..155785aa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed aspect ratio in ProductImage component - @przspa (#3187) - Fixed AMP Product page - @przspa (#3227) - Fixed when store has updated, but plugin didn't called - @serzilo (#3238) +- Add ./packages as volume to docker-compose.yml - @cewald (#3251) ### Changed / Improved - Shipping address is saved as default when not logged in user chooses to create account during checkout - @iwonapiotrowska (#2636) From e073566eb1423881a7f285e958cf0a08f0ff2405 Mon Sep 17 00:00:00 2001 From: andrzejewsky Date: Thu, 20 Jun 2019 21:51:01 +0200 Subject: [PATCH 0363/1227] feature/2346 Change product color or size when product is in the cart --- CHANGELOG.md | 1 + config/default.json | 854 ++++++++---------- core/modules/cart/components/Product.ts | 37 + core/modules/cart/helpers/optimizeProduct.ts | 15 + core/modules/cart/store/actions.ts | 35 +- .../catalog/components/ProductOption.ts | 20 + core/modules/catalog/helpers/filters.ts | 37 + core/modules/catalog/helpers/search.ts | 95 ++ core/modules/catalog/store/product/actions.ts | 159 ++-- .../catalog/test/unit/helpers/filters.spec.ts | 79 ++ .../catalog/types/ProductConfiguration.ts | 10 + core/modules/order/store/actions.ts | 4 + core/pages/Product.js | 9 +- docs/guide/basics/configuration.md | 6 + .../core/blocks/Microcart/EditButton.vue | 8 + .../core/blocks/Microcart/EditMode.vue | 36 + .../core/blocks/Microcart/Microcart.vue | 25 +- .../core/blocks/Microcart/Product.vue | 283 ++++-- .../core/blocks/Microcart/RemoveButton.vue | 2 +- src/themes/default/index.js | 2 + src/themes/default/pages/Product.vue | 32 - src/themes/default/store/cart/actions.ts | 28 + src/themes/default/store/cart/getters.ts | 20 + .../getCurrentConfigurationFromTotals.ts | 12 + src/themes/default/store/cart/index.ts | 15 + .../default/store/cart/mutation-types.ts | 5 + src/themes/default/store/cart/mutations.ts | 20 + .../default/store/cart/types/CartState.ts | 5 + .../default/store/cart/types/EditMode.ts | 6 + 29 files changed, 1186 insertions(+), 674 deletions(-) create mode 100644 core/modules/cart/helpers/optimizeProduct.ts create mode 100644 core/modules/catalog/components/ProductOption.ts create mode 100644 core/modules/catalog/helpers/filters.ts create mode 100644 core/modules/catalog/helpers/search.ts create mode 100644 core/modules/catalog/test/unit/helpers/filters.spec.ts create mode 100644 core/modules/catalog/types/ProductConfiguration.ts create mode 100644 src/themes/default/components/core/blocks/Microcart/EditButton.vue create mode 100644 src/themes/default/components/core/blocks/Microcart/EditMode.vue create mode 100644 src/themes/default/store/cart/actions.ts create mode 100644 src/themes/default/store/cart/getters.ts create mode 100644 src/themes/default/store/cart/helpers/getCurrentConfigurationFromTotals.ts create mode 100644 src/themes/default/store/cart/index.ts create mode 100644 src/themes/default/store/cart/mutation-types.ts create mode 100644 src/themes/default/store/cart/mutations.ts create mode 100644 src/themes/default/store/cart/types/CartState.ts create mode 100644 src/themes/default/store/cart/types/EditMode.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 45846bb52..2d30373f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Items count badges for Compare products and wishlist icons at header - @vishal-7037 (#3047) - Get also none product image thumbnails via API - @cewald, @resubaka (#3207) - Added a config option `optimizeShoppingCartOmitFields` - @EmilsM (#3222) +- Added possibility to change color or size of the product that is already in the cart - @andrzejewsky (#2346) ### Fixed - Fixed product link in wishlist and microcart - @michasik (#2987) diff --git a/config/default.json b/config/default.json index c3b2bd065..4037d5359 100644 --- a/config/default.json +++ b/config/default.json @@ -1,337 +1,337 @@ { - "server": { - "host": "localhost", - "port": 3000, - "protocol": "http", - "api": "api", - "devServiceWorker": false, - "useOutputCacheTagging": false, - "useOutputCache": false, - "outputCacheDefaultTtl": 86400, - "availableCacheTags": ["product", "category", "home", "checkout", "page-not-found", "compare", "my-account", "P", "C", "error"], - "invalidateCacheKey": "aeSu7aip", - "dynamicConfigReload": false, - "dynamicConfigContinueOnError": false, - "dynamicConfigExclude": ["ssr", "storeViews", "entities", "localForage", "shipping", "boost", "query"], - "dynamicConfigInclude": [], - "elasticCacheQuota": 4096, - "ssrDisabledFor": { - "extensions": [".png", ".gif", ".jpg", ".jpeg", ".woff", ".eot", ".woff2", ".ttf", ".svg", ".css", ".js", ".json", ".ico", ".tiff", ".tif", ".raw"] - } - }, - "seo": { - "useUrlDispatcher": true, - "disableUrlRoutesPersistentCache": true - }, - "console": { - "showErrorOnProduction" : false, - "verbosityLevel": "display-everything" - }, - "redis": { - "host": "localhost", - "port": 6379, - "db": 0 - }, - "graphql":{ - "host": "localhost", - "port": 8080 - }, - "api": { - "url": "http://localhost:8080" - }, - "elasticsearch": { - "httpAuth": "", - "host": "/api/catalog", - "index": "vue_storefront_catalog", - "min_score": 0.02, - "csrTimeout": 5000, - "ssrTimeout": 1000, - "queryMethod": "GET", - "disablePersistentQueriesCache": true, - "searchScoring": { - "attributes": { - "attribute_code": { - "scoreValues": { "attribute_value": { "weight": 1 } } - } - }, - "fuzziness": 2, - "cutoff_frequency": 0.01, - "max_expansions": 3, - "minimum_should_match": "75%", - "prefix_length": 2, - "boost_mode": "multiply", - "score_mode": "multiply", - "max_boost": 100, - "function_min_score": 1 - }, - "searchableAttributes": { - "name": { - "boost": 4 - }, - "sku": { - "boost": 2 - }, - "category.name": { - "boost": 1 + "server": { + "host": "localhost", + "port": 3000, + "protocol": "http", + "api": "api", + "devServiceWorker": false, + "useOutputCacheTagging": false, + "useOutputCache": false, + "outputCacheDefaultTtl": 86400, + "availableCacheTags": ["product", "category", "home", "checkout", "page-not-found", "compare", "my-account", "P", "C", "error"], + "invalidateCacheKey": "aeSu7aip", + "dynamicConfigReload": false, + "dynamicConfigContinueOnError": false, + "dynamicConfigExclude": ["ssr", "storeViews", "entities", "localForage", "shipping", "boost", "query"], + "dynamicConfigInclude": [], + "elasticCacheQuota": 4096, + "ssrDisabledFor": { + "extensions": [".png", ".gif", ".jpg", ".jpeg", ".woff", ".eot", ".woff2", ".ttf", ".svg", ".css", ".js", ".json", ".ico", ".tiff", ".tif", ".raw"] + } + }, + "seo": { + "useUrlDispatcher": true, + "disableUrlRoutesPersistentCache": true + }, + "console": { + "showErrorOnProduction" : false, + "verbosityLevel": "display-everything" + }, + "redis": { + "host": "localhost", + "port": 6379, + "db": 0 + }, + "graphql":{ + "host": "localhost", + "port": 8080 + }, + "api": { + "url": "http://localhost:8080" + }, + "elasticsearch": { + "httpAuth": "", + "host": "/api/catalog", + "index": "vue_storefront_catalog", + "min_score": 0.02, + "csrTimeout": 5000, + "ssrTimeout": 1000, + "queryMethod": "GET", + "disablePersistentQueriesCache": true, + "searchScoring": { + "attributes": { + "attribute_code": { + "scoreValues": { "attribute_value": { "weight": 1 } } } - } - }, - "ssr": { - "templates": { - "default": "dist/index.html", - "minimal": "dist/index.minimal.html", - "basic": "dist/index.basic.html", - "amp": "dist/index.amp.html" }, - "executeMixedinAsyncData": true, - "initialStateFilter": ["__DEMO_MODE__", "version", "storeView"], - "useInitialStateFilter": true - }, - "queues": { - "maxNetworkTaskAttempts": 1, - "maxCartBypassAttempts": 1 - }, - "defaultStoreCode": "", - "storeViews": { - "multistore": false, - "commonCache": true, - "mapStoreUrlsFor": ["de", "it"], - "de": { - "storeCode": "de", - "disabled": true, - "storeId": 3, - "name": "German Store", - "url": "/de", - "appendStoreCode": true, - "elasticsearch": { - "host": "/api/catalog", - "index": "vue_storefront_catalog_de" - }, - "tax": { - "sourcePriceIncludesTax": false, - "defaultCountry": "DE", - "defaultRegion": "", - "calculateServerSide": true - }, - "i18n": { - "fullCountryName": "Germany", - "fullLanguageName": "German", - "defaultLanguage": "DE", - "defaultCountry": "DE", - "defaultLocale": "de-DE", - "currencyCode": "EUR", - "currencySign": "EUR", - "dateFormat": "HH:mm D-M-YYYY" - } + "fuzziness": 2, + "cutoff_frequency": 0.01, + "max_expansions": 3, + "minimum_should_match": "75%", + "prefix_length": 2, + "boost_mode": "multiply", + "score_mode": "multiply", + "max_boost": 100, + "function_min_score": 1 + }, + "searchableAttributes": { + "name": { + "boost": 4 }, - "it": { - "extend": "de", - "storeCode": "it", - "disabled": true, - "storeId": 4, - "name": "Italian Store", - "url": "/it", - "elasticsearch": { - "host": "/api/catalog", - "index": "vue_storefront_catalog_it" - }, - "tax": { - "defaultCountry": "IT" - }, - "i18n": { - "fullCountryName": "Italy", - "fullLanguageName": "Italian", - "defaultCountry": "IT", - "defaultLanguage": "IT", - "defaultLocale": "it-IT" - } - } - }, - "entities": { - "optimize": true, - "twoStageCaching": true, - "optimizeShoppingCart": true, - "optimizeShoppingCartOmitFields": ["configurable_children", "configurable_options", "media_gallery", "description", "category", "category_ids", "product_links", "stock", "description"], - "category": { - "includeFields": [ "id", "*.children_data.id", "*.id", "children_count", "sku", "name", "is_active", "parent_id", "level", "url_key", "url_path", "product_count", "path"], - "excludeFields": [ "sgn" ], - "categoriesRootCategorylId": 2, - "categoriesDynamicPrefetchLevel": 2, - "categoriesDynamicPrefetch": true + "sku": { + "boost": 2 }, - "attribute": { - "includeFields": [ "attribute_code", "id", "entity_type_id", "options", "default_value", "is_user_defined", "frontend_label", "attribute_id", "default_frontend_label", "is_visible_on_front", "is_visible", "is_comparable", "tier_prices", "frontend_input" ] - }, - "productList": { - "sort": "updated_at:desc", - "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "url_path", "url_key", "status", "tier_prices", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax" ], - "excludeFields": [ "description", "configurable_options", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options" ] - }, - "productListWithChildren": { - "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "configurable_children.tier_prices", "product_links", "url_path", "url_key", "status", "tier_prices"], - "excludeFields": [ "description", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options"] + "category.name": { + "boost": 1 + } + } + }, + "ssr": { + "templates": { + "default": "dist/index.html", + "minimal": "dist/index.minimal.html", + "basic": "dist/index.basic.html", + "amp": "dist/index.amp.html" + }, + "executeMixedinAsyncData": true, + "initialStateFilter": ["__DEMO_MODE__", "version", "storeView"], + "useInitialStateFilter": true + }, + "queues": { + "maxNetworkTaskAttempts": 1, + "maxCartBypassAttempts": 1 + }, + "defaultStoreCode": "", + "storeViews": { + "multistore": false, + "commonCache": true, + "mapStoreUrlsFor": ["de", "it"], + "de": { + "storeCode": "de", + "disabled": true, + "storeId": 3, + "name": "German Store", + "url": "/de", + "appendStoreCode": true, + "elasticsearch": { + "host": "/api/catalog", + "index": "vue_storefront_catalog_de" }, - "review": { - "excludeFields": ["review_entity", "review_status"] + "tax": { + "sourcePriceIncludesTax": false, + "defaultCountry": "DE", + "defaultRegion": "", + "calculateServerSide": true }, - "product": { - "excludeFields": [ "*.msrp_display_actual_price_type", "required_options", "updated_at", "created_at", "attribute_set_id", "options_container", "msrp_display_actual_price_type", "has_options", "stock.manage_stock", "stock.use_config_min_qty", "stock.use_config_notify_stock_qty", "stock.stock_id", "stock.use_config_backorders", "stock.use_config_enable_qty_inc", "stock.enable_qty_increments", "stock.use_config_manage_stock", "stock.use_config_min_sale_qty", "stock.notify_stock_qty", "stock.use_config_max_sale_qty", "stock.use_config_max_sale_qty", "stock.qty_increments", "small_image", "sgn", "*.sgn"], - "includeFields": null, - "useDynamicAttributeLoader": true, - "standardSystemFields": [ - "description", - "configurable_options", - "tsk", - "custom_attributes", - "size_options", - "regular_price", - "final_price", - "final_price_incl_tax", - "final_price_tax", - "price", - "color_options", - "id", - "links", - "gift_message_available", - "category_ids", - "sku", - "stock", - "image", - "thumbnail", - "visibility", - "type_id", - "tax_class_id", - "media_gallery", - "url_key", - "url_path", - "max_price", - "minimal_regular_price", - "special_price", - "minimal_price", - "name", - "configurable_children", - "max_regular_price", - "category", - "status", - "price_tax", - "price_incl_tax", - "special_price_tax", - "special_price_incl_tax", - "_score", - "slug", - "errors", - "info", - "erin_recommends", - "special_from_date", - "news_from_date", - "custom_design_from", - "original_price", - "original_price_incl_tax", - "parentSku", - "options", - "product_option", - "qty", - "is_configured" - ] + "i18n": { + "fullCountryName": "Germany", + "fullLanguageName": "German", + "defaultLanguage": "DE", + "defaultCountry": "DE", + "defaultLocale": "de-DE", + "currencyCode": "EUR", + "currencySign": "EUR", + "dateFormat": "HH:mm D-M-YYYY" } }, - "cart": { - "thumbnails": { - "width": 150, - "height": 150 - }, - "bypassCartLoaderForAuthorizedUsers": true, - "serverMergeByDefault": true, - "serverSyncCanRemoveLocalItems": false, - "serverSyncCanModifyLocalItems": false, - "synchronize": true, - "synchronize_totals": true, - "setCustomProductOptions": true, - "setConfigurableProductOptions": true, - "askBeforeRemoveProduct": true, - "displayItemDiscounts": true, - "minicartCountType": "quantities", - "create_endpoint": "/api/cart/create?token={{token}}", - "updateitem_endpoint": "/api/cart/update?token={{token}}&cartId={{cartId}}", - "deleteitem_endpoint": "/api/cart/delete?token={{token}}&cartId={{cartId}}", - "pull_endpoint": "/api/cart/pull?token={{token}}&cartId={{cartId}}", - "totals_endpoint": "/api/cart/totals?token={{token}}&cartId={{cartId}}", - "paymentmethods_endpoint": "/api/cart/payment-methods?token={{token}}&cartId={{cartId}}", - "shippingmethods_endpoint": "/api/cart/shipping-methods?token={{token}}&cartId={{cartId}}", - "shippinginfo_endpoint": "/api/cart/shipping-information?token={{token}}&cartId={{cartId}}", - "collecttotals_endpoint": "/api/cart/collect-totals?token={{token}}&cartId={{cartId}}", - "deletecoupon_endpoint": "/api/cart/delete-coupon?token={{token}}&cartId={{cartId}}", - "applycoupon_endpoint": "/api/cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}" - }, - "products": { - "disablePersistentProductsCache": true, - "useMagentoUrlKeys": true, - "setFirstVarianAsDefaultInURL": false, - "configurableChildrenStockPrefetchStatic": false, - "configurableChildrenStockPrefetchDynamic": false, - "configurableChildrenStockPrefetchStaticPrefetchCount": 8, - "filterUnavailableVariants": false, - "listOutOfStockProducts": true, - "preventConfigurableChildrenDirectAccess": true, - "alwaysSyncPlatformPricesOver": false, - "clearPricesBeforePlatformSync": false, - "waitForPlatformSync": false, - "setupVariantByAttributeCode": true, - "endpoint": "/api/product", - "defaultFilters": ["color", "size", "price", "erin_recommends"], - "routerFiltersSource": "query", - "filterFieldMapping": { - "category.name": "category.name.keyword" - }, - "colorMappings": { - "Melange graphite": "#eeeeee" - }, - "defaultSortBy": { - "attribute": "updated_at", - "order": "desc" + "it": { + "extend": "de", + "storeCode": "it", + "disabled": true, + "storeId": 4, + "name": "Italian Store", + "url": "/it", + "elasticsearch": { + "host": "/api/catalog", + "index": "vue_storefront_catalog_it" }, - "sortByAttributes": { - "Latest": "updated_at", - "Price: Low to high":"final_price", - "Price: High to low":"final_price:desc" + "tax": { + "defaultCountry": "IT" }, - "gallery": { - "mergeConfigurableChildren": true, - "imageAttributes": ["image","thumbnail","small_image"], - "width": 600, - "height": 744 - }, - "thumbnails": { - "width": 310, - "height": 300 - }, - "filterAggregationSize": { - "default": 10, - "size": 10, - "color": 10 - }, - "priceFilters": { - "ranges": [ - { "from": 0, "to": 50 }, - { "from": 50, "to": 100 }, - { "from": 100, "to": 150 }, - { "from": 150 } - ] + "i18n": { + "fullCountryName": "Italy", + "fullLanguageName": "Italian", + "defaultCountry": "IT", + "defaultLanguage": "IT", + "defaultLocale": "it-IT" } - }, - "orders": { - "directBackendSync": true, - "endpoint": "/api/order", - "payment_methods_mapping": { - }, - "offline_orders": { - "automatic_transmission_enabled": false, - "notification" : { - "enabled": true, - "title" : "Order waiting!", - "message": "Click here to confirm the order that you made offline.", - "icon": "/assets/logo.png" - } + } + }, + "entities": { + "optimize": true, + "twoStageCaching": true, + "optimizeShoppingCart": true, + "optimizeShoppingCartOmitFields": ["configurable_children", "configurable_options", "media_gallery", "description", "category", "category_ids", "product_links", "stock", "description"], + "category": { + "includeFields": [ "id", "*.children_data.id", "*.id", "children_count", "sku", "name", "is_active", "parent_id", "level", "url_key", "url_path", "product_count", "path"], + "excludeFields": [ "sgn" ], + "categoriesRootCategorylId": 2, + "categoriesDynamicPrefetchLevel": 2, + "categoriesDynamicPrefetch": true + }, + "attribute": { + "includeFields": [ "attribute_code", "id", "entity_type_id", "options", "default_value", "is_user_defined", "frontend_label", "attribute_id", "default_frontend_label", "is_visible_on_front", "is_visible", "is_comparable", "tier_prices", "frontend_input" ] + }, + "productList": { + "sort": "updated_at:desc", + "includeFields": [ "type_id", "sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "url_path", "url_key", "status", "tier_prices", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax" ], + "excludeFields": [ "description", "configurable_options", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options" ] + }, + "productListWithChildren": { + "includeFields": [ "type_id", "sku", "name", "tax_class_id", "special_price", "special_to_date", "special_from_date", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "configurable_children.tier_prices", "product_links", "url_path", "url_key", "status", "tier_prices"], + "excludeFields": [ "description", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options"] + }, + "review": { + "excludeFields": ["review_entity", "review_status"] + }, + "product": { + "excludeFields": [ "*.msrp_display_actual_price_type", "required_options", "updated_at", "created_at", "attribute_set_id", "options_container", "msrp_display_actual_price_type", "has_options", "stock.manage_stock", "stock.use_config_min_qty", "stock.use_config_notify_stock_qty", "stock.stock_id", "stock.use_config_backorders", "stock.use_config_enable_qty_inc", "stock.enable_qty_increments", "stock.use_config_manage_stock", "stock.use_config_min_sale_qty", "stock.notify_stock_qty", "stock.use_config_max_sale_qty", "stock.use_config_max_sale_qty", "stock.qty_increments", "small_image", "sgn", "*.sgn"], + "includeFields": null, + "useDynamicAttributeLoader": true, + "standardSystemFields": [ + "description", + "configurable_options", + "tsk", + "custom_attributes", + "size_options", + "regular_price", + "final_price", + "final_price_incl_tax", + "final_price_tax", + "price", + "color_options", + "id", + "links", + "gift_message_available", + "category_ids", + "sku", + "stock", + "image", + "thumbnail", + "visibility", + "type_id", + "tax_class_id", + "media_gallery", + "url_key", + "url_path", + "max_price", + "minimal_regular_price", + "special_price", + "minimal_price", + "name", + "configurable_children", + "max_regular_price", + "category", + "status", + "price_tax", + "price_incl_tax", + "special_price_tax", + "special_price_incl_tax", + "_score", + "slug", + "errors", + "info", + "erin_recommends", + "special_from_date", + "news_from_date", + "custom_design_from", + "original_price", + "original_price_incl_tax", + "parentSku", + "options", + "product_option", + "qty", + "is_configured" + ] + } + }, + "cart": { + "thumbnails": { + "width": 150, + "height": 150 + }, + "bypassCartLoaderForAuthorizedUsers": true, + "serverMergeByDefault": true, + "serverSyncCanRemoveLocalItems": false, + "serverSyncCanModifyLocalItems": false, + "synchronize": true, + "synchronize_totals": true, + "setCustomProductOptions": true, + "setConfigurableProductOptions": true, + "askBeforeRemoveProduct": true, + "displayItemDiscounts": true, + "productsAreReconfigurable": true, + "minicartCountType": "quantities", + "create_endpoint": "/api/cart/create?token={{token}}", + "updateitem_endpoint": "/api/cart/update?token={{token}}&cartId={{cartId}}", + "deleteitem_endpoint": "/api/cart/delete?token={{token}}&cartId={{cartId}}", + "pull_endpoint": "/api/cart/pull?token={{token}}&cartId={{cartId}}", + "totals_endpoint": "/api/cart/totals?token={{token}}&cartId={{cartId}}", + "paymentmethods_endpoint": "/api/cart/payment-methods?token={{token}}&cartId={{cartId}}", + "shippingmethods_endpoint": "/api/cart/shipping-methods?token={{token}}&cartId={{cartId}}", + "shippinginfo_endpoint": "/api/cart/shipping-information?token={{token}}&cartId={{cartId}}", + "collecttotals_endpoint": "/api/cart/collect-totals?token={{token}}&cartId={{cartId}}", + "deletecoupon_endpoint": "/api/cart/delete-coupon?token={{token}}&cartId={{cartId}}", + "applycoupon_endpoint": "/api/cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}" + }, + "products": { + "disablePersistentProductsCache": true, + "useMagentoUrlKeys": true, + "setFirstVarianAsDefaultInURL": false, + "configurableChildrenStockPrefetchStatic": false, + "configurableChildrenStockPrefetchDynamic": false, + "configurableChildrenStockPrefetchStaticPrefetchCount": 8, + "filterUnavailableVariants": false, + "listOutOfStockProducts": true, + "preventConfigurableChildrenDirectAccess": true, + "alwaysSyncPlatformPricesOver": false, + "clearPricesBeforePlatformSync": false, + "waitForPlatformSync": false, + "setupVariantByAttributeCode": true, + "endpoint": "/api/product", + "defaultFilters": ["color", "size", "price", "erin_recommends"], + "routerFiltersSource": "query", + "filterFieldMapping": { + "category.name": "category.name.keyword" + }, + "colorMappings": { + "Melange graphite": "#eeeeee" + }, + "defaultSortBy": { + "attribute": "updated_at", + "order": "desc" + }, + "sortByAttributes": { + "Latest": "updated_at", + "Price: Low to high":"final_price", + "Price: High to low":"final_price:desc" + }, + "gallery": { + "mergeConfigurableChildren": true, + "imageAttributes": ["image","thumbnail","small_image"], + "width": 600, + "height": 744 + }, + "thumbnails": { + "width": 310, + "height": 300 + }, + "filterAggregationSize": { + "default": 10, + "size": 10, + "color": 10 + }, + "priceFilters": { + "ranges": [ + { "from": 0, "to": 50 }, + { "from": 50, "to": 100 }, + { "from": 100, "to": 150 }, + { "from": 150 } + ] + } + }, + "orders": { + "directBackendSync": true, + "endpoint": "/api/order", + "payment_methods_mapping": { + }, + "offline_orders": { + "automatic_transmission_enabled": false, + "notification" : { + "enabled": true, + "title" : "Order waiting!", + "message": "Click here to confirm the order that you made offline.", + "icon": "/assets/logo.png" } }, "localForage": { @@ -350,142 +350,90 @@ "ordersHistory": "LOCALSTORAGE", "checkout": "LOCALSTORAGE" } - }, - "reviews": { - "create_endpoint": "/api/review/create" - }, - "users": { - "autoRefreshTokens": true, - "endpoint": "/api/user", - "history_endpoint": "/api/user/order-history?token={{token}}", - "resetPassword_endpoint": "/api/user/reset-password", - "changePassword_endpoint": "/api/user/change-password?token={{token}}", - "login_endpoint": "/api/user/login", - "create_endpoint": "/api/user/create", - "me_endpoint": "/api/user/me?token={{token}}", - "refresh_endpoint": "/api/user/refresh" - }, - "stock": { - "synchronize": true, - "allowOutOfStockInCart": true, - "endpoint": "/api/stock" - }, - "images": { - "useExactUrlsNoProxy": false, - "baseUrl": "https://demo.vuestorefront.io/img/", - "useSpecificImagePaths": false, - "paths": { - "product": "/catalog/product" - }, - "productPlaceholder": "/assets/placeholder.jpg" - }, - "install": { - "is_local_backend": true, - "backend_dir": "../vue-storefront-api" - }, - "demomode": false, - "tax": { - "defaultCountry": "US", - "defaultRegion": "", - "sourcePriceIncludesTax": false, - "calculateServerSide": true - }, - "shipping": { - "methods": [ + ] + }, + "syncTasks": { + "disablePersistentTaskQueue": true + }, + "i18n": { + "defaultCountry": "US", + "defaultLanguage": "EN", + "availableLocale": ["en-US","de-DE","fr-FR","es-ES","nl-NL", "jp-JP", "ru-RU", "it-IT", "pt-BR", "pl-PL", "cs-CZ"], + "defaultLocale": "en-US", + "currencyCode": "USD", + "currencySign": "$", + "currencySignPlacement": "preppend", + "dateFormat": "HH:mm D/M/YYYY", + "fullCountryName": "United States", + "fullLanguageName": "English", + "bundleAllStoreviewLanguages": true + }, + "newsletter": { + "endpoint": "/api/ext/mailchimp-subscribe/subscribe" + }, + "mailer": { + "endpoint": { + "send": "/api/ext/mail-service/send-email", + "token": "/api/ext/mail-service/get-token" + }, + "contactAddress": "contributors@vuestorefront.io", + "sendConfirmation": true + }, + "theme": "@vue-storefront/theme-default", + "analytics": { + "id": false + }, + "googleTagManager": { + "id": false, + "debug": true + }, + "hotjar": { + "id": false + }, + "cms": { + "endpoint": "/api/ext/cms-data/cms{{type}}/{{cmsId}}", + "endpointIdentifier": "/api/ext/cms-data/cms{{type}}Identifier/{{cmsIdentifier}}/storeId/{{storeId}}" + }, + "cms_block": { + "max_count": 500 + }, + "cms_page": { + "max_count": 500 + }, + "usePriceTiers": false, + "useZeroPriceProduct": true, + "query": { + "inspirations": { + "filter": [ { - "method_title": "DPD Courier", - "method_code": "flatrate", - "carrier_code": "flatrate", - "amount": 4, - "price_incl_tax": 5, - "default": true, - "offline": true + "key": "category.name", + "value" : { "eq": "Performance Fabrics" } } ] }, - "syncTasks": { - "disablePersistentTaskQueue": true - }, - "i18n": { - "defaultCountry": "US", - "defaultLanguage": "EN", - "availableLocale": ["en-US","de-DE","fr-FR","es-ES","nl-NL", "jp-JP", "ru-RU", "it-IT", "pt-BR", "pl-PL", "cs-CZ"], - "defaultLocale": "en-US", - "currencyCode": "USD", - "currencySign": "$", - "currencySignPlacement": "preppend", - "dateFormat": "HH:mm D/M/YYYY", - "fullCountryName": "United States", - "fullLanguageName": "English", - "bundleAllStoreviewLanguages": true - }, - "newsletter": { - "endpoint": "/api/ext/mailchimp-subscribe/subscribe" - }, - "mailer": { - "endpoint": { - "send": "/api/ext/mail-service/send-email", - "token": "/api/ext/mail-service/get-token" - }, - "contactAddress": "contributors@vuestorefront.io", - "sendConfirmation": true - }, - "theme": "@vue-storefront/theme-default", - "analytics": { - "id": false - }, - "googleTagManager": { - "id": false, - "debug": true - }, - "hotjar": { - "id": false - }, - "cms": { - "endpoint": "/api/ext/cms-data/cms{{type}}/{{cmsId}}", - "endpointIdentifier": "/api/ext/cms-data/cms{{type}}Identifier/{{cmsIdentifier}}/storeId/{{storeId}}" - }, - "cms_block": { - "max_count": 500 + "newProducts": { + "filter": [ + { + "key": "category.name", + "value" : { "eq": "Tees" } + } + ] }, - "cms_page": { - "max_count": 500 + "coolBags": { + "filter": [ + { + "key": "category.name", + "value" : { "eq": "Women" } + } + ] }, - "usePriceTiers": false, - "useZeroPriceProduct": true, - "query": { - "inspirations": { - "filter": [ - { - "key": "category.name", - "value" : { "eq": "Performance Fabrics" } - } - ] - }, - "newProducts": { - "filter": [ - { - "key": "category.name", - "value" : { "eq": "Tees" } - } - ] - }, - "coolBags": { - "filter": [ - { - "key": "category.name", - "value" : { "eq": "Women" } - } - ] - }, - "bestSellers": { - "filter": [ - { - "key": "category.name", - "value" : { "eq": "Tees" } - } - ] - } + "bestSellers": { + "filter": [ + { + "key": "category.name", + "value" : { "eq": "Tees" } + } + ] } + } } - diff --git a/core/modules/cart/components/Product.ts b/core/modules/cart/components/Product.ts index 0c07dc86d..3d7104e5c 100644 --- a/core/modules/cart/components/Product.ts +++ b/core/modules/cart/components/Product.ts @@ -15,6 +15,43 @@ export const MicrocartProduct = { if (typeof navigator !== 'undefined' && !navigator.onLine) { return this.getThumbnail(thumbnail, config.products.thumbnails.width, config.products.thumbnails.height) // for offline support we do need to have ProductTile version } else return this.getThumbnail(thumbnail, config.cart.thumbnails.width, config.cart.thumbnails.height) + }, + options () { + const opts = {} + + if (!this.product.configurable_options) { + return null + } + + this.product.configurable_options.forEach(el => { + opts[el.attribute_code] = el.values.map(obj => ({ + id: obj.value_index, + label: obj.label, + attribute_code: el.attribute_code, + type: el.attribute_code + })) + }) + + return opts + }, + configuration () { + if (!this.options) { + return null + } + + const getAttributesFields = (attributeCode) => + this.options[attributeCode].find(c => c.id === parseInt(this.product[attributeCode])) + + return { + color: { + attribute_code: 'color', + ...getAttributesFields('color') + }, + size: { + attribute_code: 'size', + ...getAttributesFields('size') + } + } } }, methods: { diff --git a/core/modules/cart/helpers/optimizeProduct.ts b/core/modules/cart/helpers/optimizeProduct.ts new file mode 100644 index 000000000..9943fd927 --- /dev/null +++ b/core/modules/cart/helpers/optimizeProduct.ts @@ -0,0 +1,15 @@ +import config from 'config' +import omit from 'lodash-es/omit' +import pullAll from 'lodash-es/pullAll' + +const optimizeProduct = (product) => { + let fieldsToOmit = config.entities.optimizeShoppingCartOmitFields + + if (config.cart.productsAreReconfigurable) { + fieldsToOmit = pullAll(fieldsToOmit, ['configurable_children', 'configurable_options']) + } + + return omit(product, fieldsToOmit) +} + +export default optimizeProduct diff --git a/core/modules/cart/store/actions.ts b/core/modules/cart/store/actions.ts index 63ce33d7c..56332e46f 100644 --- a/core/modules/cart/store/actions.ts +++ b/core/modules/cart/store/actions.ts @@ -16,6 +16,8 @@ import config from 'config' import Task from '@vue-storefront/core/lib/sync/types/Task' import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' +import { configureProductAsync } from '@vue-storefront/core/modules/catalog/helpers' +import optimizeProduct from './../helpers/optimizeProduct' let _connectBypassCount = 0 @@ -295,7 +297,7 @@ const actions: ActionTree = { continue } if (config.entities.optimize && config.entities.optimizeShoppingCart) { - product = omit(product, config.entities.optimizeShoppingCartOmitFields) + product = optimizeProduct(product) } if (product.errors !== null && typeof product.errors !== 'undefined') { let productCanBeAdded = true @@ -387,6 +389,27 @@ const actions: ActionTree = { return diffLog } }, + configureItem (context, { product, configuration }) { + const { commit, dispatch, getters } = context + const variant = configureProductAsync(context, { + product, + configuration, + selectDefaultVariant: false + }) + const itemWithSameSku = getters.getCartItems.find(item => item.sku === variant.sku) + + if (itemWithSameSku && product.sku !== variant.sku) { + Logger.debug('Item with the same sku detected', 'cart', { sku: itemWithSameSku.sku })() + commit(types.CART_DEL_ITEM, { product: itemWithSameSku }) + product.qty = parseInt(product.qty) + parseInt(itemWithSameSku.qty) + } + + commit(types.CART_UPD_ITEM_PROPS, { product: { ...product, ...variant } }) + + if (getters.isCartSyncEnabled && product.server_item_id) { + dispatch('sync', { forceClientState: true }) + } + }, /** this action merges in new product properties into existing cart item (by sku) @description this method is part of "public" cart API */ updateItem ({ commit }, { product }) { commit(types.CART_UPD_ITEM_PROPS, { product }) @@ -572,12 +595,14 @@ const actions: ActionTree = { } /** helper - sub method to react for the server response after the sync */ - const _afterServerItemUpdated = async function ({ dispatch, commit }, event, clientItem = null) { + const _afterServerItemUpdated = async function ({ dispatch, commit }, event, clientItem = null, serverItem = null) { Logger.debug('Cart item server sync' + event, 'cart')() diffLog.serverResponses.push({ 'status': event.resultCode, 'sku': clientItem.sku, 'result': event }) if (event.resultCode !== 200) { // TODO: add the strategy to configure behaviour if the product is (confirmed) out of the stock - if (clientItem.server_item_id) { + if (!serverItem) { + commit(types.CART_DEL_ITEM, { product: clientItem, removeByParentSku: false }) + } else if (clientItem.item_id) { dispatch('getItem', clientItem.sku).then((cartItem) => { if (cartItem) { Logger.log('Restoring qty after error' + clientItem.sku + cartItem.prev_qty, 'cart')() @@ -640,7 +665,7 @@ const actions: ActionTree = { product_option: clientItem.product_option } }) - _afterServerItemUpdated({ dispatch, commit }, event, clientItem) + _afterServerItemUpdated({ dispatch, commit }, event, clientItem, serverItem) serverCartUpdateRequired = true totalsShouldBeRefreshed = true } else { @@ -664,7 +689,7 @@ const actions: ActionTree = { product_option: clientItem.product_option } }) - _afterServerItemUpdated({ dispatch, commit }, event, clientItem) + _afterServerItemUpdated({ dispatch, commit }, event, clientItem, serverItem) totalsShouldBeRefreshed = true serverCartUpdateRequired = true } else { diff --git a/core/modules/catalog/components/ProductOption.ts b/core/modules/catalog/components/ProductOption.ts new file mode 100644 index 000000000..4aa4c4452 --- /dev/null +++ b/core/modules/catalog/components/ProductOption.ts @@ -0,0 +1,20 @@ +import { isOptionAvailableAsync } from '@vue-storefront/core/modules/catalog/helpers/index' +import { getAvailableFiltersByProduct, getSelectedFiltersByProduct } from '@vue-storefront/core/modules/catalog/helpers/filters' + +export const ProductOption = { + computed: { + getAvailableFilters () { + return getAvailableFiltersByProduct(this.product) + }, + getSelectedFilters () { + return getSelectedFiltersByProduct(this.product, this.configuration) + } + }, + methods: { + isOptionAvailable (option) { // check if the option is available + let currentConfig = Object.assign({}, this.configuration) + currentConfig[option.type] = option + return isOptionAvailableAsync(this.$store, { product: this.product, configuration: currentConfig }) + } + } +} diff --git a/core/modules/catalog/helpers/filters.ts b/core/modules/catalog/helpers/filters.ts new file mode 100644 index 000000000..fbabfd45c --- /dev/null +++ b/core/modules/catalog/helpers/filters.ts @@ -0,0 +1,37 @@ +import Product from '@vue-storefront/core/modules/catalog/types/Product' +import { ProductConfiguration } from '@vue-storefront/core/modules/catalog/types/ProductConfiguration' + +const getAvailableFiltersByProduct = (product: Product) => { + let filtersMap = {} + if (product && product.configurable_options) { + product.configurable_options.forEach(configurableOption => { + const type = configurableOption.attribute_code + const filterVariants = configurableOption.values.map(({value_index, label}) => { + return {id: value_index, label, type} + }) + filtersMap[type] = filterVariants + }) + } + return filtersMap +} + +const getSelectedFiltersByProduct = (product: Product, configuration: ProductConfiguration) => { + if (!configuration) { + return null + } + + let selectedFilters = {} + if (configuration && product) { + Object.keys(configuration).map(filterType => { + const filter = configuration[filterType] + selectedFilters[filterType] = { + id: filter.id, + label: filter.label, + type: filterType + } + }) + } + return selectedFilters +} + +export { getAvailableFiltersByProduct, getSelectedFiltersByProduct } diff --git a/core/modules/catalog/helpers/search.ts b/core/modules/catalog/helpers/search.ts new file mode 100644 index 000000000..37bf1bc48 --- /dev/null +++ b/core/modules/catalog/helpers/search.ts @@ -0,0 +1,95 @@ +import Vue from 'vue'; +import { Logger } from '@vue-storefront/core/lib/logger'; +import config from 'config'; +import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager'; +import { entityKeyName } from '@vue-storefront/core/store/lib/entities'; + +export const canCache = ({ includeFields, excludeFields }) => { + const isCacheable = includeFields === null && excludeFields === null; + + if (isCacheable) { + Logger.debug('Entity cache is enabled for productList')(); + } else { + Logger.debug('Entity cache is disabled for productList')(); + } + + return isCacheable; +}; + +const getCacheKey = (product, cacheByKey) => { + if (!product[cacheByKey]) { + cacheByKey = 'id'; + } + + return entityKeyName( + cacheByKey, + product[cacheByKey === 'sku' && product['parentSku'] ? 'parentSku' : cacheByKey] + ); // to avoid caching products by configurable_children.sku +}; + +export const configureChildren = product => { + if (product.configurable_children) { + for (let configurableChild of product.configurable_children) { + if (configurableChild.custom_attributes) { + for (let opt of configurableChild.custom_attributes) { + configurableChild[opt.attribute_code] = opt.value; + } + } + } + } + + return product; +}; + +export const storeProductToCache = (product, cacheByKey) => { + const cacheKey = getCacheKey(product, cacheByKey); + const cache = StorageManager.get('elasticCacheCollection'); + + cache + .setItem(cacheKey, product, null, config.products.disablePersistentProductsCache) + .catch(err => { + Logger.error('Cannot store cache for ' + cacheKey, err)(); + if (err.name === 'QuotaExceededError' || err.name === 'NS_ERROR_DOM_QUOTA_REACHED') { + // quota exceeded error + cache.clear(); // clear products cache if quota exceeded + } + }); +}; + +export const preConfigureProduct = ({ product, populateRequestCacheTags }) => { + const shouldPopulateCacheTags = populateRequestCacheTags && Vue.prototype.$ssrRequestContext; + const isFirstVariantAsDefaultInURL = + config.products.setFirstVarianAsDefaultInURL && + product.hasOwnProperty('configurable_children') && + product.configurable_children.length > 0; + product.errors = {}; // this is an object to store validation result for custom options and others + product.info = {}; + + if (shouldPopulateCacheTags) { + Vue.prototype.$ssrRequestContext.output.cacheTags.add(`P${product.id}`); + } + + if (!product.parentSku) { + product.parentSku = product.sku; + } + + if (isFirstVariantAsDefaultInURL) { + product.sku = product.configurable_children[0].sku; + } + + return product; +}; + +export const getOptimizedFields = ({ excludeFields, includeFields }) => { + if (config.entities.optimize) { + return { + excluded: excludeFields || config.entities.product.excludeFields, + included: includeFields || config.entities.product.includeFields + }; + } + + return { excluded: excludeFields, included: includeFields }; +}; + +export const isGroupedOrBundle = product => + product.type_id === 'grouped' || product.type_id === 'bundle'; diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts index ebc638c56..c3c3aa1b8 100644 --- a/core/modules/catalog/store/product/actions.ts +++ b/core/modules/catalog/store/product/actions.ts @@ -1,22 +1,23 @@ import Vue from 'vue' import { ActionTree } from 'vuex' import * as types from './mutation-types' -import { formatBreadCrumbRoutes, productThumbnailPath, isServer } from '@vue-storefront/core/helpers' +import { formatBreadCrumbRoutes, isServer } from '@vue-storefront/core/helpers' import { currentStoreView } from '@vue-storefront/core/lib/multistore' import { configureProductAsync, doPlatformPricesSync, filterOutUnavailableVariants, - calculateTaxes, populateProductConfigurationAsync, setCustomProductOptionsAsync, setBundleProductOptionsAsync, getMediaGallery, configurableChildrenImages, + calculateTaxes, attributeImages } from '../../helpers' +import { preConfigureProduct, getOptimizedFields, configureChildren, storeProductToCache, canCache, isGroupedOrBundle } from '@vue-storefront/core/modules/catalog/helpers/search' import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' import { entityKeyName } from '@vue-storefront/core/store/lib/entities' import { optionLabel } from '../../helpers/optionLabel' -import { quickSearchByQuery, isOnline } from '@vue-storefront/core/lib/search' +import { isOnline } from '@vue-storefront/core/lib/search' import omit from 'lodash-es/omit' import trim from 'lodash-es/trim' import uniqBy from 'lodash-es/uniqBy' @@ -28,6 +29,7 @@ import { TaskQueue } from '@vue-storefront/core/lib/sync' import toString from 'lodash-es/toString' import config from 'config' import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' +import { quickSearchByQuery } from '@vue-storefront/core/lib/search' import { StorageManager } from '@vue-storefront/core/store/lib/storage-manager' const PRODUCT_REENTER_TIMEOUT = 20000 @@ -276,97 +278,81 @@ const actions: ActionTree = { * @param {Int} size page size * @return {Promise} */ - list (context, { query, start = 0, size = 50, entityType = 'product', sort = '', cacheByKey = 'sku', prefetchGroupProducts = !isServer, updateState = false, meta = {}, excludeFields = null, includeFields = null, configuration = null, append = false, populateRequestCacheTags = true }) { - let isCacheable = (includeFields === null && excludeFields === null) - if (isCacheable) { - Logger.debug('Entity cache is enabled for productList')() - } else { - Logger.debug('Entity cache is disabled for productList')() + async list (context, { query, start = 0, size = 50, entityType = 'product', sort = '', cacheByKey = 'sku', prefetchGroupProducts = !isServer, updateState = false, meta = {}, excludeFields = null, includeFields = null, configuration = null, append = false, populateRequestCacheTags = true }) { + const products = await context.dispatch('findProducts', { query, start, size, entityType, sort, cacheByKey, excludeFields, includeFields, configuration, populateRequestCacheTags }) + + await context.dispatch('preConfigureAssociated', { products, prefetchGroupProducts }) + + if (updateState) { + context.commit(types.CATALOG_UPD_PRODUCTS, { products, append: append }) } - if (config.entities.optimize) { - if (excludeFields === null) { // if not set explicitly we do optimize the amount of data by using some default field list; this is cacheable - excludeFields = config.entities.product.excludeFields + EventBus.$emit('product-after-list', { query: query, start: start, size: size, sort: sort, entityType: entityType, meta: meta, result: products }) + + return products + }, + preConfigureAssociated (context, { products, prefetchGroupProducts }) { + for (let product of products.items) { + if (product.url_path) { + const { parentSku, slug } = product + + context.dispatch('url/registerMapping', { + url: product.url_path, + routeData: { + params: { parentSku, slug }, + 'name': product.type_id + '-product' + } + }, { root: true }) } - if (includeFields === null) { // if not set explicitly we do optimize the amount of data by using some default field list; this is cacheable - includeFields = config.entities.product.includeFields + + if (isGroupedOrBundle(product) && prefetchGroupProducts && !isServer) { + context.dispatch('setupAssociated', { product }) } } - return quickSearchByQuery({ query, start, size, entityType, sort, excludeFields, includeFields }).then((resp) => { - if (resp.items && resp.items.length) { // preconfigure products; eg: after filters - for (let product of resp.items) { - if (populateRequestCacheTags && Vue.prototype.$ssrRequestContext) { - Vue.prototype.$ssrRequestContext.output.cacheTags.add(`P${product.id}`) - } - product.errors = {} // this is an object to store validation result for custom options and others - product.info = {} - if (!product.parentSku) { - product.parentSku = product.sku - } - if (config.products.setFirstVarianAsDefaultInURL && product.hasOwnProperty('configurable_children') && product.configurable_children.length > 0) { - product.sku = product.configurable_children[0].sku - } - if (configuration) { - let selectedVariant = configureProductAsync(context, { product: product, configuration: configuration, selectDefaultVariant: false }) - Object.assign(product, omit(selectedVariant, ['visibility'])) - } - if (product.url_path) { - rootStore.dispatch('url/registerMapping', { - url: product.url_path, - routeData: { - params: { - 'parentSku': product.parentSku, - 'slug': product.slug - }, - 'name': product.type_id + '-product' - } - }, { root: true }) - } - } + }, + preConfigureProduct (context, { product, populateRequestCacheTags, configuration }) { + let prod = preConfigureProduct({ product, populateRequestCacheTags }) + + if (configuration) { + const selectedVariant = configureProductAsync(context, { product: prod, selectDefaultVariant: false, configuration }) + Object.assign(prod, omit(selectedVariant, ['visibility'])) + } + + return prod + }, + async configureLoadedProducts (context, { products, isCacheable, cacheByKey, populateRequestCacheTags, configuration }) { + if (products.items && products.items.length) { // preconfigure products; eg: after filters + for (let product of products.items) { + product = await context.dispatch('preConfigureProduct', { product, populateRequestCacheTags, configuration }) // preConfigure(product) } - return calculateTaxes(resp.items, context).then((updatedProducts) => { - // handle cache - const cache = StorageManager.get('elasticCache') - for (let prod of resp.items) { // we store each product separately in cache to have offline access to products/single method - if (prod.configurable_children) { - for (let configurableChild of prod.configurable_children) { - if (configurableChild.custom_attributes) { - for (let opt of configurableChild.custom_attributes) { - configurableChild[opt.attribute_code] = opt.value - } - } - } - } - if (!prod[cacheByKey]) { - cacheByKey = 'id' - } - const cacheKey = entityKeyName(cacheByKey, prod[(cacheByKey === 'sku' && prod['parentSku']) ? 'parentSku' : cacheByKey]) // to avoid caching products by configurable_children.sku - if (isCacheable) { // store cache only for full loads - cache.setItem(cacheKey, prod, null, config.products.disablePersistentProductsCache) - .catch((err) => { - Logger.error('Cannot store cache for ' + cacheKey, err)() - if ( - err.name === 'QuotaExceededError' || - err.name === 'NS_ERROR_DOM_QUOTA_REACHED' - ) { // quota exceeded error - cache.clear() // clear products cache if quota exceeded - } - }) - } - if ((prod.type_id === 'grouped' || prod.type_id === 'bundle') && prefetchGroupProducts && !isServer) { - context.dispatch('setupAssociated', { product: prod }) - } - } - // commit update products list mutation - if (updateState) { - context.commit(types.CATALOG_UPD_PRODUCTS, { products: resp, append: append }) - } - EventBus.$emit('product-after-list', { query: query, start: start, size: size, sort: sort, entityType: entityType, meta: meta, result: resp }) - return resp - }) - }) + } + + await calculateTaxes(products, context) + + for (let prod of products.items) { // we store each product separately in cache to have offline access to products/single method + prod = configureChildren(prod) + + if (isCacheable) { // store cache only for full loads + storeProductToCache(prod, cacheByKey) + } + } + + return products }, + async findProducts (context, { query, start = 0, size = 50, entityType = 'product', sort = '', cacheByKey = 'sku', excludeFields = null, includeFields = null, configuration = null, populateRequestCacheTags = true }) { + const isCacheable = canCache({ includeFields, excludeFields }) + const { excluded, included } = getOptimizedFields({ excludeFields, includeFields }) + const resp = await quickSearchByQuery({ query, start, size, entityType, sort, excludeFields: excluded, includeFields: included }) + const products = await context.dispatch('configureLoadedProducts', { products: resp, isCacheable, cacheByKey, populateRequestCacheTags, configuration }) + return products + }, + async findConfigurableParent (context, { product, configuration }) { + const searchQuery = new SearchQuery() + const query = searchQuery.applyFilter({key: 'configurable_children.sku', value: { 'eq': product.sku }}) + const products = await context.dispatch('findProducts', { query, configuration }) + return products.items && products.items.length > 0 ? products.items[0] : null + }, /** * Update associated products for bundle product * @param context @@ -449,6 +435,7 @@ const actions: ActionTree = { prefetchGroupProducts: false, updateState: false }).then((res) => { + console.log(res) if (res && res.items && res.items.length) { let prd = res.items[0] const _returnProductNoCacheHelper = (subresults) => { diff --git a/core/modules/catalog/test/unit/helpers/filters.spec.ts b/core/modules/catalog/test/unit/helpers/filters.spec.ts new file mode 100644 index 000000000..7a4f54211 --- /dev/null +++ b/core/modules/catalog/test/unit/helpers/filters.spec.ts @@ -0,0 +1,79 @@ +import Product from '@vue-storefront/core/modules/catalog/types/Product'; +import { ProductConfiguration } from '@vue-storefront/core/modules/catalog/types/ProductConfiguration'; +import { + getAvailableFiltersByProduct, + getSelectedFiltersByProduct +} from '@vue-storefront/core/modules/catalog/helpers/filters'; + +const product = ({ + configurable_options: [ + { + attribute_id: '93', + values: [ + { value_index: 50, label: 'Blue' }, + { value_index: 52, label: 'Gray' }, + { value_index: 58, label: 'Red' } + ], + product_id: 755, + id: 101, + label: 'Color', + position: 1, + attribute_code: 'color' + }, + { + attribute_id: '142', + values: [ + { value_index: 176, label: '32' }, + { value_index: 177, label: '33' }, + { value_index: 178, label: '34' }, + { value_index: 179, label: '36' } + ], + product_id: 755, + id: 100, + label: 'Size', + position: 0, + attribute_code: 'size' + } + ] +} as any) as Product; + +describe('Product configuration', () => { + it('returns available filters based on given product', () => { + const availableFilters = getAvailableFiltersByProduct(product) + + expect(availableFilters).toEqual({ + color: [ + { id: 50, label: 'Blue', type: 'color' }, + { id: 52, label: 'Gray', type: 'color' }, + { id: 58, label: 'Red', type: 'color' } + ], + size: [ + { id: 176, label: '32', type: 'size' }, + { id: 177, label: '33', type: 'size' }, + { id: 178, label: '34', type: 'size' }, + { id: 179, label: '36', type: 'size' } + ] + }); + }); + + it('returns selected filters based on given product and current configuration', () => { + const configuration: ProductConfiguration = { + color: { + attribute_code: 'color', + id: 52, + label: 'Gray' + }, + size: { + attribute_code: 'size', + id: 177, + label: '33' + } + } + const selectedFilters = getSelectedFiltersByProduct(product, configuration) + + expect(selectedFilters).toEqual({ + color: { id: 52, label: 'Gray', type: 'color' }, + size: { id: 177, label: '33', type: 'size' } + }) + }); +}); diff --git a/core/modules/catalog/types/ProductConfiguration.ts b/core/modules/catalog/types/ProductConfiguration.ts new file mode 100644 index 000000000..b310020a7 --- /dev/null +++ b/core/modules/catalog/types/ProductConfiguration.ts @@ -0,0 +1,10 @@ +export interface ProductOption { + attribute_code?: string, + id: number, + label: string +} + +export interface ProductConfiguration { + color: ProductOption, + size: ProductOption +} diff --git a/core/modules/order/store/actions.ts b/core/modules/order/store/actions.ts index bfaf23f12..489d2fe8a 100644 --- a/core/modules/order/store/actions.ts +++ b/core/modules/order/store/actions.ts @@ -1,5 +1,6 @@ import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import * as types from './mutation-types' +import omit from 'lodash-es/omit' import { currentStoreView } from '@vue-storefront/core/lib/multistore' import { ActionTree } from 'vuex' import RootState from '@vue-storefront/core/types/RootState' @@ -19,6 +20,9 @@ const actions: ActionTree = { * @param {Order} order order data to be send */ async placeOrder ({ commit, getters, dispatch }, order: Order) { + if (config.entities.optimize && config.entities.optimizeShoppingCart) { + order.products = order.products.map(product => omit(product, ['configurable_options', 'configurable_children'])) as Order['products'] + } // Check if order is already processed/processing const currentOrderHash = sha3_224(JSON.stringify(order)) const isAlreadyProcessed = getters.getSessionOrderHashes.includes(currentOrderHash) diff --git a/core/pages/Product.js b/core/pages/Product.js index 1246db8d9..6d0882900 100644 --- a/core/pages/Product.js +++ b/core/pages/Product.js @@ -7,14 +7,14 @@ import { htmlDecode } from '@vue-storefront/core/filters' import { currentStoreView, localizedRoute } from '@vue-storefront/core/lib/multistore' import { CompareProduct } from '@vue-storefront/core/modules/compare/components/Product.ts' import { AddToCompare } from '@vue-storefront/core/modules/compare/components/AddToCompare.ts' -import { isOptionAvailableAsync } from '@vue-storefront/core/modules/catalog/helpers/index' +import { ProductOption } from '@vue-storefront/core/modules/catalog/components/ProductOption.ts' import omit from 'lodash-es/omit' import Composite from '@vue-storefront/core/mixins/composite' import { Logger } from '@vue-storefront/core/lib/logger' export default { name: 'Product', - mixins: [Composite, AddToCompare, CompareProduct], + mixins: [Composite, AddToCompare, CompareProduct, ProductOption], data () { return { loading: false @@ -124,11 +124,6 @@ export default { // Method renamed to 'removeFromCompare(product)', product is an Object CompareProduct.methods.removeFromCompare.call(this, this.product) }, - isOptionAvailable (option) { // check if the option is available - let currentConfig = Object.assign({}, this.configuration) - currentConfig[option.type] = option - return isOptionAvailableAsync(this.$store, { product: this.product, configuration: currentConfig }) - }, onAfterCustomOptionsChanged (payload) { let priceDelta = 0 let priceDeltaInclTax = 0 diff --git a/docs/guide/basics/configuration.md b/docs/guide/basics/configuration.md index 3c2b12aef..3b8da4ce5 100644 --- a/docs/guide/basics/configuration.md +++ b/docs/guide/basics/configuration.md @@ -363,6 +363,12 @@ If this option is set to `items`, Vue Storefront will calculate the cart count b These endpoints should point to the `vue-storefront-api` instance and typically, you're changing just the domain-name/base-url without touching the specific endpoint URLs, as it's related to the `vue-storefront-api` specifics. +```json + "productsAreReconfigurable": true +``` + +If this option is set to `true`, you can edit current options such as color or size in the cart view. Works only for configurable products. + ## Products ```json diff --git a/src/themes/default/components/core/blocks/Microcart/EditButton.vue b/src/themes/default/components/core/blocks/Microcart/EditButton.vue new file mode 100644 index 000000000..ad2198838 --- /dev/null +++ b/src/themes/default/components/core/blocks/Microcart/EditButton.vue @@ -0,0 +1,8 @@ + diff --git a/src/themes/default/components/core/blocks/Microcart/EditMode.vue b/src/themes/default/components/core/blocks/Microcart/EditMode.vue new file mode 100644 index 000000000..70da1ab9c --- /dev/null +++ b/src/themes/default/components/core/blocks/Microcart/EditMode.vue @@ -0,0 +1,36 @@ + diff --git a/src/themes/default/components/core/blocks/Microcart/Microcart.vue b/src/themes/default/components/core/blocks/Microcart/Microcart.vue index 5b32a96f8..b16fb1cdc 100644 --- a/src/themes/default/components/core/blocks/Microcart/Microcart.vue +++ b/src/themes/default/components/core/blocks/Microcart/Microcart.vue @@ -1,9 +1,12 @@ diff --git a/src/themes/default/components/core/blocks/Microcart/Microcart.vue b/src/themes/default/components/core/blocks/Microcart/Microcart.vue index e30ce8d13..94bfee85c 100644 --- a/src/themes/default/components/core/blocks/Microcart/Microcart.vue +++ b/src/themes/default/components/core/blocks/Microcart/Microcart.vue @@ -205,12 +205,12 @@ export default { }) }, closeMicrocartExtend () { - this.closeMicrocart() + this.toggleMicrocart() this.$store.commit('ui/setSidebar', false) this.addCouponPressed = false }, onEscapePress () { - this.closeMicrocart() + this.toggleMicrocart() }, clearCart () { this.$store.dispatch('notification/spawnNotification', { diff --git a/src/themes/default/components/core/blocks/Microcart/Product.vue b/src/themes/default/components/core/blocks/Microcart/Product.vue index f5c79e81b..54d99dfcd 100644 --- a/src/themes/default/components/core/blocks/Microcart/Product.vue +++ b/src/themes/default/components/core/blocks/Microcart/Product.vue @@ -132,10 +132,11 @@ diff --git a/src/themes/default/components/core/blocks/SidebarMenu/SidebarMenu.vue b/src/themes/default/components/core/blocks/SidebarMenu/SidebarMenu.vue index fcaf0e1fb..bb5608ad5 100644 --- a/src/themes/default/components/core/blocks/SidebarMenu/SidebarMenu.vue +++ b/src/themes/default/components/core/blocks/SidebarMenu/SidebarMenu.vue @@ -141,6 +141,7 @@ import SidebarMenu from '@vue-storefront/core/compatibility/components/blocks/Si import SubBtn from 'theme/components/core/blocks/SidebarMenu/SubBtn' import SubCategory from 'theme/components/core/blocks/SidebarMenu/SubCategory' import { formatCategoryLink } from '@vue-storefront/core/modules/url/helpers' +import { disableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock' export default { components: { @@ -206,10 +207,14 @@ export default { } }, mounted () { + disableBodyScroll(this.$el) this.$nextTick(() => { this.componentLoaded = true }) }, + destroyed () { + clearAllBodyScrollLocks() + }, methods: { login () { if (!this.currentUser && this.isCurrentMenuShowed) { diff --git a/src/themes/default/components/core/blocks/Wishlist/Wishlist.vue b/src/themes/default/components/core/blocks/Wishlist/Wishlist.vue index cebe01a15..1ef11c68a 100644 --- a/src/themes/default/components/core/blocks/Wishlist/Wishlist.vue +++ b/src/themes/default/components/core/blocks/Wishlist/Wishlist.vue @@ -31,6 +31,7 @@ import Wishlist from '@vue-storefront/core/compatibility/components/blocks/Wishlist/Wishlist' import Product from 'theme/components/core/blocks/Wishlist/Product' import ClearWishlistButton from 'theme/components/core/blocks/Wishlist/ClearWishlistButton' +import { disableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock' export default { props: { @@ -59,6 +60,12 @@ export default { }) } }, + mounted () { + disableBodyScroll(this.$el) + }, + destroyed () { + clearAllBodyScrollLocks() + }, mixins: [Wishlist] } From ca9e9dddb05e265e420296c8e0449d93901a1d09 Mon Sep 17 00:00:00 2001 From: przspa Date: Thu, 15 Aug 2019 10:36:35 +0200 Subject: [PATCH 0553/1227] Linted --- .../default/components/core/ProductGalleryZoomCarousel.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/themes/default/components/core/ProductGalleryZoomCarousel.vue b/src/themes/default/components/core/ProductGalleryZoomCarousel.vue index ef1761843..a229fae1d 100644 --- a/src/themes/default/components/core/ProductGalleryZoomCarousel.vue +++ b/src/themes/default/components/core/ProductGalleryZoomCarousel.vue @@ -56,7 +56,6 @@ import { disableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock' import ProductImage from './ProductImage' import ProductVideo from './ProductVideo' - export default { name: 'ProductGalleryZoomCarousel', props: { From 11012dcc558c5a91d3b2455a9697e2dcd81f0ad0 Mon Sep 17 00:00:00 2001 From: przspa Date: Thu, 15 Aug 2019 10:40:22 +0200 Subject: [PATCH 0554/1227] Updated changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 537667270..72233ed02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,7 +65,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Refactored the vuex user module - @andrzejewsky (#3095) - Brazilian Portuguese (pt_BR) translation improved - @pxfm (#3288) - Moved store/lib to /lib - @pxfm (#3253) -- Improved some of the german translations in spelling and wording - @MariaKern (#3297) +- Improved some of the german translations in spelling and wording - @MariaKern (#3297) +- Changed body no-scroll behavior for overlapped element - @przspa (#3363) ## [1.10.0-rc.2] - UNRELEASED From 6eca28b4cb1ae7902fb3d241321bc526d98f8208 Mon Sep 17 00:00:00 2001 From: przspa Date: Thu, 15 Aug 2019 11:19:12 +0200 Subject: [PATCH 0555/1227] Linted --- core/lib/multistore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index e1ffff731..09b3f877b 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -147,7 +147,7 @@ export function storeCodeFromRoute (matchedRouteOrUrl: LocalizedRoute | RawLocat return storeCode } } - } + } return '' } From 678497fe4915db23935a610c6421d60d5c741b3d Mon Sep 17 00:00:00 2001 From: Chirag Viradya Date: Fri, 16 Aug 2019 12:03:46 +0530 Subject: [PATCH 0556/1227] Remove unnecessary code from productCustomOption --- core/modules/catalog/components/ProductCustomOption.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/core/modules/catalog/components/ProductCustomOption.ts b/core/modules/catalog/components/ProductCustomOption.ts index c413d04bf..fba4d4e19 100644 --- a/core/modules/catalog/components/ProductCustomOption.ts +++ b/core/modules/catalog/components/ProductCustomOption.ts @@ -38,12 +38,7 @@ export const ProductCustomOption = { methods: { filterChanged (filterOption) { if (filterOption.attribute_code === this.code) { - if (filterOption.id === this.id) { - this.active = !this.active - } else { - this.active = false - } - // filterOption.id === this.id ? this.active = true : this.active = false + filterOption.id === this.id ? this.active = !this.active : this.active = false } }, filterReset (filterOption) { From b91d1b4ea93e1cb3400e48f0c9c238578302a743 Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Fri, 16 Aug 2019 11:10:37 +0200 Subject: [PATCH 0557/1227] #3372 `dynamicConfigReload` should use deep copy for `Object.assign()` --- core/scripts/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/scripts/server.js b/core/scripts/server.js index 444b188ef..a81978da7 100755 --- a/core/scripts/server.js +++ b/core/scripts/server.js @@ -212,7 +212,7 @@ app.get('*', (req, res, next) => { config = require('config') // reload config if (typeof serverExtensions.configProvider === 'function') { serverExtensions.configProvider(req).then(loadedConfig => { - config = Object.assign(config, loadedConfig) // merge loaded conf with build time conf + config = config.util.extendDeep(config, loadedConfig) dynamicCacheHandler() }).catch(error => { if (config.server.dynamicConfigContinueOnError) { From d651a1149c8953dc92fa419a41291697b0fcb38b Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Fri, 16 Aug 2019 11:15:51 +0200 Subject: [PATCH 0558/1227] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cbf809eb..32cc66440 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moved store/lib to /lib - @pxfm (#3253) - Corrected usage of "configurableChildrenStockPrefetchStatic" setting, refactored logic to tested helper - @philippsander (#859) - Improved some of the german translations in spelling and wording - @MariaKern (#3297) +- `config.dynamicConfigReload` option should use deep copy for `Object.assign()` - @cewald (#3372) ## [1.10.0] - 2019.08.10 From 4644d7e2a8291b3bad746a86cd761f2a910dbb96 Mon Sep 17 00:00:00 2001 From: Chirag Viradya Date: Fri, 16 Aug 2019 15:20:24 +0530 Subject: [PATCH 0559/1227] Improved condition for easy understanding to any developer --- core/modules/catalog/components/ProductCustomOption.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modules/catalog/components/ProductCustomOption.ts b/core/modules/catalog/components/ProductCustomOption.ts index fba4d4e19..e3752ecb1 100644 --- a/core/modules/catalog/components/ProductCustomOption.ts +++ b/core/modules/catalog/components/ProductCustomOption.ts @@ -38,7 +38,7 @@ export const ProductCustomOption = { methods: { filterChanged (filterOption) { if (filterOption.attribute_code === this.code) { - filterOption.id === this.id ? this.active = !this.active : this.active = false + this.active = filterOption.id === this.id ? !this.active : false } }, filterReset (filterOption) { From 7281f971db16cb8b8ff47bdea089446ffe6930b3 Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Sun, 18 Aug 2019 15:27:39 +0200 Subject: [PATCH 0560/1227] Added test for getThumbnailPath in for helper/index.ts --- .../test/unit/getThumbnailPath.spec.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 core/helpers/test/unit/getThumbnailPath.spec.ts diff --git a/core/helpers/test/unit/getThumbnailPath.spec.ts b/core/helpers/test/unit/getThumbnailPath.spec.ts new file mode 100644 index 000000000..dc85506d9 --- /dev/null +++ b/core/helpers/test/unit/getThumbnailPath.spec.ts @@ -0,0 +1,25 @@ +import { slugify } from '@vue-storefront/core/helpers' +import config from 'config' + +jest.clearAllMocks() +jest.mock('config', () => ({})) +jest.mock('@vue-storefront/core/lib/logger', () => ({ + Logger: {} +})) +jest.mock('@vue-storefront/core/store', () => ({})) +jest.mock('@vue-storefront/core/modules/url/helpers', () => ({})) +jest.mock('@vue-storefront/core/lib/multistore', () => ({})) + +describe('slugify', () => { + it('Check if all strings are replaced to the right chars and that text is lowercase in the return', () => { + expect(slugify('testing')).toBe('testing') + expect(slugify('testing--')).toBe('testing-') + expect(slugify('TESTING--&')).toBe('testing-and-') + expect(slugify('TESTING--& ')).toBe('testing-and-') + expect(slugify('TES TING--& ')).toBe('tes-ting-and-') + }) + + it('Check that an error is thrown when the parameter is not an string', () => { + expect(() => slugify(12)).toThrow('string.replace is not a function') + }) +}) From 4295a53e5cc798a17024d00e8697640fa8da154b Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Sun, 18 Aug 2019 15:28:33 +0200 Subject: [PATCH 0561/1227] Added test for processURLAddress in for helper/index.ts --- .../test/unit/processURLAddress.spec.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 core/helpers/test/unit/processURLAddress.spec.ts diff --git a/core/helpers/test/unit/processURLAddress.spec.ts b/core/helpers/test/unit/processURLAddress.spec.ts new file mode 100644 index 000000000..d44e04126 --- /dev/null +++ b/core/helpers/test/unit/processURLAddress.spec.ts @@ -0,0 +1,21 @@ +import { processURLAddress } from '@vue-storefront/core/helpers' +import config from 'config' + +jest.clearAllMocks() +jest.mock('config', () => ({})) +jest.mock('@vue-storefront/core/lib/logger', () => ({ + Logger: {} +})) +jest.mock('@vue-storefront/core/store', () => ({})) +jest.mock('@vue-storefront/core/modules/url/helpers', () => ({})) +jest.mock('@vue-storefront/core/lib/multistore', () => ({})) + +describe('processURLAddress', () => { + it('Check that the url that comes back has the right value', () => { + config.api = { + url: 'api' + } + expect(processURLAddress('/testing')).toBe('api/testing') + expect(processURLAddress('testing')).toBe('testing') + }) +}) From c9a815c62a654446cbabc86177e3f8ed37dafa0e Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Sun, 18 Aug 2019 15:28:53 +0200 Subject: [PATCH 0562/1227] Added test for slugify in for helper/index.ts --- core/helpers/test/unit/slugify.spec.ts | 60 ++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 core/helpers/test/unit/slugify.spec.ts diff --git a/core/helpers/test/unit/slugify.spec.ts b/core/helpers/test/unit/slugify.spec.ts new file mode 100644 index 000000000..b9bdb582f --- /dev/null +++ b/core/helpers/test/unit/slugify.spec.ts @@ -0,0 +1,60 @@ +import { getThumbnailPath } from '@vue-storefront/core/helpers' +import config from 'config' + +jest.clearAllMocks() +jest.mock('config', () => ({})) +jest.mock('@vue-storefront/core/lib/logger', () => ({ + Logger: {} +})) +jest.mock('@vue-storefront/core/store', () => ({})) +jest.mock('@vue-storefront/core/modules/url/helpers', () => ({})) +jest.mock('@vue-storefront/core/lib/multistore', () => ({})) + +describe('getThumbnailPath', () => { + it('Get right value when useExactUrlsNoProxy is set', () => { + config.images = { + useExactUrlsNoProxy: true + } + expect(getThumbnailPath('testing')).toBe('testing') + }) + + it('Get right value when productPlaceholder is set', () => { + config.images = { + productPlaceholder: 'productPlaceholder' + } + expect(getThumbnailPath('no_selection')).toBe('productPlaceholder') + }) + + it('Get right value when useSpecificImagePaths is set', () => { + config.images = { + useSpecificImagePaths: true, + paths: { + product: '/catalog/product', + test: '/test' + } + } + expect(getThumbnailPath('/prod', 10, 10, 'test')).toBe('10/10/resize/test/prod') + expect(getThumbnailPath('/prod', 10, 10)).toBe('10/10/resize/catalog/product/prod') + }) + it('Get right value when useSpecificImagePaths and baseUrl are set', () => { + config.images = { + useSpecificImagePaths: true, + baseUrl: 'test/', + paths: { + product: '/catalog/product', + test: '/test' + } + } + expect(getThumbnailPath('/prod', 10, 10, 'test')).toBe('test/10/10/resize/test/prod') + expect(getThumbnailPath('/prod', 10, 10)).toBe('test/10/10/resize/catalog/product/prod') + }) + + it('Get right value when baseUrl is set', () => { + config.images = { + baseUrl: 'test/' + } + expect(getThumbnailPath('/test')).toBe('test/0/0/resize/test') + expect(getThumbnailPath('/test', 10, 20)).toBe('test/10/20/resize/test') + expect(getThumbnailPath('/test', 30, 20)).toBe('test/30/20/resize/test') + }) +}) From 0adacb982c700674036685a45bdd912dc692862e Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Sun, 18 Aug 2019 15:33:16 +0200 Subject: [PATCH 0563/1227] updated CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1fa60875..6996593b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added test:unit:watch with a workaround of a jest problem with template strings - @resubaka (#3351) - Added test to multistore.ts so it is nearly fully unit tested - @resubaka (#3352) - Added test:unit:watch with a workaround of a jest problem with template strings - @resubaka (#3351, #3354) +- Added test to helpers/index.ts so it is partly tested - @resubaka (#3352) ### Fixed From 1e67485599f74c1841f598e1ff4b9dec209fa250 Mon Sep 17 00:00:00 2001 From: andrzejewsky Date: Fri, 16 Aug 2019 17:28:34 +0200 Subject: [PATCH 0564/1227] Load modules on-demand --- config/default.json | 2 +- src/modules/index.ts | 30 +++++-------------- .../core/blocks/Checkout/OrderReview.vue | 5 ++++ .../core/blocks/Checkout/ThankYouPage.vue | 5 ++++ .../core/blocks/Microcart/Microcart.vue | 5 ++++ src/themes/default/pages/Checkout.vue | 5 ++++ src/themes/default/pages/CmsPage.vue | 1 + src/themes/default/pages/Home.vue | 5 ++++ src/themes/default/pages/Product.vue | 7 +++++ 9 files changed, 42 insertions(+), 23 deletions(-) diff --git a/config/default.json b/config/default.json index e9f9f1bbd..ccaeb725c 100644 --- a/config/default.json +++ b/config/default.json @@ -88,7 +88,7 @@ "amp": "dist/index.amp.html" }, "executeMixedinAsyncData": true, - "initialStateFilter": ["__DEMO_MODE__", "version", "storeView", "attribute", "checkout"], + "initialStateFilter": ["__DEMO_MODE__", "version", "storeView", "attribute"], "useInitialStateFilter": true }, "queues": { diff --git a/src/modules/index.ts b/src/modules/index.ts index 9049b4f51..cb685619a 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -4,24 +4,17 @@ import { CatalogNextModule } from '@vue-storefront/core/modules/catalog-next' import { CartModule } from '@vue-storefront/core/modules/cart' import { CheckoutModule } from '@vue-storefront/core/modules/checkout' import { CompareModule } from '@vue-storefront/core/modules/compare' -import { ReviewModule } from '@vue-storefront/core/modules/review' -import { MailerModule } from '@vue-storefront/core/modules/mailer' import { WishlistModule } from '@vue-storefront/core/modules/wishlist' -import { NewsletterModule } from '@vue-storefront/core/modules/newsletter' import { NotificationModule } from '@vue-storefront/core/modules/notification' -import { RecentlyViewedModule } from '@vue-storefront/core/modules/recently-viewed' import { UrlModule } from '@vue-storefront/core/modules/url' import { BreadcrumbsModule } from '@vue-storefront/core/modules/breadcrumbs' -import { OrderModule } from '@vue-storefront/core/modules/order' -import { CmsModule } from '@vue-storefront/core/modules/cms' import { UserModule } from '@vue-storefront/core/modules/user' -// import { GoogleAnalyticsModule } from './google-analytics'; -// import { HotjarModule } from './hotjar'; +import { CmsModule } from '@vue-storefront/core/modules/cms' import { GoogleTagManagerModule } from './google-tag-manager'; import { AmpRendererModule } from './amp-renderer'; -import { PaymentBackendMethodsModule } from './payment-backend-methods'; -import { PaymentCashOnDeliveryModule } from './payment-cash-on-delivery'; -import { InstantCheckoutModule } from './instant-checkout' +import { PaymentBackendMethodsModule } from './payment-backend-methods' +import { PaymentCashOnDeliveryModule } from './payment-cash-on-delivery' +import { NewsletterModule } from '@vue-storefront/core/modules/newsletter' import { registerModule } from '@vue-storefront/core/lib/modules' @@ -31,25 +24,18 @@ export function registerNewModules () { registerModule(CatalogModule) registerModule(CheckoutModule) // To Checkout registerModule(CartModule) - registerModule(ReviewModule) // To Product - registerModule(MailerModule) // load lazily + registerModule(PaymentBackendMethodsModule) + registerModule(PaymentCashOnDeliveryModule) registerModule(WishlistModule) // Trigger on wishlist icon click - registerModule(NewsletterModule) // Load lazily registerModule(NotificationModule) registerModule(UserModule) // Trigger on user icon click registerModule(CatalogNextModule) registerModule(CompareModule) registerModule(BreadcrumbsModule) - registerModule(OrderModule) - registerModule(CmsModule) - registerModule(RecentlyViewedModule) // To HomePage registerModule(GoogleTagManagerModule) - // registerModule(GoogleAnalyticsModule) - // registerModule(HotjarModule) - registerModule(PaymentBackendMethodsModule) - registerModule(PaymentCashOnDeliveryModule) // To checkout registerModule(AmpRendererModule) - registerModule(InstantCheckoutModule) // Load lazily from Microcart + registerModule(CmsModule) + registerModule(NewsletterModule) } // Deprecated API, will be removed in 2.0 diff --git a/src/themes/default/components/core/blocks/Checkout/OrderReview.vue b/src/themes/default/components/core/blocks/Checkout/OrderReview.vue index 64ce89dbf..0899de8ba 100644 --- a/src/themes/default/components/core/blocks/Checkout/OrderReview.vue +++ b/src/themes/default/components/core/blocks/Checkout/OrderReview.vue @@ -116,6 +116,8 @@ import ButtonFull from 'theme/components/theme/ButtonFull' import CartSummary from 'theme/components/core/blocks/Checkout/CartSummary' import Modal from 'theme/components/core/Modal' import { OrderReview } from '@vue-storefront/core/modules/checkout/components/OrderReview' +import { OrderModule } from '@vue-storefront/core/modules/order' +import { registerModule } from '@vue-storefront/core/lib/modules' export default { components: { @@ -132,6 +134,9 @@ export default { } } }, + beforeCreate () { + registerModule(OrderModule) + }, methods: { onSuccess () { }, diff --git a/src/themes/default/components/core/blocks/Checkout/ThankYouPage.vue b/src/themes/default/components/core/blocks/Checkout/ThankYouPage.vue index e47430962..ce717f68a 100644 --- a/src/themes/default/components/core/blocks/Checkout/ThankYouPage.vue +++ b/src/themes/default/components/core/blocks/Checkout/ThankYouPage.vue @@ -85,10 +85,15 @@ import VueOfflineMixin from 'vue-offline/mixin' import { EmailForm } from '@vue-storefront/core/modules/mailer/components/EmailForm' import { isServer } from '@vue-storefront/core/helpers' import config from 'config' +import { registerModule } from '@vue-storefront/core/lib/modules' +import { MailerModule } from '@vue-storefront/core/modules/mailer' export default { name: 'ThankYouPage', mixins: [Composite, VueOfflineMixin, EmailForm], + beforeCreate () { + registerModule(MailerModule) + }, data () { return { feedback: '' diff --git a/src/themes/default/components/core/blocks/Microcart/Microcart.vue b/src/themes/default/components/core/blocks/Microcart/Microcart.vue index b013cbeaf..06affa9f8 100644 --- a/src/themes/default/components/core/blocks/Microcart/Microcart.vue +++ b/src/themes/default/components/core/blocks/Microcart/Microcart.vue @@ -131,6 +131,7 @@ import { isModuleRegistered } from '@vue-storefront/core/lib/modules' import VueOfflineMixin from 'vue-offline/mixin' import onEscapePress from '@vue-storefront/core/mixins/onEscapePress' import InstantCheckout from 'src/modules/instant-checkout/components/InstantCheckout.vue' +import { registerModule } from '@vue-storefront/core/lib/modules' import BaseInput from 'theme/components/core/blocks/Form/BaseInput' import ClearCartButton from 'theme/components/core/blocks/Microcart/ClearCartButton' @@ -138,6 +139,7 @@ import ButtonFull from 'theme/components/theme/ButtonFull' import ButtonOutline from 'theme/components/theme/ButtonOutline' import Product from 'theme/components/core/blocks/Microcart/Product' import EditMode from './EditMode' +import { InstantCheckoutModule } from 'src/modules/instant-checkout' export default { components: { @@ -168,6 +170,9 @@ export default { default: () => false } }, + beforeCreate () { + registerModule(InstantCheckoutModule) + }, mounted () { this.$nextTick(() => { this.componentLoaded = true diff --git a/src/themes/default/pages/Checkout.vue b/src/themes/default/pages/Checkout.vue index 40bf4e050..ded5f55ca 100644 --- a/src/themes/default/pages/Checkout.vue +++ b/src/themes/default/pages/Checkout.vue @@ -36,6 +36,8 @@ import Payment from 'theme/components/core/blocks/Checkout/Payment' import OrderReview from 'theme/components/core/blocks/Checkout/OrderReview' import CartSummary from 'theme/components/core/blocks/Checkout/CartSummary' import ThankYouPage from 'theme/components/core/blocks/Checkout/ThankYouPage' +import { registerModule } from '@vue-storefront/core/lib/modules' +import { OrderModule } from '@vue-storefront/core/modules/order' export default { components: { @@ -47,6 +49,9 @@ export default { ThankYouPage }, mixins: [Checkout], + beforeCreate () { + registerModule(OrderModule) + }, methods: { notifyEmptyCart () { this.$store.dispatch('notification/spawnNotification', { diff --git a/src/themes/default/pages/CmsPage.vue b/src/themes/default/pages/CmsPage.vue index a0d05a031..833c31e57 100644 --- a/src/themes/default/pages/CmsPage.vue +++ b/src/themes/default/pages/CmsPage.vue @@ -15,6 +15,7 @@ diff --git a/src/themes/default/components/theme/blocks/AsyncSidebar/AsyncSidebar.vue b/src/themes/default/components/theme/blocks/AsyncSidebar/AsyncSidebar.vue index f08d247d3..1b2f589b7 100644 --- a/src/themes/default/components/theme/blocks/AsyncSidebar/AsyncSidebar.vue +++ b/src/themes/default/components/theme/blocks/AsyncSidebar/AsyncSidebar.vue @@ -4,6 +4,7 @@ class="mw-100 fixed cl-accent bg-cl-primary" :class="direction === 'left' ? 'left-sidebar' : direction === 'right' ? 'right-sidebar' : null " data-testid="sidebar" + ref="sidebar" v-if="isOpen" > @@ -14,6 +15,7 @@ From e29531af40c703fb941280fb79a4eca241c928fc Mon Sep 17 00:00:00 2001 From: przspa Date: Mon, 26 Aug 2019 14:34:17 +0200 Subject: [PATCH 0605/1227] Fixed modal backgrounds --- src/themes/default/components/core/blocks/Auth/ForgotPass.vue | 2 +- src/themes/default/components/core/blocks/Auth/Login.vue | 2 +- src/themes/default/components/core/blocks/Auth/Register.vue | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/themes/default/components/core/blocks/Auth/ForgotPass.vue b/src/themes/default/components/core/blocks/Auth/ForgotPass.vue index bdb872a35..ec8b98f23 100644 --- a/src/themes/default/components/core/blocks/Auth/ForgotPass.vue +++ b/src/themes/default/components/core/blocks/Auth/ForgotPass.vue @@ -11,7 +11,7 @@ -