Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add unit tests for `core/modules/order` - @dz3n (#3466)
- Add unit tests for `core/modules/user` - @dz3n (#3470)
- Add to cart from Wishlist and Product listing for simple products - @Dnd-Dboy, @dz3n (#2637)
- Add global Category and Breadcrumb filters, defined in local.json - @grimasod (#3691)

### Fixed
- Fixed problem with cutting image height in category page on 1024px+ screen res - @AdKamil (#3781)
Expand All @@ -22,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed sorting on category page and product tile sizing - @andrzejewsky (#3817)
- Redirect from simple product using url_path - @benjick (#3804)
- Mount app in 'beforeResolve' if it's not dispatched in 'onReady' - @gibkigonzo (#3669)
- Fixed AMP pages - @andrzejewsky (#3799)
- Fixed Product page breadcrumbs problem when products are in multiple categories in different branches of the category tree - @grimasod (#3691)
- Change translation from jp-JP to ja-JP - @gibkigonzo (#3824)

### Changed / Improved
Expand All @@ -34,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Add defense for incomplete config in preferchCachedAttributes helper


### Fixed
- Fixed deprecated getter in cmsBlock store - @resubaka (#3683)
- Fixed problem around dynamic urls when default storeView is set with appendStoreCode false and url set to / . @resubaka (#3685)
Expand All @@ -57,7 +61,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed missing parameter in the compare list - @andrzejewsky (#3757)
- Fixed product link on mobile - @andrzejewsky (#3772)
- Custom module `ConfigProvider` aren't called anymore - @cewald (#3797)
- Fixed AMP pages - @andrzejewsky (#3799)

### Added
- Added Estonian translations - @alphpkeemik
Expand Down
2 changes: 2 additions & 0 deletions config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@
"category": {
"includeFields": [ "id", "*.children_data.id", "*.id", "children_count", "sku", "name", "is_active", "parent_id", "level", "url_key", "url_path", "product_count", "path", "position"],
"excludeFields": [ "sgn" ],
"filterFields": {},
"breadcrumbFilterFields": {},
"categoriesRootCategorylId": 2,
"categoriesDynamicPrefetchLevel": 2,
"categoriesDynamicPrefetch": true,
Expand Down
12 changes: 8 additions & 4 deletions core/data-resolver/CategoryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ const getCategories = async ({
}

for (var [key, value] of Object.entries(filters)) {
if (Array.isArray(value)) {
searchQuery = searchQuery.applyFilter({key: key, value: {'in': value}})
} else {
searchQuery = searchQuery.applyFilter({key: key, value: {'eq': value}})
if (value !== null) {
if (Array.isArray(value)) {
searchQuery = searchQuery.applyFilter({key: key, value: {'in': value}})
} else if (typeof value === 'object') {
searchQuery = searchQuery.applyFilter({key: key, value: value})
} else {
searchQuery = searchQuery.applyFilter({key: key, value: {'eq': value}})
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/lib/multistore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export function localizedDispatcherRouteName (routeName: string, storeCode: stri
return routeName
}

export function localizedRoute (routeObj: LocalizedRoute | string | RouteConfig | RawLocation, storeCode: string): any {
export function localizedRoute (routeObj: LocalizedRoute | string | RouteConfig | RawLocation, storeCode: string = null): any {
if (!storeCode) {
storeCode = currentStoreView().storeCode
}
Expand Down
38 changes: 35 additions & 3 deletions core/modules/breadcrumbs/components/Breadcrumbs.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
import { localizedRoute, currentStoreView } from '@vue-storefront/core/lib/multistore'
import i18n from '@vue-storefront/i18n'
import { mapGetters } from 'vuex'

export const Breadcrumbs = {
computed: {
routes () {
return this.$store.state.breadcrumbs.routes
...mapGetters({
getBreadcrumbsRoutes: 'breadcrumbs/getBreadcrumbsRoutes',
getBreadcrumbsCurrent: 'breadcrumbs/getBreadcrumbsCurrent'
}),
paths () {
const routes = this.routes ? this.routes : this.getBreadcrumbsRoutes

if (this.withHomepage) {
return [
{ name: i18n.t('Homepage'), route_link: localizedRoute('/', currentStoreView().storeCode) },
...routes
]
}

return routes
},
current () {
return this.$store.state.breadcrumbs.current
return this.activeRoute || this.getBreadcrumbsCurrent
}
},
props: {
routes: {
type: Array,
required: false,
default: null
},
withHomepage: {
type: Boolean,
default: false
},
activeRoute: {
type: String,
default: ''
}
}
}
4 changes: 4 additions & 0 deletions core/modules/breadcrumbs/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,9 @@ export const breadcrumbsStore = {
set ({ commit }, payload) {
commit('set', payload)
}
},
getters: {
getBreadcrumbsRoutes: (state) => state.routes,
getBreadcrumbsCurrent: (state) => state.current
}
}
29 changes: 23 additions & 6 deletions core/modules/catalog-next/store/category/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import chunk from 'lodash-es/chunk'
import Product from 'core/modules/catalog/types/Product';
import omit from 'lodash-es/omit'
import config from 'config'
import { parseCategoryPath } from '@vue-storefront/core/modules/breadcrumbs/helpers'

const actions: ActionTree<CategoryState, RootState> = {
async loadCategoryProducts ({ commit, getters, dispatch, rootState }, { route, category, pageSize = 50 } = {}) {
Expand Down Expand Up @@ -127,20 +128,27 @@ const actions: ActionTree<CategoryState, RootState> = {
return CategoryService.getCategories(categorySearchOptions)
},
async loadCategories ({ commit, getters }, categorySearchOptions: DataResolver.CategorySearchOptions): Promise<Category[]> {
const searchingByIds = categorySearchOptions && categorySearchOptions.filters && categorySearchOptions.filters.id
const searchingByIds = !(!categorySearchOptions || !categorySearchOptions.filters || !categorySearchOptions.filters.id)
const searchedIds: string[] = searchingByIds ? (categorySearchOptions.filters.id as string[]) : []
if (searchingByIds) { // removing from search query already loaded categories
const loadedCategories: Category[] = []
if (searchingByIds) { // removing from search query already loaded categories, they are added to returned results
for (const [categoryId, category] of Object.entries(getters.getCategoriesMap)) {
if (searchedIds.includes(categoryId)) {
loadedCategories.push(category as Category)
}
}
categorySearchOptions.filters.id = searchedIds.filter(categoryId => !getters.getCategoriesMap[categoryId] && !getters.getNotFoundCategoryIds.includes(categoryId))
}
if (!searchingByIds || categorySearchOptions.filters.id.length) {
categorySearchOptions.filters = Object.assign(config.entities.category.filterFields, categorySearchOptions.filters)
const categories = await CategoryService.getCategories(categorySearchOptions)
const notFoundCategories = searchedIds.filter(categoryId => !categories.some(cat => cat.id === parseInt(categoryId)))

commit(types.CATEGORY_ADD_CATEGORIES, categories)
commit(types.CATEGORY_ADD_NOT_FOUND_CATEGORY_IDS, notFoundCategories)
return categories
return [...loadedCategories, ...categories]
}
return []
return loadedCategories
},
async loadCategory ({ commit }, categorySearchOptions: DataResolver.CategorySearchOptions): Promise<Category> {
const categories: Category[] = await CategoryService.getCategories(categorySearchOptions)
Expand Down Expand Up @@ -185,11 +193,20 @@ const actions: ActionTree<CategoryState, RootState> = {
async changeRouterFilterParameters (context, query) {
router.push({[products.routerFiltersSource]: query})
},
async loadCategoryBreadcrumbs ({ dispatch, getters }, category: Category) {
async loadCategoryBreadcrumbs ({ dispatch, getters }, { category, currentRouteName, omitCurrent = false }) {
if (!category) return
const categoryHierarchyIds = _prepareCategoryPathIds(category) // getters.getCategoriesHierarchyMap.find(categoryMapping => categoryMapping.includes(category.id))
const categoryFilters = { 'id': categoryHierarchyIds }
await dispatch('loadCategories', {filters: categoryFilters})
const categories = await dispatch('loadCategories', {filters: categoryFilters})
const sorted = []
for (const id of categoryHierarchyIds) {
const index = categories.findIndex(cat => cat.id.toString() === id)
if (index >= 0 && (!omitCurrent || categories[index].id !== category.id)) {
sorted.push(categories[index])
}
}
await dispatch('breadcrumbs/set', { current: currentRouteName, routes: parseCategoryPath(sorted) }, { root: true })
return sorted
}
}

Expand Down
13 changes: 8 additions & 5 deletions core/modules/catalog/store/product/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -680,12 +680,15 @@ const actions: ActionTree<ProductState, RootState> = {
context.commit(types.PRODUCT_SET_GALLERY, productGallery)
}
},
async loadProductBreadcrumbs ({ dispatch }, { product } = {}) {
async loadProductBreadcrumbs ({ dispatch, rootGetters }, { product } = {}) {
if (product && product.category_ids) {
const categoryFilters = { 'id': product.category_ids }
const categories = await dispatch('category-next/loadCategories', {filters: categoryFilters}, { root: true })
const deepestCategory = categories.sort((a, b) => (a.level > b.level) ? -1 : 1)[0] // sort starting by deepest level
await dispatch('category-next/loadCategoryBreadcrumbs', deepestCategory, { root: true })
let currentCategory = rootGetters['category-next/getCurrentCategory'] // use current category, if set
if (!currentCategory || !currentCategory.id || !product.category_ids.includes(currentCategory.id.toString())) {
const categoryFilters = Object.assign({ 'id': product.category_ids }, config.entities.category.breadcrumbFilterFields)
const categories = await dispatch('category-next/loadCategories', {filters: categoryFilters}, { root: true })
currentCategory = categories.sort((a, b) => (a.level > b.level) ? -1 : 1)[0] // sort starting by deepest level
}
await dispatch('category-next/loadCategoryBreadcrumbs', { category: currentCategory, currentRouteName: product.name }, { root: true })
}
}
}
Expand Down
9 changes: 1 addition & 8 deletions core/modules/catalog/store/product/getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,14 @@ import ProductState from '../../types/ProductState'

const getters: GetterTree<ProductState, RootState> = {
getCurrentProduct: state => state.current,
getCurrentProductCategoryId: (state, getters, rootState, rootGetters) => {
if (getters.getCurrentProduct && getters.getCurrentProduct.category_ids) {
return rootGetters['category-next/getCategoriesMap'][getters.getCurrentProduct.category_ids[0]]
}
return null
},
getCurrentProductConfiguration: state => state.current_configuration,
getCurrentProductOptions: state => state.current_options,
getOriginalProduct: state => state.original,
getParentProduct: state => state.parent,
getProductsSearchResult: state => state.list,
getProducts: (state, getters) => getters.getProductsSearchResult.items,
getProductGallery: state => state.productGallery,
getProductRelated: state => state.related,
getProductBreadcrumbs: (state, getters, rootState, rootGetters) => rootGetters['category-next/getBreadcrumbsFor'](getters.getCurrentProductCategoryId)
getProductRelated: state => state.related
}

export default getters
2 changes: 2 additions & 0 deletions docs/guide/upgrade-notes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ If by some reasons you wan't to have the `localStorage` back on for `Products by
- Optionally give theme routes priority, to ensure they override module routes if there are any conflicts. For example `setupMultistoreRoutes(config, router, routes, 10)`.
- See `/src/themes/default/index.js` for a complete example.
- In `storeView` config there is no more `disabled` flag for specific language config. Links for other languages will be displayed if specific `storeView` config exist.
- Categories can be filtered globally, to never be loaded, by setting `entities.category.filterFields` in local.json, e.g. `"filterFields": { "is_active": true }`.
- Categories can be filtered in the Breadcrumbs, by setting `entities.category.breadcrumbFilterFields` in local.json, e.g. `"breadcrumbFilterFields": { "include_in_menu": true }`.

## 1.9 -> 1.10
- Event `application-after-init` is now emitted by event bus instead of root Vue instance (app), so you need to listen to `Vue.prototype.$bus` (`EventBus.$on()`) now
Expand Down
2 changes: 1 addition & 1 deletion src/themes/default-amp/pages/Category.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div id="category">
<header class="bg-cl-secondary py35 pl20">
<div class="container">
<breadcrumbs :routes="breadcrumbs.routes" :active-route="category.name" />
<breadcrumbs />
<div class="row middle-sm">
<h1 class="col-sm-9 category-title mb10">
{{ category.name }}
Expand Down
2 changes: 0 additions & 2 deletions src/themes/default-amp/pages/Product.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
<div class="col-xs-12 col-md-5 data">
<breadcrumbs
class="pt40 pb20 hidden-xs"
:routes="breadcrumbs"
:active-route="product.name"
/>
<h1 class="mb20 mt0 cl-mine-shaft product-name" data-testid="productName" itemprop="name">
{{ product.name | htmlDecode }}
Expand Down
36 changes: 2 additions & 34 deletions src/themes/default/components/core/Breadcrumbs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,9 @@
</template>

<script>
import { localizedRoute, currentStoreView } from '@vue-storefront/core/lib/multistore'
import i18n from '@vue-storefront/i18n'
import { Breadcrumbs } from '@vue-storefront/core/modules/breadcrumbs/components/Breadcrumbs.ts'
export default {
computed: {
paths () {
const routes = this.routes ? this.routes : this.$store.state.breadcrumbs.routes
if (this.withHomepage) {
return [
{ name: i18n.t('Homepage'), route_link: localizedRoute('/', currentStoreView().storeCode) },
...routes
]
}
return routes
},
current () {
return this.activeRoute || this.$store.state.breadcrumbs.current
}
},
props: {
routes: {
type: Array,
required: false,
default: null
},
withHomepage: {
type: Boolean,
default: false
},
activeRoute: {
type: String,
default: ''
}
}
mixins: [Breadcrumbs]
}
</script>
7 changes: 2 additions & 5 deletions src/themes/default/pages/Category.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div id="category">
<header class="bg-cl-secondary py35 pl20">
<div class="container">
<breadcrumbs :routes="getBreadcrumbs" :active-route="getCurrentCategory.name" />
<breadcrumbs />
<div class="row middle-sm">
<h1 class="col-sm-8 category-title mb10">
{{ getCurrentCategory.name }}
Expand Down Expand Up @@ -101,7 +101,7 @@ const composeInitialPageState = async (store, route, forceLoad = false) => {
const cachedCategory = store.getters['category-next/getCategoryFrom'](route.path)
const currentCategory = cachedCategory && !forceLoad ? cachedCategory : await store.dispatch('category-next/loadCategory', { filters })
await store.dispatch('category-next/loadCategoryProducts', {route, category: currentCategory})
const breadCrumbsLoader = store.dispatch('category-next/loadCategoryBreadcrumbs', currentCategory)
const breadCrumbsLoader = store.dispatch('category-next/loadCategoryBreadcrumbs', { category: currentCategory, currentRouteName: currentCategory.name, omitCurrent: true })
if (isServer) await breadCrumbsLoader
catalogHooksExecutors.categoryPageVisited(currentCategory)
} catch (e) {
Expand Down Expand Up @@ -141,9 +141,6 @@ export default {
},
isCategoryEmpty () {
return this.getCategoryProductsTotal === 0
},
getBreadcrumbs () {
return this.$store.getters['category-next/getBreadcrumbs'].filter(breadcrumb => breadcrumb.name !== this.getCurrentCategory.name)
}
},
async asyncData ({ store, route }) { // this is for SSR purposes to prefetch data - and it's always executed before parent component methods
Expand Down
3 changes: 0 additions & 3 deletions src/themes/default/pages/Product.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
<div class="col-xs-12 col-md-5 data">
<breadcrumbs
class="pt40 pb20 hidden-xs"
:routes="getBreadcrumbs"
:active-route="getCurrentProduct.name"
/>
<h1
class="mb20 mt0 cl-mine-shaft product-name"
Expand Down Expand Up @@ -280,7 +278,6 @@ export default {
computed: {
...mapGetters({
getCurrentCategory: 'category-next/getCurrentCategory',
getBreadcrumbs: 'product/getProductBreadcrumbs',
getCurrentProduct: 'product/getCurrentProduct',
getProductGallery: 'product/getProductGallery',
getCurrentProductConfiguration: 'product/getCurrentProductConfiguration',
Expand Down