From 521ff1bf57ad39c561274b7a0b4741444ac6f1c2 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Fri, 27 Sep 2019 14:55:05 +0200 Subject: [PATCH 01/47] added catch for fetching single product in cart synchronization --- CHANGELOG.md | 1 + core/modules/cart/store/actions.ts | 76 ++++++++++++++++-------------- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74194c84c6..53e74546d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Broken sidebar menu in mobile view - @przspa (#3549) - UrlDispatcher issues with multistore routes - @pkarw (#3568) +- Added try/catch for fetching single product in cart synchronization - @gibkigonzo (#) ## [1.10.2] - 2019.09.06 diff --git a/core/modules/cart/store/actions.ts b/core/modules/cart/store/actions.ts index 8b8dc1e1eb..ceead6c952 100644 --- a/core/modules/cart/store/actions.ts +++ b/core/modules/cart/store/actions.ts @@ -545,20 +545,16 @@ const actions: ActionTree = { const clientCartAddItems = [] /** helper to find the item to be added to the cart by sku */ - let productActionOptions = (serverItem) => { - return new Promise(resolve => { - if (serverItem.product_type === 'configurable') { - let searchQuery = new SearchQuery() - searchQuery = searchQuery.applyFilter({key: 'configurable_children.sku', value: {'eq': serverItem.sku}}) - dispatch('product/list', {query: searchQuery, start: 0, size: 1, updateState: false}, { root: true }).then((resp) => { - if (resp.items.length >= 1) { - resolve({ sku: resp.items[0].sku, childSku: serverItem.sku }) - } - }) - } else { - resolve({ sku: serverItem.sku }) - } - }) + const productActionOptions = async (serverItem) => { + if (serverItem.product_type === 'configurable') { + let query = new SearchQuery() + query = query.applyFilter({key: 'configurable_children.sku', value: {'eq': serverItem.sku}}) + + const { items } = await dispatch('product/list', { query, start: 0, size: 1, updateState: false }, { root: true }) + + return items.length >= 1 ? { sku: items[0].sku, childSku: serverItem.sku } : null + } + return { sku: serverItem.sku } } /** helper - sub method to update the item in the cart */ const _updateClientItem = async function ({ dispatch }, event, clientItem) { @@ -703,38 +699,48 @@ const actions: ActionTree = { }) diffLog.serverResponses.push({ 'status': res.resultCode, 'sku': serverItem.sku, 'result': res }) } else { - clientCartAddItems.push( - new Promise(resolve => { - productActionOptions(serverItem).then((actionOtions) => { - dispatch('product/single', { options: actionOtions, assignDefaultVariant: true, setCurrentProduct: false, selectDefaultVariant: false }, { root: true }).then((product) => { - resolve({ product: product, serverItem: serverItem }) - }) - }) - }) - ) + const getServerCartItem = new Promise(async resolve => { + try { + const actionOtions = await productActionOptions(serverItem) + + if (!actionOtions) { + resolve(null) + } + + const product = await dispatch('product/single', { options: actionOtions, assignDefaultVariant: true, setCurrentProduct: false, selectDefaultVariant: false }, { root: true }) + + resolve({ product: product, serverItem: serverItem }) + } catch (err) { + resolve(null) + } + }) + clientCartAddItems.push(getServerCartItem) } } } } } - if (clientCartAddItems.length) { + + const resolvedCartItems = await Promise.all(clientCartAddItems) + const validCartItems = resolvedCartItems.filter(Boolean) + + if (validCartItems.length) { totalsShouldBeRefreshed = true clientCartUpdateRequired = true cartHasItems = true } diffLog.items.push({ 'party': 'client', 'status': clientCartUpdateRequired ? 'update-required' : 'no-changes' }) diffLog.items.push({ 'party': 'server', 'status': serverCartUpdateRequired ? 'update-required' : 'no-changes' }) - Promise.all(clientCartAddItems).then((items) => { - items.map(({ product, serverItem }) => { - product.server_item_id = serverItem.item_id - product.qty = serverItem.qty - product.server_cart_id = serverItem.quote_id - if (serverItem.product_option) { - product.product_option = serverItem.product_option - } - dispatch('addItem', { productToAdd: product, forceServerSilence: true }) - }) - }) + + for (const { product, serverItem } of validCartItems) { + product.server_item_id = serverItem.item_id + product.qty = serverItem.qty + product.server_cart_id = serverItem.quote_id + if (serverItem.product_option) { + product.product_option = serverItem.product_option + } + dispatch('addItem', { productToAdd: product, forceServerSilence: true }) + } if (!dryRun) { if (totalsShouldBeRefreshed && cartHasItems) { From f0d539c5f7fc8c58c42d164fa732018d60faab45 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Fri, 27 Sep 2019 15:54:43 +0200 Subject: [PATCH 02/47] update changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53e74546d1..d5312d3e05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,16 @@ 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/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.10.4] - 2019.09.27 + +### Fixed +- Added try/catch for fetching single product in cart synchronization - @gibkigonzo (#) + ## [1.10.3] - 2019.09.18 ### Fixed - Broken sidebar menu in mobile view - @przspa (#3549) - UrlDispatcher issues with multistore routes - @pkarw (#3568) -- Added try/catch for fetching single product in cart synchronization - @gibkigonzo (#) ## [1.10.2] - 2019.09.06 From b09c9c78a292d5d68495a13881012e37a7788f20 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Sun, 29 Sep 2019 15:57:47 +0200 Subject: [PATCH 03/47] change Promise to async --- core/modules/cart/store/actions.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/modules/cart/store/actions.ts b/core/modules/cart/store/actions.ts index ceead6c952..147af113c9 100644 --- a/core/modules/cart/store/actions.ts +++ b/core/modules/cart/store/actions.ts @@ -699,22 +699,22 @@ const actions: ActionTree = { }) diffLog.serverResponses.push({ 'status': res.resultCode, 'sku': serverItem.sku, 'result': res }) } else { - const getServerCartItem = new Promise(async resolve => { + const getServerCartItem = async () => { try { const actionOtions = await productActionOptions(serverItem) if (!actionOtions) { - resolve(null) + return null } const product = await dispatch('product/single', { options: actionOtions, assignDefaultVariant: true, setCurrentProduct: false, selectDefaultVariant: false }, { root: true }) - resolve({ product: product, serverItem: serverItem }) + return { product: product, serverItem: serverItem } } catch (err) { - resolve(null) + return null } - }) - clientCartAddItems.push(getServerCartItem) + } + clientCartAddItems.push(getServerCartItem()) } } } From 3f0f08803d4cb62a92a423cf748d7dcb49073934 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 30 Sep 2019 08:05:11 +0200 Subject: [PATCH 04/47] check if product exist --- core/modules/cart/store/actions.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/modules/cart/store/actions.ts b/core/modules/cart/store/actions.ts index 147af113c9..241328484d 100644 --- a/core/modules/cart/store/actions.ts +++ b/core/modules/cart/store/actions.ts @@ -709,6 +709,10 @@ const actions: ActionTree = { const product = await dispatch('product/single', { options: actionOtions, assignDefaultVariant: true, setCurrentProduct: false, selectDefaultVariant: false }, { root: true }) + if (!product) { + return null + } + return { product: product, serverItem: serverItem } } catch (err) { return null From 9edaf96832df45ded08dc6291e067a3bf70c6236 Mon Sep 17 00:00:00 2001 From: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Date: Mon, 30 Sep 2019 09:38:37 +0200 Subject: [PATCH 05/47] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5312d3e05..39c9365c19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,10 @@ 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/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.10.4] - 2019.09.27 +## [1.10.4] - UNRELEASED ### Fixed -- Added try/catch for fetching single product in cart synchronization - @gibkigonzo (#) +- Added try/catch for fetching single product in cart synchronization - @gibkigonzo (#3632) ## [1.10.3] - 2019.09.18 From d7d11412aa03c6fe5e9f9dd40956dd35ebf8dfd4 Mon Sep 17 00:00:00 2001 From: andrzejewsky Date: Fri, 4 Oct 2019 20:42:34 +0200 Subject: [PATCH 06/47] backport bugfixes --- CHANGELOG.md | 4 +++ core/app.ts | 2 +- core/lib/multistore.ts | 10 +++---- core/lib/search/adapter/api/searchAdapter.ts | 2 +- .../user/components/UserShippingDetails.ts | 26 +++++++------------ 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39c9365c19..0d86d5ea8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Added try/catch for fetching single product in cart synchronization - @gibkigonzo (#3632) +- Removed infinite loop when changing checkbox in shipping details - @gibkigonzo (#3656) +- Remove modifying config by reference in multistore - @gibkigonzo (#3617) +- Fix displaying same country twice in the in the country switcher - @andrzejewsky (#3587) +- Remove race condition while loading locale messages - @gibkigonzo (#3602) ## [1.10.3] - 2019.09.18 diff --git a/core/app.ts b/core/app.ts index d798b656eb..132aa63373 100755 --- a/core/app.ts +++ b/core/app.ts @@ -70,7 +70,7 @@ const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vu store.state.__DEMO_MODE__ = (config.demomode === true) if (ssrContext) Vue.prototype.$ssrRequestContext = ssrContext if (!store.state.config) store.state.config = globalConfig // @deprecated - we should avoid the `config` - const storeView = prepareStoreView(storeCode) // prepare the default storeView + const storeView = await prepareStoreView(storeCode) // prepare the default storeView store.state.storeView = storeView // to depreciate in near future diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 7ccf27fb10..ae1bb5c191 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -49,11 +49,11 @@ export function currentStoreView (): StoreView { return rootStore.state.storeView } -export function prepareStoreView (storeCode: string): StoreView { +export async function prepareStoreView (storeCode: string): StoreView { let storeView = { // current, default store - tax: config.tax, - i18n: config.i18n, - elasticsearch: config.elasticsearch, + tax: Object.assign({}, config.tax), + i18n: Object.assign({}, config.i18n), + elasticsearch: Object.assign({}, config.elasticsearch), storeCode: '', storeId: config.defaultStoreCode && config.defaultStoreCode !== '' ? config.storeViews[config.defaultStoreCode].storeId : 1 } @@ -69,7 +69,7 @@ export function prepareStoreView (storeCode: string): StoreView { } if (storeViewHasChanged) { rootStore.state.storeView = storeView - loadLanguageAsync(storeView.i18n.defaultLocale) + await loadLanguageAsync(storeView.i18n.defaultLocale) } if (storeViewHasChanged || Vue.prototype.$db.currentStoreCode !== storeCode) { if (typeof Vue.prototype.$db === 'undefined') { diff --git a/core/lib/search/adapter/api/searchAdapter.ts b/core/lib/search/adapter/api/searchAdapter.ts index 9dd8c7845e..1d4c346997 100644 --- a/core/lib/search/adapter/api/searchAdapter.ts +++ b/core/lib/search/adapter/api/searchAdapter.ts @@ -38,7 +38,7 @@ export class SearchAdapter { ElasticsearchQueryBody['groupToken'] = Request.groupToken } - const storeView = (Request.store === null) ? currentStoreView() : prepareStoreView(Request.store) + const storeView = (Request.store === null) ? currentStoreView() : await prepareStoreView(Request.store) Request.index = storeView.elasticsearch.index diff --git a/core/modules/user/components/UserShippingDetails.ts b/core/modules/user/components/UserShippingDetails.ts index 271fc4f735..020c9fd054 100644 --- a/core/modules/user/components/UserShippingDetails.ts +++ b/core/modules/user/components/UserShippingDetails.ts @@ -130,23 +130,17 @@ export const UserShippingDetails = { } }, fillCompanyAddress () { - this.useCompanyAddress = !this.useCompanyAddress if (this.useCompanyAddress) { - let index - for (let i = 0; i < this.currentUser.addresses.length; i++) { - if (toString(this.currentUser.addresses[i].id) === toString(this.currentUser.default_billing)) { - index = i - } - } - if (index >= 0) { - this.shippingDetails.firstName = this.currentUser.addresses[index].firstname - this.shippingDetails.lastName = this.currentUser.addresses[index].lastname - this.shippingDetails.street = this.currentUser.addresses[index].street[0] - this.shippingDetails.house = this.currentUser.addresses[index].street[1] - this.shippingDetails.city = this.currentUser.addresses[index].city - this.shippingDetails.postcode = this.currentUser.addresses[index].postcode - this.shippingDetails.region = this.currentUser.addresses[index].region.region ? this.currentUser.addresses[index].region.region : '' - this.shippingDetails.country = this.currentUser.addresses[index].country_id + const companyAddress = this.currentUser.addresses.find((address) => toString(address.id) === toString(this.currentUser.default_billing)) + if (companyAddress) { + this.shippingDetails.firstName = companyAddress.firstname + this.shippingDetails.lastName = companyAddress.lastname + this.shippingDetails.street = companyAddress.street[0] + this.shippingDetails.house = companyAddress.street[1] + this.shippingDetails.city = companyAddress.city + this.shippingDetails.postcode = companyAddress.postcode + this.shippingDetails.region = companyAddress.region.region ? companyAddress.region.region : '' + this.shippingDetails.country = companyAddress.country_id } } else { this.shippingDetails = this.getShippingDetails() From 68ae8e90c3cf829727f38fa07313c753e2d86462 Mon Sep 17 00:00:00 2001 From: andrzejewsky Date: Fri, 4 Oct 2019 20:51:00 +0200 Subject: [PATCH 07/47] fix types --- 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 ae1bb5c191..147d1a8bdf 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -49,7 +49,7 @@ export function currentStoreView (): StoreView { return rootStore.state.storeView } -export async function prepareStoreView (storeCode: string): StoreView { +export async function prepareStoreView (storeCode: string): Promise { let storeView = { // current, default store tax: Object.assign({}, config.tax), i18n: Object.assign({}, config.i18n), From 71d142a629c966b0a5db2ca64ca209f90b8e6d23 Mon Sep 17 00:00:00 2001 From: andrzejewsky Date: Fri, 4 Oct 2019 21:05:26 +0200 Subject: [PATCH 08/47] bugfixes --- CHANGELOG.md | 3 +++ core/helpers/index.ts | 5 +++++ core/lib/search/adapter/graphql/searchAdapter.ts | 4 ++-- core/modules/cart/store/actions.ts | 2 +- core/modules/catalog/helpers/tax.ts | 8 +++++++- core/modules/url/router/beforeEach.ts | 8 +++++++- 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d86d5ea8f..6993b95c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove modifying config by reference in multistore - @gibkigonzo (#3617) - Fix displaying same country twice in the in the country switcher - @andrzejewsky (#3587) - Remove race condition while loading locale messages - @gibkigonzo (#3602) +- Fixed special price that can break when you change pages (browser navigation for/back) or just go from category to product page - @resubaka (#3638) +- Change sku to string when checking products equality - @gibkigonzo (#3606) +- Fixed problem with losing browser history - @andrzejewsky (#3642) ## [1.10.3] - 2019.09.18 diff --git a/core/helpers/index.ts b/core/helpers/index.ts index 249e4f4915..6ba0ae6663 100644 --- a/core/helpers/index.ts +++ b/core/helpers/index.ts @@ -165,8 +165,13 @@ export const onlineHelper = Vue.observable({ isOnline: isServer || navigator.onLine }) +export const routerHelper = Vue.observable({ + popStateDetected: false +}) + !isServer && window.addEventListener('online', () => { onlineHelper.isOnline = true }) !isServer && window.addEventListener('offline', () => { onlineHelper.isOnline = false }) +!isServer && window.addEventListener('popstate', () => { routerHelper.popStateDetected = true }) export const processURLAddress = (url: string = '') => { if (url.startsWith('/')) return `${config.api.url}${url}` diff --git a/core/lib/search/adapter/graphql/searchAdapter.ts b/core/lib/search/adapter/graphql/searchAdapter.ts index 00e0e31eda..7524b4c7f4 100644 --- a/core/lib/search/adapter/graphql/searchAdapter.ts +++ b/core/lib/search/adapter/graphql/searchAdapter.ts @@ -17,7 +17,7 @@ export class SearchAdapter { * @param {Request} Request request object * @return {Promise} */ - public search (Request) { + public async search (Request) { if (!(Request.searchQuery instanceof SearchQuery)) { throw new Error('SearchQuery instance has wrong class required to process with graphQl request.') } @@ -26,7 +26,7 @@ export class SearchAdapter { throw new Error('No entity type registered for ' + Request.type) } - const storeView = (Request.store === null) ? currentStoreView() : prepareStoreView(Request.store) + const storeView = (Request.store === null) ? currentStoreView() : await prepareStoreView(Request.store) if (storeView.storeCode === undefined || storeView.storeCode == null || !Request.type) { throw new Error('Store and SearchRequest.type are required arguments for executing Graphql query') } diff --git a/core/modules/cart/store/actions.ts b/core/modules/cart/store/actions.ts index 241328484d..b0b63c15c7 100644 --- a/core/modules/cart/store/actions.ts +++ b/core/modules/cart/store/actions.ts @@ -617,7 +617,7 @@ const actions: ActionTree = { for (const clientItem of clientItems) { cartHasItems = true const serverItem = serverItems.find((itm) => { - return itm.sku === clientItem.sku || itm.sku.indexOf(clientItem.sku + '-') === 0 /* bundle products */ + return String(itm.sku) === String(clientItem.sku) || itm.sku.indexOf(clientItem.sku + '-') === 0 /* bundle products */ }) if (!serverItem) { diff --git a/core/modules/catalog/helpers/tax.ts b/core/modules/catalog/helpers/tax.ts index 1416339ba0..91d8688ba0 100644 --- a/core/modules/catalog/helpers/tax.ts +++ b/core/modules/catalog/helpers/tax.ts @@ -32,6 +32,12 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) product.priceTax = priceExclTax * rateFactor product.priceInclTax = priceExclTax + product.priceTax + if (!product.original_price) { + product.original_price = priceExclTax + product.original_price_incl_tax = product.price_incl_tax + product.original_price_tax = product.price_tax + } + let specialPriceExclTax = product.special_price if (sourcePriceInclTax) { specialPriceExclTax = product.special_price / (1 + rateFactor) @@ -41,7 +47,7 @@ export function updateProductPrices (product, rate, sourcePriceInclTax = false) product.specialPriceTax = specialPriceExclTax * rateFactor product.specialPriceInclTax = specialPriceExclTax + product.specialPriceTax - if (product.special_price && (product.special_price < product.price)) { + if (product.special_price && (product.special_price < product.original_price)) { if (!isSpecialPriceActive(product.special_from_date, product.special_to_date)) { product.special_price = 0 // out of the dates period } else { diff --git a/core/modules/url/router/beforeEach.ts b/core/modules/url/router/beforeEach.ts index 0d79ce3eea..8f5f94c5b7 100644 --- a/core/modules/url/router/beforeEach.ts +++ b/core/modules/url/router/beforeEach.ts @@ -9,6 +9,7 @@ import { isServer } from '@vue-storefront/core/helpers' import { currentStoreView, LocalizedRoute, localizedRoute } from '@vue-storefront/core/lib/multistore' import Vue from 'vue' import { RouterManager } from '@vue-storefront/core/lib/router-manager' +import { routerHelper } from '@vue-storefront/core/helpers' export const UrlDispatchMapper = async (to) => { const routeData = await store.dispatch('url/mapUrl', { url: to.fullPath, query: to.query }) @@ -31,7 +32,10 @@ export async function beforeEach (to: Route, from: Route, next) { if (routeData) { let dynamicRoutes: LocalizedRoute[] = processDynamicRoute(routeData, fullPath, !isPreviouslyDispatchedDynamicRoute) if (dynamicRoutes && dynamicRoutes.length > 0) { - next(dynamicRoutes[0]) + next({ + ...dynamicRoutes[0], + replace: routerHelper.popStateDetected || dynamicRoutes[0].fullPath === from.fullPath + }) } else { Logger.error('Route not found ' + routeData['name'], 'dispatcher')() next(localizedRoute('/page-not-found', currentStoreView().storeCode)) @@ -56,4 +60,6 @@ export async function beforeEach (to: Route, from: Route, next) { next() RouterManager.unlockRoute() } + + routerHelper.popStateDetected = false } From 217704e1273a71b01baee9f944c3f9cb2cc969d5 Mon Sep 17 00:00:00 2001 From: andrzejewsky Date: Fri, 4 Oct 2019 21:36:11 +0200 Subject: [PATCH 09/47] bugfixes --- CHANGELOG.md | 2 + core/client-entry.ts | 3 +- core/lib/multistore.ts | 79 +------------------ core/lib/storeCodeFromRoute.ts | 49 ++++++++++++ core/lib/types.ts | 36 +++++++++ core/modules/url/helpers/index.ts | 3 +- core/modules/url/router/beforeEach.ts | 7 +- core/modules/url/store/actions.ts | 4 +- core/modules/url/types/UrlState.ts | 2 +- core/server-entry.ts | 2 +- .../core/blocks/Wishlist/Product.vue | 5 ++ 11 files changed, 106 insertions(+), 86 deletions(-) create mode 100644 core/lib/storeCodeFromRoute.ts create mode 100644 core/lib/types.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 6993b95c31..5a07ff3ecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed special price that can break when you change pages (browser navigation for/back) or just go from category to product page - @resubaka (#3638) - Change sku to string when checking products equality - @gibkigonzo (#3606) - Fixed problem with losing browser history - @andrzejewsky (#3642) +- Fixed resolving store code on SSR - @andrzejewsky (#3576) +- Fixed styles for original price on Wishlist sidebar - @przspa (#3392) ## [1.10.3] - 2019.09.18 diff --git a/core/client-entry.ts b/core/client-entry.ts index 4b82d68338..38f242ab50 100755 --- a/core/client-entry.ts +++ b/core/client-entry.ts @@ -5,7 +5,8 @@ import { createApp } from '@vue-storefront/core/app' import rootStore from '@vue-storefront/core/store' import { registerSyncTaskProcessor } from '@vue-storefront/core/lib/sync/task' import i18n from '@vue-storefront/i18n' -import { prepareStoreView, storeCodeFromRoute, currentStoreView, localizedRoute } from '@vue-storefront/core/lib/multistore' +import storeCodeFromRoute from '@vue-storefront/core/lib/storeCodeFromRoute' +import { prepareStoreView, currentStoreView, localizedRoute } from '@vue-storefront/core/lib/multistore' import { onNetworkStatusChange } from '@vue-storefront/core/modules/offline-order/helpers/onNetworkStatusChange' import '@vue-storefront/core/service-worker/registration' // register the service worker import { AsyncDataLoader } from './lib/async-data-loader' diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 147d1a8bdf..2af874ea93 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -6,43 +6,8 @@ import queryString from 'query-string' import { RouterManager } from '@vue-storefront/core/lib/router-manager' import VueRouter, { RouteConfig, RawLocation } from 'vue-router' import config from 'config' - -export interface LocalizedRoute { - path?: string, - name?: string, - hash?: string, - params?: object, - fullPath?: string, - host?: string -} - -export interface StoreView { - storeCode: string, - disabled?: boolean, - storeId: any, - name?: string, - url?: string, - elasticsearch: { - host: string, - index: string - }, - tax: { - sourcePriceIncludesTax: boolean, - defaultCountry: string, - defaultRegion: null | string, - calculateServerSide: boolean - }, - i18n: { - fullCountryName: string, - fullLanguageName: string, - defaultLanguage: string, - defaultCountry: string, - defaultLocale: string, - currencyCode: string, - currencySign: string, - dateFormat: string - } -} +import { LocalizedRoute, StoreView } from './types' +import storeCodeFromRoute from './storeCodeFromRoute' export function currentStoreView (): StoreView { // TODO: Change to getter all along our code @@ -81,46 +46,6 @@ export async function prepareStoreView (storeCode: string): Promise { return storeView } -export function storeCodeFromRoute (matchedRouteOrUrl: LocalizedRoute | RawLocation | string): string { - if (matchedRouteOrUrl) { - for (let storeCode of config.storeViews.mapStoreUrlsFor) { - const store = config.storeViews[storeCode] - - // handle resolving by path - const matchingPath = typeof matchedRouteOrUrl === 'object' ? matchedRouteOrUrl.path : matchedRouteOrUrl - let normalizedPath = matchingPath // assume that matching string is a path - if (matchingPath.length > 0 && matchingPath[0] !== '/') { - normalizedPath = '/' + matchingPath - } - - if (normalizedPath.startsWith(`${store.url}/`) || normalizedPath === store.url) { - return storeCode - } - - // handle resolving by domain+path - let url = '' - - if (typeof matchedRouteOrUrl === 'object') { - if (matchedRouteOrUrl['host']) { - url = matchedRouteOrUrl['host'] + normalizedPath - } else { - return '' // this route does not have url so there is nothing to do here - } - } else { - url = matchedRouteOrUrl as string - } - - if (url.startsWith(`${store.url}/`) || url === store.url) { - return storeCode - } - } - - return '' - } else { - return '' - } -} - export function removeStoreCodeFromRoute (matchedRouteOrUrl: LocalizedRoute | string): LocalizedRoute | string { const storeCodeInRoute = storeCodeFromRoute(matchedRouteOrUrl) if (storeCodeInRoute !== '') { diff --git a/core/lib/storeCodeFromRoute.ts b/core/lib/storeCodeFromRoute.ts new file mode 100644 index 0000000000..57b9567141 --- /dev/null +++ b/core/lib/storeCodeFromRoute.ts @@ -0,0 +1,49 @@ +import { RawLocation } from 'vue-router' +import config from 'config' +import { LocalizedRoute } from './types' + +const getNormalizedPath = (matchedRouteOrUrl) => { + const matchingPath = matchedRouteOrUrl && (matchedRouteOrUrl.path || matchedRouteOrUrl) + + return matchingPath && (matchingPath.length > 0 && matchingPath[0] !== '/') ? `/${matchingPath}` : matchingPath +} + +const getUrl = (matchedRouteOrUrl) => { + const normalizedPath = getNormalizedPath(matchedRouteOrUrl) + + if (matchedRouteOrUrl && typeof matchedRouteOrUrl === 'object') { + if (matchedRouteOrUrl['host']) { + return matchedRouteOrUrl['host'] + normalizedPath + } + + return '' + } + + return matchedRouteOrUrl +} + +const isMatchingByPath = (matchedRouteOrUrl, store) => { + const normalizedPath = getNormalizedPath(matchedRouteOrUrl) + return normalizedPath.startsWith(`${store.url}/`) || normalizedPath === store.url +} + +const isMatchingByDomainAndPath = (matchedRouteOrUrl, store) => { + const url = getUrl(matchedRouteOrUrl) + return url.startsWith(`${store.url}/`) || url === store.url +} + +const storeCodeFromRoute = (matchedRouteOrUrl: LocalizedRoute | RawLocation | string): string => { + if (!matchedRouteOrUrl) return '' + + for (let storeCode of config.storeViews.mapStoreUrlsFor) { + const store = config.storeViews[storeCode] + + if (isMatchingByPath(matchedRouteOrUrl, store) || isMatchingByDomainAndPath(matchedRouteOrUrl, store)) { + return storeCode + } + } + + return '' +} + +export default storeCodeFromRoute diff --git a/core/lib/types.ts b/core/lib/types.ts new file mode 100644 index 0000000000..bf0e52b6c5 --- /dev/null +++ b/core/lib/types.ts @@ -0,0 +1,36 @@ +export interface LocalizedRoute { + path?: string, + name?: string, + hash?: string, + params?: object, + fullPath?: string, + host?: string +} + +export interface StoreView { + storeCode: string, + disabled?: boolean, + storeId: any, + name?: string, + url?: string, + elasticsearch: { + host: string, + index: string + }, + tax: { + sourcePriceIncludesTax: boolean, + defaultCountry: string, + defaultRegion: null | string, + calculateServerSide: boolean + }, + i18n: { + fullCountryName: string, + fullLanguageName: string, + defaultLanguage: string, + defaultCountry: string, + defaultLocale: string, + currencyCode: string, + currencySign: string, + dateFormat: string + } +} diff --git a/core/modules/url/helpers/index.ts b/core/modules/url/helpers/index.ts index 9029ee7a8f..115d3e06fe 100644 --- a/core/modules/url/helpers/index.ts +++ b/core/modules/url/helpers/index.ts @@ -1,6 +1,7 @@ import { router } from '@vue-storefront/core/app' import config from 'config' -import { localizedDispatcherRoute, localizedRoute, LocalizedRoute, currentStoreView } from '@vue-storefront/core/lib/multistore' +import { LocalizedRoute } from '@vue-storefront/core/lib/types' +import { localizedDispatcherRoute, localizedRoute, currentStoreView } from '@vue-storefront/core/lib/multistore' import { RouteConfig } from 'vue-router/types/router'; import { RouterManager } from '@vue-storefront/core/lib/router-manager' diff --git a/core/modules/url/router/beforeEach.ts b/core/modules/url/router/beforeEach.ts index 8f5f94c5b7..7bb45a1afd 100644 --- a/core/modules/url/router/beforeEach.ts +++ b/core/modules/url/router/beforeEach.ts @@ -6,7 +6,8 @@ import store from '@vue-storefront/core/store' import { Logger } from '@vue-storefront/core/lib/logger' import { processDynamicRoute, normalizeUrlPath } from '../helpers' import { isServer } from '@vue-storefront/core/helpers' -import { currentStoreView, LocalizedRoute, localizedRoute } from '@vue-storefront/core/lib/multistore' +import { currentStoreView, localizedRoute } from '@vue-storefront/core/lib/multistore' +import { LocalizedRoute } from '@vue-storefront/core/lib/types' import Vue from 'vue' import { RouterManager } from '@vue-storefront/core/lib/router-manager' import { routerHelper } from '@vue-storefront/core/helpers' @@ -54,12 +55,12 @@ export async function beforeEach (to: Route, from: Route, next) { // ps. we can't use the next() call here as it's not doing the real redirect in SSR mode (just processing different component without changing the URL and that causes the CSR / SSR DOM mismatch while hydrating) } }).finally(() => { + routerHelper.popStateDetected = false RouterManager.unlockRoute() }) } else { next() RouterManager.unlockRoute() + routerHelper.popStateDetected = false } - - routerHelper.popStateDetected = false } diff --git a/core/modules/url/store/actions.ts b/core/modules/url/store/actions.ts index ccafbc2a10..db37dfe8a7 100644 --- a/core/modules/url/store/actions.ts +++ b/core/modules/url/store/actions.ts @@ -6,8 +6,8 @@ import { cacheStorage } from '../' import queryString from 'query-string' import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' import { processMultipleDynamicRoutes, normalizeUrlPath, parametrizeRouteData } from '../helpers' -import { storeCodeFromRoute, removeStoreCodeFromRoute } from '@vue-storefront/core/lib/multistore' -import config from 'config' +import { removeStoreCodeFromRoute } from '@vue-storefront/core/lib/multistore' +import storeCodeFromRoute from '@vue-storefront/core/lib/storeCodeFromRoute' // it's a good practice for all actions to return Promises with effect of their execution export const actions: ActionTree = { diff --git a/core/modules/url/types/UrlState.ts b/core/modules/url/types/UrlState.ts index 7fed8b4469..fba3babff0 100644 --- a/core/modules/url/types/UrlState.ts +++ b/core/modules/url/types/UrlState.ts @@ -1,4 +1,4 @@ -import { LocalizedRoute } from 'core/lib/multistore'; +import { LocalizedRoute } from '@vue-storefront/core/lib/types' // 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) diff --git a/core/server-entry.ts b/core/server-entry.ts index b555876d52..2569e88a7a 100755 --- a/core/server-entry.ts +++ b/core/server-entry.ts @@ -2,7 +2,7 @@ import union from 'lodash-es/union' import { createApp } from '@vue-storefront/core/app' import { HttpError } from '@vue-storefront/core/helpers/exceptions' -import { storeCodeFromRoute } from '@vue-storefront/core/lib/multistore' +import storeCodeFromRoute from '@vue-storefront/core/lib/storeCodeFromRoute' import omit from 'lodash-es/omit' import pick from 'lodash-es/pick' import buildTimeConfig from 'config' diff --git a/src/themes/default/components/core/blocks/Wishlist/Product.vue b/src/themes/default/components/core/blocks/Wishlist/Product.vue index 9a71ef317b..11fe9f325e 100644 --- a/src/themes/default/components/core/blocks/Wishlist/Product.vue +++ b/src/themes/default/components/core/blocks/Wishlist/Product.vue @@ -75,4 +75,9 @@ input { .image{ flex: 0 0 121px; } +.price-original { + text-decoration: line-through; + color: #828282; + font-size: .95rem; +} From 4563368f00b5f4b641a4ee19ae0af1f6e00b382f Mon Sep 17 00:00:00 2001 From: andrzejewsky Date: Fri, 4 Oct 2019 21:52:35 +0200 Subject: [PATCH 10/47] bugfixes --- CHANGELOG.md | 1 + core/compatibility/components/blocks/Microcart/Product.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a07ff3ecb..d2510c373e 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 problem with losing browser history - @andrzejewsky (#3642) - Fixed resolving store code on SSR - @andrzejewsky (#3576) - Fixed styles for original price on Wishlist sidebar - @przspa (#3392) +- Added debounce for updating quantity method in the cart - @andrzejewsky (#3191) ## [1.10.3] - 2019.09.18 diff --git a/core/compatibility/components/blocks/Microcart/Product.js b/core/compatibility/components/blocks/Microcart/Product.js index 9a0fa8c4f9..a4d239ef73 100644 --- a/core/compatibility/components/blocks/Microcart/Product.js +++ b/core/compatibility/components/blocks/Microcart/Product.js @@ -1,5 +1,6 @@ import { MicrocartProduct } from '@vue-storefront/core/modules/cart/components/Product.ts' import i18n from '@vue-storefront/i18n' +import debounce from 'lodash-es/debounce' import config from 'config' export default { @@ -12,11 +13,13 @@ export default { // deprecated, will be moved to theme or removed in the near future #1742 this.$bus.$on('cart-after-itemchanged', this.onProductChanged) this.$bus.$on('notification-after-itemremoved', this.onProductRemoved) + this.updateQuantity = debounce(this.updateQuantity, 5000) }, beforeDestroy () { // deprecated, will be moved to theme or removed in the near future #1742 this.$bus.$off('cart-after-itemchanged', this.onProductChanged) this.$bus.$off('notification-after-itemremoved', this.onProductRemoved) + this.updateQuantity.cancel() }, methods: { removeItem () { From c604f7a8b9e2048432a1e8b2218fa395e46dcded Mon Sep 17 00:00:00 2001 From: andrzejewsky Date: Fri, 4 Oct 2019 22:12:07 +0200 Subject: [PATCH 11/47] fix tests --- core/lib/test/unit/multistore.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/test/unit/multistore.spec.ts b/core/lib/test/unit/multistore.spec.ts index e819bf3a62..0ddf62be10 100644 --- a/core/lib/test/unit/multistore.spec.ts +++ b/core/lib/test/unit/multistore.spec.ts @@ -1,4 +1,4 @@ -import { storeCodeFromRoute } from '../../multistore' +import storeCodeFromRoute from '../../storeCodeFromRoute' import config from 'config' jest.mock('../../../store', () => ({})) jest.mock('@vue-storefront/i18n', () => ({loadLanguageAsync: jest.fn()})) From eb6a701db94eaf9b9697caa37005649574108b6f Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 7 Oct 2019 11:31:02 +0200 Subject: [PATCH 12/47] backport pr 3552 --- CHANGELOG.md | 1 + core/i18n/resource/i18n/jp-JP.csv | 1 - .../default/components/core/CookieNotification.vue | 4 +++- src/themes/default/components/core/OfflineBadge.vue | 11 ++++++++--- src/themes/default/resource/i18n/ar-SY.csv | 2 +- src/themes/default/resource/i18n/cs-CZ.csv | 2 +- src/themes/default/resource/i18n/de-DE.csv | 2 +- src/themes/default/resource/i18n/en-US.csv | 2 +- src/themes/default/resource/i18n/es-ES.csv | 2 +- src/themes/default/resource/i18n/fr-FR.csv | 2 +- src/themes/default/resource/i18n/it-IT.csv | 2 +- src/themes/default/resource/i18n/jp-JP.csv | 2 +- src/themes/default/resource/i18n/nl-NL.csv | 2 +- src/themes/default/resource/i18n/pl-PL.csv | 2 +- src/themes/default/resource/i18n/pt-BR.csv | 2 +- src/themes/default/resource/i18n/ru-RU.csv | 2 +- src/themes/default/resource/i18n/zh-cn.csv | 2 +- 17 files changed, 25 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2510c373e..abaff4ab6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed resolving store code on SSR - @andrzejewsky (#3576) - Fixed styles for original price on Wishlist sidebar - @przspa (#3392) - Added debounce for updating quantity method in the cart - @andrzejewsky (#3191) +- Improved cookie and offline badges (z-index, overflow) - @phoenixdev-kl (#3552) ## [1.10.3] - 2019.09.18 diff --git a/core/i18n/resource/i18n/jp-JP.csv b/core/i18n/resource/i18n/jp-JP.csv index 40a4617656..dcf151cf58 100644 --- a/core/i18n/resource/i18n/jp-JP.csv +++ b/core/i18n/resource/i18n/jp-JP.csv @@ -154,7 +154,6 @@ "We will send you the invoice to given e-mail address","頂いたメールアドレスに請求書を送ります" "Wishlist","お気に入りリスト" "You are offline","オフラインです" -"You are offline, some of the functionalities are limited","現在オフラインですので、使えない機能があります" "You can also use","またこれらを使うことができます" "You can log to your account using e-mail and password defined earlier. On your account you can edit your profile data, check history of transactions, edit subscription to newsletter.","登録されたメールアドレスとパスワードを使ってログインできます。アカウント内ではプロフィールの編集注文の履歴の確認ニュースレターへの購読が行えます。" "You have been successfully subscribed to our newsletter!","ニュースレターへの購読が完了しました!" diff --git a/src/themes/default/components/core/CookieNotification.vue b/src/themes/default/components/core/CookieNotification.vue index 93686a9cfd..fb254b7008 100644 --- a/src/themes/default/components/core/CookieNotification.vue +++ b/src/themes/default/components/core/CookieNotification.vue @@ -74,13 +74,15 @@ export default { diff --git a/src/themes/default/resource/i18n/ar-SY.csv b/src/themes/default/resource/i18n/ar-SY.csv index ab6f719805..7f356f8649 100644 --- a/src/themes/default/resource/i18n/ar-SY.csv +++ b/src/themes/default/resource/i18n/ar-SY.csv @@ -130,7 +130,7 @@ "search","البحث" "to find product you were looking for.","لإيجاد المنتج الذي تبحث عنه." "See our bestsellers","مشاهدة الأكثر مبيعاً" -"You are offline, some of the functionalities are limited","أنت غير متّصل بالإنترنت، بعض وظائف الموقع محدودة" +"You are offline. Some features might not be available.","أنت غير متّصل بالإنترنت، بعض وظائف الموقع محدودة" "Search","البحث" "Help","المساعدة" "Go to Facebook","اذهب إلى فيس بوك" diff --git a/src/themes/default/resource/i18n/cs-CZ.csv b/src/themes/default/resource/i18n/cs-CZ.csv index 807fba0683..3e88eafe02 100644 --- a/src/themes/default/resource/i18n/cs-CZ.csv +++ b/src/themes/default/resource/i18n/cs-CZ.csv @@ -130,7 +130,7 @@ "search","vyhledávání" "to find product you were looking for.","pro nalezení produktů, které hledáte." "See our bestsellers","Podívejte se na naše bestsellery" -"You are offline, some of the functionalities are limited","Jste offline, některé funkce jsou tudíž omezeny" +"You are offline. Some features might not be available.","Jste offline, některé funkce jsou tudíž omezeny" "Search","Hledat" "Help","Pomoc" "Go to Facebook","Přejít na Facebook" diff --git a/src/themes/default/resource/i18n/de-DE.csv b/src/themes/default/resource/i18n/de-DE.csv index 4d49997bfb..f05ec353e9 100644 --- a/src/themes/default/resource/i18n/de-DE.csv +++ b/src/themes/default/resource/i18n/de-DE.csv @@ -135,7 +135,7 @@ "search","die Suche" "to find product you were looking for.","benutzen um das gesuchte Produkt zu finden." "See our bestsellers","Sehen Sie sich unsere Bestseller an" -"You are offline, some of the functionalities are limited","Sie sind offline. Einige Funktionen sind daher nur eingeschränkt nutzbar" +"You are offline. Some features might not be available.","Sie sind offline. Einige Funktionen sind daher nur eingeschränkt nutzbar" "Search","Suche" "Help","Hilfe" "Go to Facebook","Zu Facebook gehen" diff --git a/src/themes/default/resource/i18n/en-US.csv b/src/themes/default/resource/i18n/en-US.csv index 20daa4bed9..4e9639137b 100644 --- a/src/themes/default/resource/i18n/en-US.csv +++ b/src/themes/default/resource/i18n/en-US.csv @@ -138,7 +138,7 @@ "search","search" "to find product you were looking for.","to find product you were looking for." "See our bestsellers","See our bestsellers" -"You are offline, some of the functionalities are limited","You are offline, some of the functionalities are limited" +"You are offline. Some features might not be available.","You are offline. Some features might not be available." "Search","Search" "Help","Help" "Go to Facebook","Go to Facebook" diff --git a/src/themes/default/resource/i18n/es-ES.csv b/src/themes/default/resource/i18n/es-ES.csv index 824ce00e6b..0bac763300 100644 --- a/src/themes/default/resource/i18n/es-ES.csv +++ b/src/themes/default/resource/i18n/es-ES.csv @@ -129,7 +129,7 @@ "search","buscar" "to find product you were looking for.","para encontrar el producto que estabas buscando." "See our bestsellers","Vea nuestros bestsellers" -"You are offline, some of the functionalities are limited","Estás fuera de línea, algunas de las funcionalidades son limitadas" +"You are offline. Some features might not be available.","Estás fuera de línea, algunas de las funcionalidades son limitadas" "Search","Buscar" "Help","Ayuda" "Go to Facebook","Ir a Facebook" diff --git a/src/themes/default/resource/i18n/fr-FR.csv b/src/themes/default/resource/i18n/fr-FR.csv index 848a44b25e..278c9733d6 100644 --- a/src/themes/default/resource/i18n/fr-FR.csv +++ b/src/themes/default/resource/i18n/fr-FR.csv @@ -130,7 +130,7 @@ "search","la recherche" "to find product you were looking for.","pour trouver le produit que vous cherchiez." "See our bestsellers","Voir nos meilleures ventes" -"You are offline, some of the functionalities are limited","Vous êtes hors ligne, certaines fonctionnalités sont limitées" +"You are offline. Some features might not be available.","Vous êtes hors ligne, certaines fonctionnalités sont limitées" "Search","Recherche" "Help","Aide" "Go to Facebook","Aller sur Facebook" diff --git a/src/themes/default/resource/i18n/it-IT.csv b/src/themes/default/resource/i18n/it-IT.csv index cfa6bdab50..d06c6b3eba 100644 --- a/src/themes/default/resource/i18n/it-IT.csv +++ b/src/themes/default/resource/i18n/it-IT.csv @@ -130,7 +130,7 @@ "search","cerca" "to find product you were looking for.","per trovare il prodotto che cerchi." "See our bestsellers","Visualizza i prodotti più venduti" -"You are offline, some of the functionalities are limited","Non sei connesso ad internet, alcune funzionalità potrebbero essere limitate" +"You are offline. Some features might not be available.","Non sei connesso ad internet, alcune funzionalità potrebbero essere limitate" "Search","Cerca" "Help","Aiuto" "Go to Facebook","Vai su Facebook" diff --git a/src/themes/default/resource/i18n/jp-JP.csv b/src/themes/default/resource/i18n/jp-JP.csv index 58974fb590..01f4940bc9 100644 --- a/src/themes/default/resource/i18n/jp-JP.csv +++ b/src/themes/default/resource/i18n/jp-JP.csv @@ -129,7 +129,7 @@ "search","検索" "to find product you were looking for.","から欲しい商品を見つける" "See our bestsellers","ベストセラーを見る" -"You are offline, some of the functionalities are limited","オフラインです、使えない機能があります" +"You are offline. Some features might not be available.","オフラインです、使えない機能があります" "Search","検索" "Help","ヘルプ" "Go to Facebook","Facebookへ行く" diff --git a/src/themes/default/resource/i18n/nl-NL.csv b/src/themes/default/resource/i18n/nl-NL.csv index 7bf72a76b3..9ba5e33d12 100644 --- a/src/themes/default/resource/i18n/nl-NL.csv +++ b/src/themes/default/resource/i18n/nl-NL.csv @@ -129,7 +129,7 @@ You can also use,U kunt ook de search,zoekfunctie to find product you were looking for.,gebruiken om een product te vinden. See our bestsellers,Bekijk onze bestsellers -"You are offline, some of the functionalities are limited","U bent momenteel offline, niet alle onderdelen van de shop zullen volledig werken" +"You are offline. Some features might not be available.","U bent momenteel offline, niet alle onderdelen van de shop zullen volledig werken" Search,Zoeken Help,Hulp Go to Facebook,Ga naar Facebook diff --git a/src/themes/default/resource/i18n/pl-PL.csv b/src/themes/default/resource/i18n/pl-PL.csv index b5fea211e8..a0b4aa4074 100644 --- a/src/themes/default/resource/i18n/pl-PL.csv +++ b/src/themes/default/resource/i18n/pl-PL.csv @@ -130,7 +130,7 @@ "search","szukaj" "to find product you were looking for.","aby znaleźć produkt, który szukasz." "See our bestsellers","Zobacz bestsellery" -"You are offline, some of the functionalities are limited","Jesteś offline, niektóre funkcje są ograniczone" +"You are offline. Some features might not be available.","Jesteś offline, niektóre funkcje są ograniczone" "Search","Szukaj" "Help","Pomoc" "Go to Facebook","Przejdź do Facebook" diff --git a/src/themes/default/resource/i18n/pt-BR.csv b/src/themes/default/resource/i18n/pt-BR.csv index f33248ccc7..33b1c883fc 100644 --- a/src/themes/default/resource/i18n/pt-BR.csv +++ b/src/themes/default/resource/i18n/pt-BR.csv @@ -129,7 +129,7 @@ "search","a busca" "to find product you were looking for.","para achar o produto que você está procurando." "See our bestsellers","Ver os mais vendidos" -"You are offline, some of the functionalities are limited","Você está sem Internet, algumas funcionalidades estão limitadas" +"You are offline. Some features might not be available.","Você está sem Internet, algumas funcionalidades estão limitadas" "Search","Busca" "Help","Ajuda" "Go to Facebook","Ir para Facebook" diff --git a/src/themes/default/resource/i18n/ru-RU.csv b/src/themes/default/resource/i18n/ru-RU.csv index b9a219ab39..c38eee9414 100644 --- a/src/themes/default/resource/i18n/ru-RU.csv +++ b/src/themes/default/resource/i18n/ru-RU.csv @@ -129,7 +129,7 @@ "search","поиском" "to find product you were looking for.","чтобы найти искомый Вами товар." "See our bestsellers","Посмотрите наши бестселлеры" -"You are offline, some of the functionalities are limited","Отсутствует соединение с интернетом, некоторые возможности будут ограничены" +"You are offline. Some features might not be available.","Отсутствует соединение с интернетом, некоторые возможности будут ограничены" "Search","Поиск" "Help","Помощь" "Go to Facebook","Перейти в Facebook" diff --git a/src/themes/default/resource/i18n/zh-cn.csv b/src/themes/default/resource/i18n/zh-cn.csv index 1bb73b8d50..12d7a5f92c 100644 --- a/src/themes/default/resource/i18n/zh-cn.csv +++ b/src/themes/default/resource/i18n/zh-cn.csv @@ -134,7 +134,7 @@ "search","搜索" "to find product you were looking for.","找到你想要的产品." "See our bestsellers","查看我们的畅销书" -"You are offline, some of the functionalities are limited","您处于离线状态,部分功能有限" +"You are offline. Some features might not be available.","您处于离线状态,部分功能有限" "Search","搜索" "Help","帮助" "Go to Facebook","Go to Facebook" From ddeeb8746b990e24f192dedcba06e218993305ad Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 7 Oct 2019 11:50:34 +0200 Subject: [PATCH 13/47] backport pr 3551 --- CHANGELOG.md | 1 + .../components/core/blocks/SearchPanel/SearchPanel.gql.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index abaff4ab6e..6bc503ac28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed resolving store code on SSR - @andrzejewsky (#3576) - Fixed styles for original price on Wishlist sidebar - @przspa (#3392) - Added debounce for updating quantity method in the cart - @andrzejewsky (#3191) +- Improved scrolling in Safari on iOS devices (sidebars) - @phoenixdev-kl (#3551) - Improved cookie and offline badges (z-index, overflow) - @phoenixdev-kl (#3552) ## [1.10.3] - 2019.09.18 diff --git a/src/themes/default/components/core/blocks/SearchPanel/SearchPanel.gql.vue b/src/themes/default/components/core/blocks/SearchPanel/SearchPanel.gql.vue index e662a39aca..3bdfb4335d 100644 --- a/src/themes/default/components/core/blocks/SearchPanel/SearchPanel.gql.vue +++ b/src/themes/default/components/core/blocks/SearchPanel/SearchPanel.gql.vue @@ -67,6 +67,7 @@ export default { transition: transform 300ms $motion-main; overflow-y: auto; overflow-x: hidden; + -webkit-overflow-scrolling: touch; &.active { transform: translateX(0); From 8b851f8f452171178c9b00176a0e7d56e667e3c1 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 7 Oct 2019 12:01:36 +0200 Subject: [PATCH 14/47] backport pr 3289 --- CHANGELOG.md | 1 + config/default.json | 5 +++++ core/scripts/server.js | 12 ++++++++++-- package.json | 1 + yarn.lock | 5 +++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bc503ac28..a3197658b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added debounce for updating quantity method in the cart - @andrzejewsky (#3191) - Improved scrolling in Safari on iOS devices (sidebars) - @phoenixdev-kl (#3551) - Improved cookie and offline badges (z-index, overflow) - @phoenixdev-kl (#3552) +- Added config to set Cache-Control header for static assets based on mime type - @phoenix-bjoern (#3268) ## [1.10.3] - 2019.09.18 diff --git a/config/default.json b/config/default.json index a88d04003a..fa13463da6 100644 --- a/config/default.json +++ b/config/default.json @@ -409,6 +409,11 @@ "fullLanguageName": "English", "bundleAllStoreviewLanguages": true }, + "expireHeaders": { + "default": "30d", + "application/json": "24h", + "image/png": "7d" + }, "newsletter": { "endpoint": "/api/ext/mailchimp-subscribe/subscribe" }, diff --git a/core/scripts/server.js b/core/scripts/server.js index 670d2c7c3b..b29a59a85d 100755 --- a/core/scripts/server.js +++ b/core/scripts/server.js @@ -1,6 +1,7 @@ const fs = require('fs') const path = require('path') const express = require('express') +const ms = require('ms') const compile = require('lodash.template') const rootPath = require('app-root-path').path const resolve = file => path.resolve(rootPath, file) @@ -104,8 +105,15 @@ function invalidateCache (req, res) { } const serve = (path, cache, options) => express.static(resolve(path), Object.assign({ - maxAge: cache && isProd ? 2592000000 : 0, // 1 month in milliseconds = 1000 * 60 * 60 * 24 * 30 = 2592000000 - fallthrough: false + fallthrough: false, + setHeaders: cache && isProd ? function (res, path) { + const mimeType = express.static.mime.lookup(path); + let maxAge = config.expireHeaders.default; + if (config.expireHeaders.hasOwnProperty(mimeType)) { + maxAge = config.expireHeaders.get(mimeType); + } + res.setHeader('Cache-Control', 'public, max-age=' + ms(maxAge)); + } : null }, options)) const themeRoot = require('../build/theme-path') diff --git a/package.json b/package.json index 1231098778..1717827f64 100755 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "js-sha3": "^0.8.0", "localforage": "^1.7.2", "magento2-rest-client": "github:DivanteLtd/magento2-rest-client", + "ms": "^2.1.2", "pm2": "^2.10.4", "redis-tag-cache": "^1.2.1", "reflect-metadata": "^0.1.12", diff --git a/yarn.lock b/yarn.lock index 733eeb0c3c..e17ff6d2e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9380,6 +9380,11 @@ ms@^2.0.0, ms@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" +ms@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + multimatch@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" From 9d0adabdf38102c4c63a622843ffce2dc591b86a Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 7 Oct 2019 12:04:44 +0200 Subject: [PATCH 15/47] backport pr 3223 --- CHANGELOG.md | 1 + core/lib/search/adapter/api/searchAdapter.ts | 6 +++++- core/lib/search/adapter/graphql/searchAdapter.ts | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3197658b6..92053ced73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved scrolling in Safari on iOS devices (sidebars) - @phoenixdev-kl (#3551) - Improved cookie and offline badges (z-index, overflow) - @phoenixdev-kl (#3552) - Added config to set Cache-Control header for static assets based on mime type - @phoenix-bjoern (#3268) +- Added catching of errors when ES is down - @qiqqq ## [1.10.3] - 2019.09.18 diff --git a/core/lib/search/adapter/api/searchAdapter.ts b/core/lib/search/adapter/api/searchAdapter.ts index 1d4c346997..556c6f6603 100644 --- a/core/lib/search/adapter/api/searchAdapter.ts +++ b/core/lib/search/adapter/api/searchAdapter.ts @@ -79,7 +79,11 @@ export class SearchAdapter { 'Content-Type': 'application/json' }, body: config.elasticsearch.queryMethod === 'POST' ? JSON.stringify(ElasticsearchQueryBody) : null - }).then(resp => { return resp.json() }) + }) + .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 7524b4c7f4..382abfa1f7 100644 --- a/core/lib/search/adapter/graphql/searchAdapter.ts +++ b/core/lib/search/adapter/graphql/searchAdapter.ts @@ -60,6 +60,9 @@ export class SearchAdapter { .then(resp => { return resp.json() }) + .catch(error => { + throw new Error('FetchError in request to ES: ' + error.toString()) + }) } /** From 0e084415da16ecda5654f926f3aeee94c34ebab5 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 7 Oct 2019 14:28:26 +0200 Subject: [PATCH 16/47] backport pr 3548, 3516 --- CHANGELOG.md | 3 ++ core/lib/multistore.ts | 33 +++++++++++++------ core/lib/router-manager.ts | 4 +-- core/lib/types.ts | 1 + core/modules/url/helpers/index.ts | 18 +++++----- core/modules/url/router/beforeEach.ts | 10 +++--- .../blocks/Inspirations/InspirationTile.vue | 2 +- 7 files changed, 44 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92053ced73..8d64579316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved cookie and offline badges (z-index, overflow) - @phoenixdev-kl (#3552) - Added config to set Cache-Control header for static assets based on mime type - @phoenix-bjoern (#3268) - Added catching of errors when ES is down - @qiqqq +- `localizedRoute()` doesn't return urlDispatcher routes anymore. Use localizedDispatcherRoute instead - @lukeromanowicz (#3548) +- Fixed hash in dynamically resolved urls causing resolving issues - @lukeromanowicz (#3515) +- `localizedRoute()` now supports path (and prefers over fullPath) in LocalizedRoute objects - @lukeromanowicz (#3515) ## [1.10.3] - 2019.09.18 diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 2af874ea93..6c019ffcc8 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -66,22 +66,29 @@ export function adjustMultistoreApiUrl (url: string): string { } export function localizedDispatcherRoute (routeObj: LocalizedRoute | string, storeCode: string): LocalizedRoute | string { - if (!storeCode) { - storeCode = currentStoreView().storeCode + const { storeCode: currentStoreCode, appendStoreCode } = currentStoreView() + if (!storeCode || !config.storeViews[storeCode]) { + storeCode = currentStoreCode } - const appendStoreCodePrefix = config.storeViews[storeCode] ? config.storeViews[storeCode].appendStoreCode : false + const appendStoreCodePrefix = storeCode && appendStoreCode if (typeof routeObj === 'string') { if (routeObj[0] !== '/') routeObj = `/${routeObj}` return appendStoreCodePrefix ? `/${storeCode}${routeObj}` : routeObj } - if (routeObj && routeObj.fullPath) { // case of using dispatcher - const routeCodePrefix = config.defaultStoreCode !== storeCode && appendStoreCodePrefix ? `/${storeCode}` : '' - const qrStr = queryString.stringify(routeObj.params) + if (routeObj) { + if ((routeObj as LocalizedRoute).fullPath && !(routeObj as LocalizedRoute).path) { // support both path and fullPath + routeObj['path'] = (routeObj as LocalizedRoute).fullPath + } + + if (routeObj.path) { // case of using dispatcher + const routeCodePrefix = appendStoreCodePrefix ? `/${storeCode}` : '' + const qrStr = queryString.stringify(routeObj.params); - const normalizedPath = routeObj.fullPath[0] !== '/' ? `/${routeObj.fullPath}` : routeObj.fullPath - return `${routeCodePrefix}${normalizedPath}${qrStr ? `?${qrStr}` : ''}` + const normalizedPath = routeObj.path[0] !== '/' ? `/${routeObj.path}` : routeObj.path + return `${routeCodePrefix}${normalizedPath}${qrStr ? `?${qrStr}` : ''}` + } } return routeObj @@ -91,8 +98,14 @@ export function localizedRoute (routeObj: LocalizedRoute | string | RouteConfig if (!storeCode) { storeCode = currentStoreView().storeCode } - if (routeObj && (routeObj as LocalizedRoute).fullPath && config.seo.useUrlDispatcher) { - return localizedDispatcherRoute(Object.assign({}, routeObj, { params: null }) as LocalizedRoute, storeCode) + if (!routeObj) { + return routeObj + } + + if ((typeof routeObj === 'object') && (routeObj as LocalizedRoute)) { + if ((routeObj as LocalizedRoute).fullPath && !(routeObj as LocalizedRoute).path) { // support both path and fullPath + routeObj['path'] = (routeObj as LocalizedRoute).fullPath + } } if (storeCode && routeObj && config.defaultStoreCode !== storeCode && config.storeViews[storeCode].appendStoreCode) { diff --git a/core/lib/router-manager.ts b/core/lib/router-manager.ts index eaf4a19322..87795f6b5c 100644 --- a/core/lib/router-manager.ts +++ b/core/lib/router-manager.ts @@ -23,8 +23,8 @@ const RouterManager = { findByName: function (name: string): RouteConfig { return this._registeredRoutes.find(r => r.name === name) }, - findByPath: function (fullPath: string): RouteConfig { - return this._registeredRoutes.find(r => r.fullPath === fullPath) + findByPath: function (path: string): RouteConfig { + return this._registeredRoutes.find(r => r.path === path) }, lockRoute: function () { let resolver diff --git a/core/lib/types.ts b/core/lib/types.ts index bf0e52b6c5..0f76fadfea 100644 --- a/core/lib/types.ts +++ b/core/lib/types.ts @@ -13,6 +13,7 @@ export interface StoreView { storeId: any, name?: string, url?: string, + appendStoreCode?: boolean, elasticsearch: { host: string, index: string diff --git a/core/modules/url/helpers/index.ts b/core/modules/url/helpers/index.ts index 115d3e06fe..be799affe6 100644 --- a/core/modules/url/helpers/index.ts +++ b/core/modules/url/helpers/index.ts @@ -14,20 +14,20 @@ export function parametrizeRouteData (routeData: LocalizedRoute, query: { [id: s return parametrizedRoute } -function prepareDynamicRoutes (routeData: LocalizedRoute, fullPath: string): RouteConfig[] { +function prepareDynamicRoutes (routeData: LocalizedRoute, path: string): RouteConfig[] { const userRoute = RouterManager.findByName(routeData.name) if (userRoute) { const currentStoreCode = currentStoreView().storeCode - const dynamicRouteName = (config.defaultStoreCode !== currentStoreCode) ? `urldispatcher-${fullPath}-${currentStoreCode}` : `urldispatcher-${fullPath}` - const dynamicRoute = Object.assign({}, userRoute, routeData, { path: '/' + fullPath, name: dynamicRouteName }) + const dynamicRouteName = (config.defaultStoreCode !== currentStoreCode) ? `urldispatcher-${path}-${currentStoreCode}` : `urldispatcher-${path}` + const dynamicRoute = Object.assign({}, userRoute, routeData, { path: '/' + path, name: dynamicRouteName }) return [dynamicRoute] } else { return [] } } -export function processDynamicRoute (routeData: LocalizedRoute, fullPath: string, addToRoutes: boolean = true): LocalizedRoute[] { - const preparedRoutes = prepareDynamicRoutes(routeData, fullPath) +export function processDynamicRoute (routeData: LocalizedRoute, path: string, addToRoutes: boolean = true): LocalizedRoute[] { + const preparedRoutes = prepareDynamicRoutes(routeData, path) if (addToRoutes && preparedRoutes) { RouterManager.addRoutes(preparedRoutes, router) } @@ -45,8 +45,8 @@ export function processMultipleDynamicRoutes (dispatcherMap: {}, addToRoutes: bo return preparedRoutes } -export function findRouteByPath (fullPath: string): RouteConfig { - return RouterManager.findByPath(fullPath) +export function findRouteByPath (path: string): RouteConfig { + return RouterManager.findByPath(path) } export function normalizeUrlPath (url: string): string { @@ -78,11 +78,11 @@ export function formatProductLink ( let routeData: LocalizedRoute; if (product.configurable_children && product.configurable_children.length > 0) { routeData = { - fullPath: product.url_path, + path: product.url_path, params: { childSku: product.sku } } } else { - routeData = { fullPath: product.url_path } + routeData = { path: product.url_path } } return localizedDispatcherRoute(routeData, storeCode) } else { diff --git a/core/modules/url/router/beforeEach.ts b/core/modules/url/router/beforeEach.ts index 7bb45a1afd..a2704be1e5 100644 --- a/core/modules/url/router/beforeEach.ts +++ b/core/modules/url/router/beforeEach.ts @@ -13,7 +13,7 @@ import { RouterManager } from '@vue-storefront/core/lib/router-manager' import { routerHelper } from '@vue-storefront/core/helpers' export const UrlDispatchMapper = async (to) => { - const routeData = await store.dispatch('url/mapUrl', { url: to.fullPath, query: to.query }) + const routeData = await store.dispatch('url/mapUrl', { url: to.path, query: to.query }) return Object.assign({}, to, routeData) } @@ -25,24 +25,24 @@ export async function beforeEach (to: Route, from: Route, next) { } RouterManager.lockRoute() - const fullPath = normalizeUrlPath(to.fullPath) + const path = normalizeUrlPath(to.path) const hasRouteParams = to.hasOwnProperty('params') && Object.values(to.params).length > 0 const isPreviouslyDispatchedDynamicRoute = to.matched.length > 0 && to.name && to.name.startsWith('urldispatcher') if (!to.matched.length || (isPreviouslyDispatchedDynamicRoute && !hasRouteParams)) { UrlDispatchMapper(to).then((routeData) => { if (routeData) { - let dynamicRoutes: LocalizedRoute[] = processDynamicRoute(routeData, fullPath, !isPreviouslyDispatchedDynamicRoute) + let dynamicRoutes: LocalizedRoute[] = processDynamicRoute(routeData, path, !isPreviouslyDispatchedDynamicRoute) if (dynamicRoutes && dynamicRoutes.length > 0) { next({ ...dynamicRoutes[0], - replace: routerHelper.popStateDetected || dynamicRoutes[0].fullPath === from.fullPath + replace: routerHelper.popStateDetected || dynamicRoutes[0].path === from.path }) } else { Logger.error('Route not found ' + routeData['name'], 'dispatcher')() next(localizedRoute('/page-not-found', currentStoreView().storeCode)) } } else { - Logger.error('No mapping found for ' + fullPath, 'dispatcher')() + Logger.error('No mapping found for ' + path, 'dispatcher')() next(localizedRoute('/page-not-found', currentStoreView().storeCode)) } }).catch(e => { diff --git a/src/themes/default/components/theme/blocks/Inspirations/InspirationTile.vue b/src/themes/default/components/theme/blocks/Inspirations/InspirationTile.vue index cc81402b3d..eda480a67c 100644 --- a/src/themes/default/components/theme/blocks/Inspirations/InspirationTile.vue +++ b/src/themes/default/components/theme/blocks/Inspirations/InspirationTile.vue @@ -1,7 +1,7 @@