From 66e6f0c96bf2ca3ebcd62b4b1ad8c1794d3bbf47 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 29 Oct 2019 12:07:39 +0100 Subject: [PATCH 01/29] change links in promoted_offers --- .../default/resource/banners/de_promoted_offers.json | 8 ++++---- .../default/resource/banners/it_promoted_offers.json | 8 ++++---- src/themes/default/resource/promoted_offers.json | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/themes/default/resource/banners/de_promoted_offers.json b/src/themes/default/resource/banners/de_promoted_offers.json index deb423d5d2..54a9c64068 100644 --- a/src/themes/default/resource/banners/de_promoted_offers.json +++ b/src/themes/default/resource/banners/de_promoted_offers.json @@ -4,7 +4,7 @@ "title": "Büro lässig", "subtitle": "Kollektion", "image": "/assets/ban1.jpg", - "link": "/c/frauen-20" + "link": "/women/frauen-20" } ], "smallBanners": [ @@ -12,13 +12,13 @@ "title": "Sheinen", "subtitle": "Zubehör", "image": "/assets/ban2.jpg", - "link": "/c/herren-11" + "link": "/men/herren-11" }, { "title": "Der Frühling kommt", "subtitle": "Hüte", "image": "/assets/ban3.jpg", - "link": "/c/gerat-3" + "link": "/gear/gerat-3" } ], "productBanners": [ @@ -26,7 +26,7 @@ "title": "Der Frühling kommt", "subtitle": "Hüte", "image": "/assets/ban3.jpg", - "link": "/c/gerat-3" + "link": "/gear/gerat-3" } ] } diff --git a/src/themes/default/resource/banners/it_promoted_offers.json b/src/themes/default/resource/banners/it_promoted_offers.json index 810b93166f..da98c29b5d 100644 --- a/src/themes/default/resource/banners/it_promoted_offers.json +++ b/src/themes/default/resource/banners/it_promoted_offers.json @@ -4,7 +4,7 @@ "title": "Ufficio casual", "subtitle": "Collezione", "image": "/assets/ban1.jpg", - "link": "/c/la-donne-20" + "link": "/women/la-donne-20" } ], "smallBanners": [ @@ -12,13 +12,13 @@ "title": "Brilla", "subtitle": "Accessori", "image": "/assets/ban2.jpg", - "link": "/c/signori-11" + "link": "/men/signori-11" }, { "title": "La primavera sta arrivando", "subtitle": "Cappelli", "image": "/assets/ban3.jpg", - "link": "/c/equipaggiamento-3" + "link": "/gear/equipaggiamento-3" } ], "productBanners": [ @@ -26,7 +26,7 @@ "title": "La primavera sta arrivando", "subtitle": "Cappelli", "image": "/assets/ban3.jpg", - "link": "/c/equipaggiamento-3" + "link": "/gear/equipaggiamento-3" } ] } diff --git a/src/themes/default/resource/promoted_offers.json b/src/themes/default/resource/promoted_offers.json index 1a35bdf134..e6f309df77 100644 --- a/src/themes/default/resource/promoted_offers.json +++ b/src/themes/default/resource/promoted_offers.json @@ -4,7 +4,7 @@ "title": "Office casual", "subtitle": "Collection", "image": "/assets/ban1.jpg", - "link": "/c/women-20" + "link": "/women/women-20" } ], "smallBanners": [ @@ -12,13 +12,13 @@ "title": "Shine on", "subtitle": "Accesories", "image": "/assets/ban2.jpg", - "link": "/c/men-11" + "link": "/men/men-11" }, { "title": "Spring is coming", "subtitle": "Hats", "image": "/assets/ban3.jpg", - "link": "/c/gear-3" + "link": "/gear/gear-3" } ], "productBanners": [ @@ -26,7 +26,7 @@ "title": "Spring is coming", "subtitle": "Hats", "image": "/assets/ban3.jpg", - "link": "/c/gear-3" + "link": "/gear/gear-3" } ] } \ No newline at end of file From 45230adbe461dd208a2091e8fdc526ba62da0558 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 29 Oct 2019 12:17:08 +0100 Subject: [PATCH 02/29] update formatCategoryLink --- core/modules/url/helpers/index.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/core/modules/url/helpers/index.ts b/core/modules/url/helpers/index.ts index be799affe6..782b35a19e 100644 --- a/core/modules/url/helpers/index.ts +++ b/core/modules/url/helpers/index.ts @@ -59,8 +59,17 @@ 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 (category: Category, storeCode: string = currentStoreView().storeCode): string { + storeCode ? storeCode += '/' : storeCode = ''; + + if (currentStoreView().appendStoreCode === false) { + storeCode = '' + } + + if (category) { + return config.seo.useUrlDispatcher ? ('/' + storeCode + category.url_path) : ('/' + storeCode + 'c/' + category.slug) + } + return '/' + storeCode; } export function formatProductLink ( From 4e21f41ffb84970f559d63a027151fec2fec9aa5 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 29 Oct 2019 12:26:34 +0100 Subject: [PATCH 03/29] format category link in menu --- core/modules/url/helpers/index.ts | 2 +- .../components/core/blocks/SidebarMenu/SidebarMenu.vue | 6 +++++- .../components/core/blocks/SidebarMenu/SubCategory.vue | 8 ++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/core/modules/url/helpers/index.ts b/core/modules/url/helpers/index.ts index 782b35a19e..29a940f018 100644 --- a/core/modules/url/helpers/index.ts +++ b/core/modules/url/helpers/index.ts @@ -59,7 +59,7 @@ export function normalizeUrlPath (url: string): string { return url } -export function formatCategoryLink (category: Category, storeCode: string = currentStoreView().storeCode): string { +export function formatCategoryLink (category: { url_path: string, slug: string }, storeCode: string = currentStoreView().storeCode): string { storeCode ? storeCode += '/' : storeCode = ''; if (currentStoreView().appendStoreCode === false) { diff --git a/src/themes/default/components/core/blocks/SidebarMenu/SidebarMenu.vue b/src/themes/default/components/core/blocks/SidebarMenu/SidebarMenu.vue index ab9c699941..e2d6af05f9 100644 --- a/src/themes/default/components/core/blocks/SidebarMenu/SidebarMenu.vue +++ b/src/themes/default/components/core/blocks/SidebarMenu/SidebarMenu.vue @@ -52,7 +52,7 @@ {{ category.name }} @@ -140,6 +140,7 @@ import i18n from '@vue-storefront/i18n' import SidebarMenu from '@vue-storefront/core/compatibility/components/blocks/SidebarMenu/SidebarMenu' 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' export default { components: { @@ -218,6 +219,9 @@ export default { this.$router.push({ name: 'my-account' }) }) } + }, + categoryLink (category) { + return formatCategoryLink(category) } } } diff --git a/src/themes/default/components/core/blocks/SidebarMenu/SubCategory.vue b/src/themes/default/components/core/blocks/SidebarMenu/SubCategory.vue index 6fbe07b960..abd55e8b3f 100644 --- a/src/themes/default/components/core/blocks/SidebarMenu/SubCategory.vue +++ b/src/themes/default/components/core/blocks/SidebarMenu/SubCategory.vue @@ -11,7 +11,7 @@ > {{ $t('View all') }} @@ -35,7 +35,7 @@ {{ link.name }} @@ -84,6 +84,7 @@ import { mapState } from 'vuex' import SubBtn from './SubBtn.vue' import i18n from '@vue-storefront/i18n' import config from 'config' +import { formatCategoryLink } from '@vue-storefront/core/modules/url/helpers' export default { name: 'SubCategory', @@ -154,6 +155,9 @@ export default { action1: { label: i18n.t('OK') } }) } + }, + categoryLink (category) { + return formatCategoryLink(category) } } } From 6d164dc43b4afdf5fd3277068b35fc359ca2bfe1 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 29 Oct 2019 13:26:41 +0100 Subject: [PATCH 04/29] update breadcrumbs component --- .../default/components/core/Breadcrumbs.vue | 42 ++++++++++++++++--- .../core/blocks/Checkout/ThankYouPage.vue | 1 + src/themes/default/pages/Compare.vue | 2 +- src/themes/default/pages/MyAccount.vue | 1 + src/themes/default/pages/Static.vue | 2 +- 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/themes/default/components/core/Breadcrumbs.vue b/src/themes/default/components/core/Breadcrumbs.vue index 0fb73675b5..5761a7f93b 100644 --- a/src/themes/default/components/core/Breadcrumbs.vue +++ b/src/themes/default/components/core/Breadcrumbs.vue @@ -1,20 +1,52 @@ diff --git a/src/themes/default/components/core/blocks/Checkout/ThankYouPage.vue b/src/themes/default/components/core/blocks/Checkout/ThankYouPage.vue index e474309622..1e948053e8 100644 --- a/src/themes/default/components/core/blocks/Checkout/ThankYouPage.vue +++ b/src/themes/default/components/core/blocks/Checkout/ThankYouPage.vue @@ -3,6 +3,7 @@
diff --git a/src/themes/default/pages/Compare.vue b/src/themes/default/pages/Compare.vue index a32b940c68..2fb2619993 100644 --- a/src/themes/default/pages/Compare.vue +++ b/src/themes/default/pages/Compare.vue @@ -2,7 +2,7 @@
- +

{{ title }}

diff --git a/src/themes/default/pages/MyAccount.vue b/src/themes/default/pages/MyAccount.vue index 51483132e5..6dbd763dc2 100644 --- a/src/themes/default/pages/MyAccount.vue +++ b/src/themes/default/pages/MyAccount.vue @@ -3,6 +3,7 @@
diff --git a/src/themes/default/pages/Static.vue b/src/themes/default/pages/Static.vue index d2a1132fbf..280f0e334a 100644 --- a/src/themes/default/pages/Static.vue +++ b/src/themes/default/pages/Static.vue @@ -2,7 +2,7 @@
- +

{{ $props.title }}

From d7c9c3a4ce19796f5a3cb721f68d66cb93fe490e Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 29 Oct 2019 13:30:59 +0100 Subject: [PATCH 05/29] update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c30940fc74..0fc5b880e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ 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.5] - 29.10.2019 + +### Fixed +- Render correct category links when multistore is active - @gibkigonzo (#3753) + ## [1.10.4] - 18.10.2019 ### Fixed From 154ae9073d5ed5845a74b81dfe966c0e552ef709 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 30 Oct 2019 08:11:08 +0100 Subject: [PATCH 06/29] update links in main-image and slider --- CHANGELOG.md | 2 +- src/themes/default/resource/banners/de_main-image.json | 2 +- src/themes/default/resource/banners/it_main-image.json | 2 +- src/themes/default/resource/main-image.json | 2 +- src/themes/default/resource/slider.json | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fc5b880e0..08281f90f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ 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.5] - 29.10.2019 +## [1.10.5] - unreleased ### Fixed - Render correct category links when multistore is active - @gibkigonzo (#3753) diff --git a/src/themes/default/resource/banners/de_main-image.json b/src/themes/default/resource/banners/de_main-image.json index 56d84292cb..79edf26ddd 100644 --- a/src/themes/default/resource/banners/de_main-image.json +++ b/src/themes/default/resource/banners/de_main-image.json @@ -3,6 +3,6 @@ "title": "Laufe den Lauf.", "subtitle": "Eine Mode kann zum vorherrschenden Stil im Verhalten werden oder die neuesten Kreationen von Designern, Technologen, Ingenieuren und Designmanagern manifestieren.", "image": "/assets/full_width_banner.jpg", - "link": "/c/frauen-20" + "link": "/women/frauen-20" } } diff --git a/src/themes/default/resource/banners/it_main-image.json b/src/themes/default/resource/banners/it_main-image.json index 5b6bcc3220..0eb03931c8 100644 --- a/src/themes/default/resource/banners/it_main-image.json +++ b/src/themes/default/resource/banners/it_main-image.json @@ -3,6 +3,6 @@ "title": "Cammina la passeggiata.", "subtitle": "Una moda può diventare lo stile prevalente nel comportamento o manifestare le ultime creazioni di designer, tecnologi, ingegneri e responsabili del design.", "image": "/assets/full_width_banner.jpg", - "link": "/c/la-donne-20" + "link": "/women/la-donne-20" } } diff --git a/src/themes/default/resource/main-image.json b/src/themes/default/resource/main-image.json index 32a57a801c..b156168d9e 100644 --- a/src/themes/default/resource/main-image.json +++ b/src/themes/default/resource/main-image.json @@ -3,6 +3,6 @@ "title": "Walk the walk.", "subtitle": "A fashion can become the prevailing style in behaviour or manifest the newest creations of designers, technologists, engineers, and design managers.", "image": "/assets/full_width_banner.jpg", - "link": "/c/women-20" + "link": "/women/women-20" } } diff --git a/src/themes/default/resource/slider.json b/src/themes/default/resource/slider.json index 5480a908da..45beb6b38a 100644 --- a/src/themes/default/resource/slider.json +++ b/src/themes/default/resource/slider.json @@ -5,21 +5,21 @@ "subtitle": "New collection", "button_text": "Shop now", "image": "/assets/slide_01.jpg", - "link": "/c/women-20" + "link": "/women/women-20" }, { "title": "Luma Fitness", "subtitle": "Collection", "button_text": "Shop now", "image": "/assets/slide_02.jpg", - "link": "/c/men-11" + "link": "/men/men-11" }, { "title": "Luma Fitness", "subtitle": "What's new", "button_text": "Shop now", "image": "/assets/slide_03.jpg", - "link": "/c/training-9" + "link": "/training/training-9" } ], "total": "3" From 8394964c7d0215f12026f1958169350d39c3bce5 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 30 Oct 2019 14:13:51 +0100 Subject: [PATCH 07/29] remove product mutate when assign product --- core/modules/catalog/store/product/actions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts index 535a6e01af..ea43a26209 100644 --- a/core/modules/catalog/store/product/actions.ts +++ b/core/modules/catalog/store/product/actions.ts @@ -307,7 +307,7 @@ const actions: ActionTree = { } if (configuration) { let selectedVariant = configureProductAsync(context, { product: product, configuration: configuration, selectDefaultVariant: false }) - Object.assign(product, omit(selectedVariant, ['visibility'])) + product = Object.assign({}, product, omit(selectedVariant, ['visibility'])) } if (product.url_path) { rootStore.dispatch('url/registerMapping', { @@ -430,7 +430,7 @@ const actions: ActionTree = { // todo: probably a good idea is to change this [0] to specific id const selectedVariant = configureProductAsync(context, { product: prod, configuration: { sku: options.childSku }, selectDefaultVariant: selectDefaultVariant, setProductErorrs: true }) if (selectedVariant && assignDefaultVariant) { - prod = Object.assign(prod, selectedVariant) + prod = Object.assign({}, prod, selectedVariant) } } else if (!skipCache || (prod.type_id === 'simple' || prod.type_id === 'downloadable')) { if (setCurrentProduct) context.dispatch('setCurrent', prod) From bb7feb27f7afcc0bd676e7b6a29dbd50cb7e825c Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 30 Oct 2019 14:27:40 +0100 Subject: [PATCH 08/29] update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c30940fc74..1ee0467df0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ 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.5] - unreleased + +### Fixed +- disable product mutation when assigning product variant - @gibkigonzo (#3735) + ## [1.10.4] - 18.10.2019 ### Fixed From ca1fab8a023656c8c120ebe67a913534e490b185 Mon Sep 17 00:00:00 2001 From: PhoenixDev - YB Date: Tue, 5 Nov 2019 11:16:27 +0200 Subject: [PATCH 09/29] PAT-1721 Issue #3748 apply hot fix for Cannot assign to read only property 'storeCode' --- core/lib/multistore.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 6c019ffcc8..dbf90e9550 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -24,9 +24,13 @@ export async function prepareStoreView (storeCode: string): Promise { } const storeViewHasChanged = !rootStore.state.storeView || rootStore.state.storeView.storeCode !== storeCode if (storeCode) { // current store code - if ((storeView = config.storeViews[storeCode])) { + const currentStoreView = config.storeViews[storeCode] + if (currentStoreView) { + storeView = Object.assign({}, currentStoreView); storeView.storeCode = storeCode rootStore.state.user.current_storecode = storeCode + } else { + console.warn(`Not found 'storeView' matching the given 'storeCode': ${storeCode}`) } } else { storeView.storeCode = config.defaultStoreCode || '' From 9236dddcc430c5c6d5f8c934056c4627383cdbf1 Mon Sep 17 00:00:00 2001 From: PhoenixDev - YB Date: Tue, 5 Nov 2019 11:23:50 +0200 Subject: [PATCH 10/29] PAT-1721 Issue #3748 add changelogs --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ee0467df0..670d1fb9a2 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 - disable product mutation when assigning product variant - @gibkigonzo (#3735) +- fix issue with Cannot assign to read only property 'storeCode' - @yuriboyko (#3748) ## [1.10.4] - 18.10.2019 From 92132f74be6f93560fdd92934127acc5cbcca60b Mon Sep 17 00:00:00 2001 From: Kamil Date: Wed, 6 Nov 2019 21:22:01 +0100 Subject: [PATCH 11/29] 3785 sorting fixed --- config/default.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/default.json b/config/default.json index 4cfa44ac8c..8be8043abf 100644 --- a/config/default.json +++ b/config/default.json @@ -289,7 +289,7 @@ "order": "desc" }, "sortByAttributes": { - "Latest": "updated_at", + "Latest": "updated_at:desc", "Price: Low to high":"final_price", "Price: High to low":"final_price:desc" }, From 2b22315b4bab0c0f84062cc8ca8f08ca1949a39f Mon Sep 17 00:00:00 2001 From: Kamil Date: Wed, 6 Nov 2019 21:35:30 +0100 Subject: [PATCH 12/29] changelog updated --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c30940fc74..d99c406890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `localizedRoute()` now supports path (and prefers over fullPath) in LocalizedRoute objects - @lukeromanowicz (#3515) - 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) - @pkarw (#2985) - Fixed evaluate detailsLink in the cookie notification - @benjick (#3689) +- Sorting fixed on category page - @AdKamil (#3785) ## Added - Added german translations - @schwerdt-ke (3076) From ced5c86fb06c5457d981b45523ab5e779d55d9c8 Mon Sep 17 00:00:00 2001 From: Kamil Date: Wed, 6 Nov 2019 22:50:59 +0100 Subject: [PATCH 13/29] 3778 fixed null in search input - ternary operator --- CHANGELOG.md | 1 + core/modules/catalog/components/Search.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c30940fc74..ced198ff6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `localizedRoute()` now supports path (and prefers over fullPath) in LocalizedRoute objects - @lukeromanowicz (#3515) - 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) - @pkarw (#2985) - Fixed evaluate detailsLink in the cookie notification - @benjick (#3689) +- Fixed null value of search input - @AdKamil (#3778) ## Added - Added german translations - @schwerdt-ke (3076) diff --git a/core/modules/catalog/components/Search.ts b/core/modules/catalog/components/Search.ts index c4c010582b..fb3a1ae9d1 100644 --- a/core/modules/catalog/components/Search.ts +++ b/core/modules/catalog/components/Search.ts @@ -26,7 +26,7 @@ export const Search = { } }, beforeDestroy () { - localStorage.setItem(`shop/user/searchQuery`, this.search); + localStorage.setItem(`shop/user/searchQuery`, this.search ? this.search : ''); }, methods: { onEscapePress () { From d9528a0373cb5693481e1b34715b0f19b2cfd308 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 19 Nov 2019 12:26:09 +0100 Subject: [PATCH 14/29] mount app in beforeResolve, after all components are resolved --- core/client-entry.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/core/client-entry.ts b/core/client-entry.ts index 38f242ab50..77ec96204c 100755 --- a/core/client-entry.ts +++ b/core/client-entry.ts @@ -64,6 +64,10 @@ const invokeClientEntry = async () => { } router.onReady(async () => { router.beforeResolve((to, from, next) => { + // Mounting app + if (!(app as any)._isMounted) { + app.$mount('#app') + } if (!from.name) return next() // do not resolve asyncData on server render - already been done if (Vue.prototype.$ssrRequestContext) Vue.prototype.$ssrRequestContext.output.cacheTags = new Set() const matched = router.getMatchedComponents(to) @@ -99,14 +103,6 @@ const invokeClientEntry = async () => { } })) }) - // Mounting app - if (!RouterManager.isRouteDispatched()) { - RouterManager.addDispatchCallback(() => { - app.$mount('#app') - }) - } else { - app.$mount('#app') - } }) registerSyncTaskProcessor() window.addEventListener('online', () => { onNetworkStatusChange(store) }) From d5f39439baa72b2400e2cbd05df969f58de26f0d Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 19 Nov 2019 14:07:09 +0100 Subject: [PATCH 15/29] if route is already resolved then we can mount app --- core/client-entry.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/client-entry.ts b/core/client-entry.ts index 77ec96204c..7e6d771fde 100755 --- a/core/client-entry.ts +++ b/core/client-entry.ts @@ -103,6 +103,10 @@ const invokeClientEntry = async () => { } })) }) + // route is already resolved so 'beforeResolve' will not be triggered + if (RouterManager.isRouteDispatched()) { + app.$mount('#app') + } }) registerSyncTaskProcessor() window.addEventListener('online', () => { onNetworkStatusChange(store) }) From b8d9d38e9e8044bac8dc9755089433c7a15d9be3 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 19 Nov 2019 14:14:37 +0100 Subject: [PATCH 16/29] update changelog --- CHANGELOG.md | 1 + core/lib/search/adapter/api/searchAdapter.ts | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8abade3c6a..ba5e3659c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Disable product mutation when assigning product variant - @gibkigonzo (#3735) - Fixed null value of search input - @AdKamil (#3778) - Sorting fixed on category page - @AdKamil (#3785) +- Mount app in 'beforeResolve' if it's not dispatched in 'onReady' - @gibkigonzo (#3669) ## [1.10.4] - 18.10.2019 diff --git a/core/lib/search/adapter/api/searchAdapter.ts b/core/lib/search/adapter/api/searchAdapter.ts index 556c6f6603..b40e8fb204 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 { From f410757796ee9e26ca2d53b0203e715c709b6940 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 20 Nov 2019 07:29:09 +0100 Subject: [PATCH 17/29] check if router history is pending --- core/client-entry.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/client-entry.ts b/core/client-entry.ts index 7e6d771fde..57848ab7d9 100755 --- a/core/client-entry.ts +++ b/core/client-entry.ts @@ -103,8 +103,9 @@ const invokeClientEntry = async () => { } })) }) - // route is already resolved so 'beforeResolve' will not be triggered - if (RouterManager.isRouteDispatched()) { + // if route is dispatched and there is no pending in router history + // if there is stil pending then 'beforeResolve' will handle app mount, otherwise 'beforeResolve' will not trigger + if (RouterManager.isRouteDispatched() && !(router as any).history.pending) { app.$mount('#app') } }) From a20bc88bdf60634f4e9293de8dc68a69d1d8ac27 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 20 Nov 2019 09:12:08 +0100 Subject: [PATCH 18/29] update code readability --- core/client-entry.ts | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/core/client-entry.ts b/core/client-entry.ts index 57848ab7d9..72437fc3d7 100755 --- a/core/client-entry.ts +++ b/core/client-entry.ts @@ -63,12 +63,22 @@ const invokeClientEntry = async () => { }) } router.onReady(async () => { + // check if app can be mounted + const canBeMounted = () => RouterManager.isRouteDispatched() && // route is dispatched + !(router as any).history.pending && // there is no pending in router history + !(app as any)._isMounted // it's not mounted before + + if (canBeMounted()) { + app.$mount('#app') + } router.beforeResolve((to, from, next) => { - // Mounting app - if (!(app as any)._isMounted) { - app.$mount('#app') + if (!from.name) { + next() + if (canBeMounted()) { + app.$mount('#app') + } + return // do not resolve asyncData on server render - already been done } - if (!from.name) return next() // do not resolve asyncData on server render - already been done if (Vue.prototype.$ssrRequestContext) Vue.prototype.$ssrRequestContext.output.cacheTags = new Set() const matched = router.getMatchedComponents(to) if (to) { // this is from url @@ -103,11 +113,6 @@ const invokeClientEntry = async () => { } })) }) - // if route is dispatched and there is no pending in router history - // if there is stil pending then 'beforeResolve' will handle app mount, otherwise 'beforeResolve' will not trigger - if (RouterManager.isRouteDispatched() && !(router as any).history.pending) { - app.$mount('#app') - } }) registerSyncTaskProcessor() window.addEventListener('online', () => { onNetworkStatusChange(store) }) From ce137e4986df42e557c89490eaef45a2ef3f6ddc Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 21 Nov 2019 07:30:59 +0100 Subject: [PATCH 19/29] backport fix for memory leak in category page --- core/app.ts | 15 ++++-- core/client-entry.ts | 2 +- core/filters/price.js | 4 +- .../modules/catalog/store/category/actions.ts | 4 +- core/modules/catalog/store/product/actions.ts | 4 +- core/modules/catalog/store/product/getters.ts | 13 ++++- core/modules/catalog/store/product/index.ts | 4 ++ .../catalog/store/product/mutations.ts | 13 +++-- core/pages/Category.js | 6 +-- core/scripts/server.js | 13 ++++- core/server-entry.ts | 1 - core/store/lib/storage.ts | 54 ++++++++++++++----- 12 files changed, 97 insertions(+), 36 deletions(-) diff --git a/core/app.ts b/core/app.ts index 132aa63373..052a0d9290 100755 --- a/core/app.ts +++ b/core/app.ts @@ -68,7 +68,12 @@ const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vu store.state.version = process.env.APPVERSION store.state.config = config // @deprecated store.state.__DEMO_MODE__ = (config.demomode === true) - if (ssrContext) Vue.prototype.$ssrRequestContext = ssrContext + if (ssrContext) { + // @deprecated - we shouldn't share server context between requests + Vue.prototype.$ssrRequestContext = {output: {cacheTags: ssrContext.output.cacheTags}} + + Vue.prototype.$cacheTags = ssrContext.output.cacheTags + } if (!store.state.config) store.state.config = globalConfig // @deprecated - we should avoid the `config` const storeView = await prepareStoreView(storeCode) // prepare the default storeView store.state.storeView = storeView @@ -87,6 +92,10 @@ const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vu Object.keys(coreMixins).forEach(key => { Vue.mixin(coreMixins[key]) }) + + Object.keys(coreFilters).forEach(key => { + Vue.filter(key, coreFilters[key]) + }) }) // @todo remove this part when we'll get rid of global multistore mixin @@ -99,10 +108,6 @@ const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vu }) } - Object.keys(coreFilters).forEach(key => { - Vue.filter(key, coreFilters[key]) - }) - let vueOptions = { router, store, diff --git a/core/client-entry.ts b/core/client-entry.ts index 38f242ab50..dbe32e5f3d 100755 --- a/core/client-entry.ts +++ b/core/client-entry.ts @@ -65,7 +65,7 @@ const invokeClientEntry = async () => { router.onReady(async () => { router.beforeResolve((to, from, next) => { if (!from.name) return next() // do not resolve asyncData on server render - already been done - if (Vue.prototype.$ssrRequestContext) Vue.prototype.$ssrRequestContext.output.cacheTags = new Set() + if (!Vue.prototype.$cacheTags) Vue.prototype.$cacheTags = new Set() const matched = router.getMatchedComponents(to) if (to) { // this is from url if (globalConfig.storeViews.multistore === true) { diff --git a/core/filters/price.js b/core/filters/price.js index e229b83807..a9e44c7cba 100644 --- a/core/filters/price.js +++ b/core/filters/price.js @@ -10,7 +10,9 @@ export function price (value) { } let formattedVal = Math.abs(parseFloat(value)).toFixed(2) const storeView = currentStoreView() - + if (!storeView.i18n) { + return value; + } const prependCurrency = (price) => { return storeView.i18n.currencySign + price } diff --git a/core/modules/catalog/store/category/actions.ts b/core/modules/catalog/store/category/actions.ts index 48c0286ece..2ee25c3a7e 100644 --- a/core/modules/catalog/store/category/actions.ts +++ b/core/modules/catalog/store/category/actions.ts @@ -138,8 +138,8 @@ const actions: ActionTree = { if (setCurrentCategory) { commit(types.CATEGORY_UPD_CURRENT_CATEGORY, mainCategory) } - if (populateRequestCacheTags && mainCategory && Vue.prototype.$ssrRequestContext) { - Vue.prototype.$ssrRequestContext.output.cacheTags.add(`C${mainCategory.id}`) + if (populateRequestCacheTags && mainCategory && Vue.prototype.$cacheTags) { + Vue.prototype.$cacheTags.add(`C${mainCategory.id}`) } if (setCurrentCategoryPath) { let currentPath = [] diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts index ea43a26209..6b6eb6c228 100644 --- a/core/modules/catalog/store/product/actions.ts +++ b/core/modules/catalog/store/product/actions.ts @@ -294,8 +294,8 @@ const actions: ActionTree = { 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}`) + if (populateRequestCacheTags && Vue.prototype.$cacheTags) { + Vue.prototype.$cacheTags.add(`P${product.id}`); } product.errors = {} // this is an object to store validation result for custom options and others product.info = {} diff --git a/core/modules/catalog/store/product/getters.ts b/core/modules/catalog/store/product/getters.ts index 6455e7b3de..449968a62e 100644 --- a/core/modules/catalog/store/product/getters.ts +++ b/core/modules/catalog/store/product/getters.ts @@ -1,6 +1,16 @@ +import { PagedProductList } from './../../types/ProductState'; +import { nonReactiveState } from './index'; import { GetterTree } from 'vuex' import RootState from '@vue-storefront/core/types/RootState' import ProductState from '../../types/ProductState' +import cloneDeep from 'lodash-es/cloneDeep' + +function mapCategoryProducts (productsSkus, productsData) { + return productsSkus.map(prodSku => { + const product = productsData.find(prodData => prodData.sku === prodSku) + return cloneDeep(product) + }) +} const getters: GetterTree = { productParent: (state) => state.parent, @@ -9,7 +19,8 @@ const getters: GetterTree = { productOriginal: (state) => state.original, currentOptions: (state) => state.current_options, breadcrumbs: (state) => state.breadcrumbs, - productGallery: (state) => state.productGallery + productGallery: (state) => state.productGallery, + list: (state) => mapCategoryProducts((state.list as PagedProductList).items, nonReactiveState.list) } export default getters diff --git a/core/modules/catalog/store/product/index.ts b/core/modules/catalog/store/product/index.ts index f59e2cbe94..81b1dfc5b5 100644 --- a/core/modules/catalog/store/product/index.ts +++ b/core/modules/catalog/store/product/index.ts @@ -34,3 +34,7 @@ export const productModule: Module = { actions, mutations } + +export const nonReactiveState = { + list: [] +} diff --git a/core/modules/catalog/store/product/mutations.ts b/core/modules/catalog/store/product/mutations.ts index ccef6d5e99..c27af487fc 100644 --- a/core/modules/catalog/store/product/mutations.ts +++ b/core/modules/catalog/store/product/mutations.ts @@ -1,7 +1,9 @@ +import { nonReactiveState } from './index'; import Vue from 'vue' import { MutationTree } from 'vuex' import * as types from './mutation-types' import ProductState, { PagedProductList } from '../../types/ProductState' +import cloneDeep from 'lodash-es/cloneDeep' const mutations: MutationTree = { [types.CATALOG_SET_BREADCRUMBS] (state, payload) { @@ -29,11 +31,14 @@ const mutations: MutationTree = { }, [types.CATALOG_UPD_PRODUCTS] (state, { products, append }) { if (append === false) { - state.list = products + nonReactiveState.list = cloneDeep(products.items) + state.list = cloneDeep({...products, items: products.items.map(prod => prod.sku)}) } else { - (state.list as PagedProductList).start = products.start as number - (state.list as PagedProductList).perPage = products.perPage as number - (state.list as PagedProductList).items = (state.list as PagedProductList).items.concat(products.items) + const pagedProductList = state.list as PagedProductList + pagedProductList.start = products.start as number + pagedProductList.perPage = products.perPage as number + nonReactiveState.list = cloneDeep(nonReactiveState.list.concat(products.items)) + pagedProductList.items = cloneDeep(pagedProductList.items.concat(products.items.map(prod => prod.sku))) } }, [types.CATALOG_SET_PRODUCT_CURRENT] (state, product) { diff --git a/core/pages/Category.js b/core/pages/Category.js index 7d01c57e46..bed87e0c16 100644 --- a/core/pages/Category.js +++ b/core/pages/Category.js @@ -29,10 +29,10 @@ export default { computed: { ...mapGetters('category', ['getCurrentCategory', 'getCurrentCategoryProductQuery', 'getAllCategoryFilters', 'getCategoryBreadcrumbs', 'getCurrentCategoryPath']), products () { - return this.$store.state.product.list.items + return this.$store.getters['product/list'] }, productsCounter () { - return this.$store.state.product.list.items ? this.$store.state.product.list.items.length : 0 + return this.products ? this.products.length : 0 }, productsTotal () { return this.$store.state.product.list.total @@ -41,7 +41,7 @@ export default { return this.getCurrentCategoryProductQuery }, isCategoryEmpty () { - return (!(this.$store.state.product.list.items) || this.$store.state.product.list.items.length === 0) + return (!(this.products) || this.products.length === 0) }, category () { return this.getCurrentCategory diff --git a/core/scripts/server.js b/core/scripts/server.js index b29a59a85d..49f17d32bf 100755 --- a/core/scripts/server.js +++ b/core/scripts/server.js @@ -62,6 +62,12 @@ if (isProd) { }) } +function clearSSRContext (context) { + Object.keys(context.server).forEach(key => delete context.server[key]) + delete context.output['cacheTags'] + delete context['meta'] +} + function invalidateCache (req, res) { if (config.server.useOutputCache) { if (req.query.tag && req.query.key) { // clear cache pages for specific query tag @@ -171,7 +177,7 @@ app.get('*', (req, res, next) => { append: (context) => { return '' }, appendHead: (context) => { return '' }, template: 'default', - cacheTags: null + cacheTags: new Set() }, server: { app: app, @@ -189,7 +195,7 @@ app.get('*', (req, res, next) => { res.setHeader('Content-Type', 'text/html') } let tagsArray = [] - if (config.server.useOutputCacheTagging && context.output.cacheTags !== null) { + if (config.server.useOutputCacheTagging && context.output.cacheTags && context.output.cacheTags.size > 0) { tagsArray = Array.from(context.output.cacheTags) const cacheTags = tagsArray.join(' ') res.setHeader('X-VS-Cache-Tags', cacheTags) @@ -218,6 +224,9 @@ app.get('*', (req, res, next) => { console.log(`whole request [${req.url}]: ${Date.now() - s}ms`) next() }).catch(errorHandler) + .finally(() => { + clearSSRContext(context) + }) } const dynamicCacheHandler = () => { diff --git a/core/server-entry.ts b/core/server-entry.ts index 2569e88a7a..5a03915503 100755 --- a/core/server-entry.ts +++ b/core/server-entry.ts @@ -70,7 +70,6 @@ export default async context => { } const { app, router, store } = await createApp(context, context.vs && context.vs.config ? context.vs.config : buildTimeConfig, storeCode) return new Promise((resolve, reject) => { - context.output.cacheTags = new Set() const meta = (app as any).$meta() router.push(context.url) context.meta = meta diff --git a/core/store/lib/storage.ts b/core/store/lib/storage.ts index 0ee70ac661..039dbad245 100644 --- a/core/store/lib/storage.ts +++ b/core/store/lib/storage.ts @@ -2,6 +2,7 @@ import Vue from 'vue' import * as localForage from 'localforage' import { Logger } from '@vue-storefront/core/lib/logger' import { isServer } from '@vue-storefront/core/helpers' +import cloneDeep from 'lodash-es/cloneDeep' const CACHE_TIMEOUT = 800 const CACHE_TIMEOUT_ITERATE = 2000 @@ -33,6 +34,13 @@ function roughSizeOfObject (object) { return bytes } +interface CacheTimeouts { + getItem: any, + iterate: any, + setItem: any, + base: any +} + class LocalForageCacheDriver { private _collectionName: string; private _dbName: string; @@ -43,6 +51,12 @@ class LocalForageCacheDriver { private _useLocalCacheByDefault: boolean; private cacheErrorsCount: any; private _storageQuota: number; + private _cacheTimeouts: CacheTimeouts = { + getItem: null, + iterate: null, + setItem: null, + base: null + } public constructor (collection, useLocalCacheByDefault = true, storageQuota = 0) { const collectionName = collection._config.storeName @@ -53,7 +67,8 @@ class LocalForageCacheDriver { const storageQuota = this._storageQuota const iterateFnc = this.iterate.bind(this) const removeItemFnc = this.removeItem.bind(this) - setInterval(() => { + clearInterval(this._cacheTimeouts.base) + this._cacheTimeouts.base = setInterval(() => { let storageSize = 0 this.iterate((item, id, number) => { storageSize += roughSizeOfObject(item) @@ -135,6 +150,10 @@ class LocalForageCacheDriver { } } + public getLocalCache (key) { + return typeof this._localCache[key] !== 'undefined' ? cloneDeep(this._localCache[key]) : null + } + // 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. @@ -144,7 +163,7 @@ class LocalForageCacheDriver { if (this._useLocalCacheByDefault && this._localCache[key]) { // Logger.debug('Local cache fallback for GET', key)() return new Promise((resolve, reject) => { - const value = typeof this._localCache[key] !== 'undefined' ? this._localCache[key] : null + const value = this.getLocalCache(key) if (isCallbackCallable) callback(null, value) resolve(value) }) @@ -165,31 +184,34 @@ class LocalForageCacheDriver { // Logger.debug('No local cache fallback for GET', key)() const promise = this._localForageCollection.ready().then(() => this._localForageCollection.getItem(key).then(result => { const endTime = new Date().getTime() + const clonedResult = cloneDeep(result) if ((endTime - startTime) >= CACHE_TIMEOUT) { Logger.error('Cache promise resolved after [ms]' + key + (endTime - startTime))() } - if (!this._localCache[key] && result) { - this._localCache[key] = result // populate the local cache for the next call + if (!this._localCache[key] && clonedResult) { + this._localCache[key] = clonedResult // populate the local cache for the next call } if (!isResolved) { if (isCallbackCallable) { - callback(null, result) + callback(null, clonedResult) } isResolved = true } else { Logger.debug('Skipping return value as it was previously resolved')() } - return result + return clonedResult }).catch(err => { this._lastError = err if (!isResolved) { - if (isCallbackCallable) callback(null, typeof this._localCache[key] !== 'undefined' ? this._localCache[key] : null) + const value = this.getLocalCache(key) + if (isCallbackCallable) callback(null, value) } Logger.error(err)() isResolved = true })) - setTimeout(() => { + clearTimeout(this._cacheTimeouts.getItem) + this._cacheTimeouts.getItem = setTimeout(() => { if (!isResolved) { // this is cache time out check if (!this._persistenceErrorNotified) { Logger.error('Cache not responding for ' + key + '.', 'cache', { timeout: CACHE_TIMEOUT, errorsCount: this.cacheErrorsCount[this._collectionName] })() @@ -197,14 +219,15 @@ class LocalForageCacheDriver { this.recreateDb() } this.cacheErrorsCount[this._collectionName] = this.cacheErrorsCount[this._collectionName] ? this.cacheErrorsCount[this._collectionName] + 1 : 1 - if (isCallbackCallable) callback(null, typeof this._localCache[key] !== 'undefined' ? this._localCache[key] : null) + const value = this.getLocalCache(key) + if (isCallbackCallable) callback(null, value) } }, CACHE_TIMEOUT) return promise } } else { return new Promise((resolve, reject) => { - const value = typeof this._localCache[key] !== 'undefined' ? this._localCache[key] : null + const value = this.getLocalCache(key) if (isCallbackCallable) callback(null, value) resolve(value) }) @@ -251,7 +274,8 @@ class LocalForageCacheDriver { if (isCallbackCallable) callback(err, null) } }) - setTimeout(() => { + clearTimeout(this._cacheTimeouts.iterate) + this._cacheTimeouts.iterate = setTimeout(() => { if (!isResolved) { // this is cache time out check if (!this._persistenceErrorNotified) { Logger.error('Cache not responding. (iterate)', 'cache', { timeout: CACHE_TIMEOUT, errorsCount: this.cacheErrorsCount[this._collectionName] })() @@ -293,7 +317,8 @@ class LocalForageCacheDriver { // saved, or something like that. public setItem (key, value, callback?, memoryOnly = false) { const isCallbackCallable = (typeof callback !== 'undefined' && callback) - this._localCache[key] = value + const copiedValue = cloneDeep(value) + this._localCache[key] = copiedValue if (memoryOnly) { return new Promise((resolve, reject) => { if (isCallbackCallable) callback(null, null) @@ -312,7 +337,7 @@ class LocalForageCacheDriver { }) } else { let isResolved = false - const promise = this._localForageCollection.ready().then(() => this._localForageCollection.setItem(key, value).then(result => { + const promise = this._localForageCollection.ready().then(() => this._localForageCollection.setItem(key, copiedValue).then(result => { if (isCallbackCallable) { callback(null, result) } @@ -322,7 +347,8 @@ class LocalForageCacheDriver { this._lastError = err throw err })) - setTimeout(() => { + clearTimeout(this._cacheTimeouts.iterate) + this._cacheTimeouts.setItem = setTimeout(() => { if (!isResolved) { // this is cache time out check if (!this._persistenceErrorNotified) { Logger.error('Cache not responding for ' + key + '.', 'cache', { timeout: CACHE_TIMEOUT, errorsCount: this.cacheErrorsCount[this._collectionName] })() From fd3a2786f1a17a9ef05df924353498c85a9d015b Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 21 Nov 2019 12:29:48 +0100 Subject: [PATCH 20/29] dont use nonReactiveState on SSR --- core/modules/catalog/store/product/getters.ts | 11 +++++++---- core/modules/catalog/store/product/mutations.ts | 7 +++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/core/modules/catalog/store/product/getters.ts b/core/modules/catalog/store/product/getters.ts index 449968a62e..57bc655c1e 100644 --- a/core/modules/catalog/store/product/getters.ts +++ b/core/modules/catalog/store/product/getters.ts @@ -5,10 +5,13 @@ import RootState from '@vue-storefront/core/types/RootState' import ProductState from '../../types/ProductState' import cloneDeep from 'lodash-es/cloneDeep' -function mapCategoryProducts (productsSkus, productsData) { - return productsSkus.map(prodSku => { - const product = productsData.find(prodData => prodData.sku === prodSku) - return cloneDeep(product) +function mapCategoryProducts (productsFromState, productsData) { + return productsFromState.map(prodState => { + if (typeof prodState === 'string') { + const product = productsData.find(prodData => prodData.sku === prodState) + return cloneDeep(product) + } + return prodState }) } diff --git a/core/modules/catalog/store/product/mutations.ts b/core/modules/catalog/store/product/mutations.ts index c27af487fc..bc85cf2890 100644 --- a/core/modules/catalog/store/product/mutations.ts +++ b/core/modules/catalog/store/product/mutations.ts @@ -1,3 +1,4 @@ +import { isServer } from '@vue-storefront/core/helpers'; import { nonReactiveState } from './index'; import Vue from 'vue' import { MutationTree } from 'vuex' @@ -32,13 +33,15 @@ const mutations: MutationTree = { [types.CATALOG_UPD_PRODUCTS] (state, { products, append }) { if (append === false) { nonReactiveState.list = cloneDeep(products.items) - state.list = cloneDeep({...products, items: products.items.map(prod => prod.sku)}) + state.list = isServer ? products : cloneDeep({...products, items: products.items.map(prod => prod.sku)}) } else { const pagedProductList = state.list as PagedProductList pagedProductList.start = products.start as number pagedProductList.perPage = products.perPage as number nonReactiveState.list = cloneDeep(nonReactiveState.list.concat(products.items)) - pagedProductList.items = cloneDeep(pagedProductList.items.concat(products.items.map(prod => prod.sku))) + pagedProductList.items = isServer + ? pagedProductList.items.concat(products.items) + : cloneDeep(pagedProductList.items.concat(products.items.map(prod => prod.sku))) } }, [types.CATALOG_SET_PRODUCT_CURRENT] (state, product) { From d992225219dc817f349bce290c57ec8fb918d6e5 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 21 Nov 2019 15:00:05 +0100 Subject: [PATCH 21/29] change translation from jp-JP to ja-JP --- .gitignore | 2 +- config/default.json | 2 +- core/i18n/index.ts | 6 +++++- core/i18n/resource/i18n/{jp-JP.csv => ja-JP.csv} | 0 docs/guide/cookbook/setup.md | 2 +- src/themes/default/resource/i18n/{jp-JP.csv => ja-JP.csv} | 0 6 files changed, 8 insertions(+), 4 deletions(-) rename core/i18n/resource/i18n/{jp-JP.csv => ja-JP.csv} (100%) rename src/themes/default/resource/i18n/{jp-JP.csv => ja-JP.csv} (100%) diff --git a/.gitignore b/.gitignore index 9069dc6d6c..15c6ca7cb5 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,7 @@ core/resource/i18n/en-US.json core/resource/i18n/es-ES.json core/resource/i18n/fr-FR.json core/resource/i18n/it-IT.json -core/resource/i18n/jp-JP.json +core/resource/i18n/ja-JP.json core/resource/i18n/multistoreLanguages.json core/resource/i18n/nl-NL.json core/resource/i18n/pl-PL.json diff --git a/config/default.json b/config/default.json index 8be8043abf..41ae29c797 100644 --- a/config/default.json +++ b/config/default.json @@ -403,7 +403,7 @@ "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"], + "availableLocale": ["en-US","de-DE","fr-FR","es-ES","nl-NL", "ja-JP", "ru-RU", "it-IT", "pt-BR", "pl-PL", "cs-CZ"], "defaultLocale": "en-US", "currencyCode": "USD", "currencySign": "$", diff --git a/core/i18n/index.ts b/core/i18n/index.ts index e785373eb6..ec26ca9629 100644 --- a/core/i18n/index.ts +++ b/core/i18n/index.ts @@ -33,7 +33,11 @@ const loadDateLocales = async (lang: string = 'en'): Promise => { const separatorIndex = localeCode.indexOf('-') if (separatorIndex) { localeCode = separatorIndex ? localeCode.substr(0, separatorIndex) : localeCode - await import(/* webpackChunkName: "dayjs-locales" */ `dayjs/locale/${localeCode}`) + try { + await import(/* webpackChunkName: "dayjs-locales" */ `dayjs/locale/${localeCode}`) + } catch (err) { + Logger.debug('Unable to load translation from dayjs')() + } } } } diff --git a/core/i18n/resource/i18n/jp-JP.csv b/core/i18n/resource/i18n/ja-JP.csv similarity index 100% rename from core/i18n/resource/i18n/jp-JP.csv rename to core/i18n/resource/i18n/ja-JP.csv diff --git a/docs/guide/cookbook/setup.md b/docs/guide/cookbook/setup.md index fef18375d8..81201c4221 100644 --- a/docs/guide/cookbook/setup.md +++ b/docs/guide/cookbook/setup.md @@ -1259,7 +1259,7 @@ At [`vue-storefront/config/default.json`](https://github.com/DivanteLtd/vue-stor "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"], + "availableLocale": ["en-US","de-DE","fr-FR","es-ES","nl-NL", "ja-JP", "ru-RU", "it-IT", "pt-BR", "pl-PL", "cs-CZ"], "defaultLocale": "en-US", "currencyCode": "USD", "currencySign": "$", diff --git a/src/themes/default/resource/i18n/jp-JP.csv b/src/themes/default/resource/i18n/ja-JP.csv similarity index 100% rename from src/themes/default/resource/i18n/jp-JP.csv rename to src/themes/default/resource/i18n/ja-JP.csv From 60fadaa7a8dd655245ebb1786f9c4fd1acc24601 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Thu, 21 Nov 2019 15:09:37 +0100 Subject: [PATCH 22/29] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba5e3659c4..fd8d3ccb1b 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 - Fixed null value of search input - @AdKamil (#3778) - Sorting fixed on category page - @AdKamil (#3785) - Mount app in 'beforeResolve' if it's not dispatched in 'onReady' - @gibkigonzo (#3669) +- change translation from jp-JP to ja-JP - @gibkigonzo (#3824) ## [1.10.4] - 18.10.2019 From 0238dbf0c8c454d756d584dbf5bd411210048126 Mon Sep 17 00:00:00 2001 From: andrzejewsky Date: Wed, 27 Nov 2019 17:39:55 +0100 Subject: [PATCH 23/29] small fixes --- .../components/core/blocks/Footer/Footer.vue | 15 ++++++++++++++- src/themes/default/pages/MyAccount.vue | 1 - src/themes/default/pages/Static.vue | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/themes/default/components/core/blocks/Footer/Footer.vue b/src/themes/default/components/core/blocks/Footer/Footer.vue index e5c9328047..326259dfea 100644 --- a/src/themes/default/components/core/blocks/Footer/Footer.vue +++ b/src/themes/default/components/core/blocks/Footer/Footer.vue @@ -15,9 +15,12 @@ {{ $t('Orders') }}
- + {{ $t('My account') }} + + {{ $t('My account') }} +
@@ -158,6 +161,7 @@