diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c67975b98..269442a60e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ 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.11.3] - 2020.04.27 + +### Changed / Improved + +- The default config file is now in more human-readable format - @juho-jaakkola (#4197) +- Create only once aside async component - @gibkigonzo (#4229, #4268) + +### Fixed +- Fixes when having multiple custom options with overlapping option_type_id values, selecting 1 changes the others - @carlokok (#4196) +- Update eslint and fix code style. - @gibkigonzo (#4179 #4181) +- Fixes bug that caused addToCart action not to display messages to user - @juho-jaakkola (#4185) +- add missing cache tags for category and product - @gibkigonzo (#4173) +- add ssrAppId to avoid second meta render on csr - @gibkigonzo (#4203) +- take control over default broswer behavior and use saved category page size to load prev products - @gibkigonzo (#4201) +- update getCurrentCartHash after add/remove coupon - @gibkigonzo (#4220) +- update replaceNumberToString, so it will change ONLY numbers to string - @gibkigonzo (#4217) +- allow empty shipping methods in checkout - @gibkigozno (#4192) +- configure products before price update - this is needed to have variant sku as product sku - @gibkigonzo (#4053) +- omit stock and totals when creating cart hash, it is not needed to compare products - @gibkigozno (#4235, #4273) + ## [1.11.2] - 2020.03.10 ### Added diff --git a/config/default.json b/config/default.json index 7b8083e976..bfb3c8a576 100644 --- a/config/default.json +++ b/config/default.json @@ -13,17 +13,55 @@ "useOutputCacheTagging": false, "useOutputCache": false, "outputCacheDefaultTtl": 86400, - "availableCacheTags": ["product", "category", "home", "checkout", "page-not-found", "compare", "my-account", "P", "C", "error", "attribute", "taxrule"], + "availableCacheTags": [ + "attribute", + "C", + "category", + "checkout", + "compare", + "error", + "home", + "my-account", + "P", + "page-not-found", + "product", + "taxrule" + ], "invalidateCacheKey": "aeSu7aip", "invalidateCacheForwarding": false, "invalidateCacheForwardUrl": "http://localhost:8080/invalidate?key=aeSu7aip&tag=", "dynamicConfigReload": true, "dynamicConfigContinueOnError": false, - "dynamicConfigExclude": ["ssr", "storeViews", "entities", "localForage", "shipping", "boost", "query"], + "dynamicConfigExclude": [ + "entities", + "boost", + "localForage", + "query", + "shipping", + "ssr", + "storeViews" + ], "dynamicConfigInclude": [], "elasticCacheQuota": 4096, "ssrDisabledFor": { - "extensions": ["png", "gif", "jpg", "jpeg", "woff", "eot", "woff2", "ttf", "svg", "css", "js", "json", "ico", "tiff", "tif", "raw"] + "extensions": [ + "css", + "eot", + "gif", + "ico", + "jpg", + "jpeg", + "js", + "json", + "png", + "raw", + "svg", + "tiff", + "tif", + "ttf", + "woff", + "woff2" + ] }, "trace": { "enabled": false, @@ -40,7 +78,7 @@ "defaultTitle": "Vue Storefront" }, "console": { - "showErrorOnProduction" : false, + "showErrorOnProduction": false, "verbosityLevel": "display-everything" }, "redis": { @@ -48,7 +86,7 @@ "port": 6379, "db": 0 }, - "graphql":{ + "graphql": { "host": "localhost", "port": 8080 }, @@ -67,11 +105,15 @@ "searchScoring": { "attributes": { "attribute_code": { - "scoreValues": { "attribute_value": { "weight": 1 } } + "scoreValues": { + "attribute_value": { + "weight": 1 + } + } } }, "fuzziness": 2, - "cutoff_frequency": 0.01, + "cutoff_frequency": 0.01, "max_expansions": 3, "minimum_should_match": "75%", "prefix_length": 2, @@ -99,9 +141,17 @@ "basic": "dist/index.basic.html", "amp": "dist/index.amp.html" }, - "lazyHydrateFor": ["category-next.products", "homepage.new_collection"], + "lazyHydrateFor": [ + "category-next.products", + "homepage.new_collection" + ], "executeMixedinAsyncData": true, - "initialStateFilter": ["__DEMO_MODE__", "version", "storeView", "attribute.list_by_id"], + "initialStateFilter": [ + "__DEMO_MODE__", + "version", + "storeView", + "attribute.list_by_id" + ], "useInitialStateFilter": true }, "queues": { @@ -112,7 +162,10 @@ "storeViews": { "multistore": false, "commonCache": false, - "mapStoreUrlsFor": ["de", "it"], + "mapStoreUrlsFor": [ + "de", + "it" + ], "de": { "storeCode": "de", "storeId": 3, @@ -173,95 +226,264 @@ "optimize": true, "twoStageCaching": true, "optimizeShoppingCart": true, - "optimizeShoppingCartOmitFields": ["configurable_children", "configurable_options", "media_gallery", "description", "category", "category_ids", "product_links", "stock", "description"], + "optimizeShoppingCartOmitFields": [ + "category", + "category_ids", + "configurable_children", + "configurable_options", + "description", + "media_gallery", + "product_links", + "stock" + ], "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" ], + "includeFields": [ + "children_count", + "id", + "is_active", + "level", + "name", + "parent_id", + "path", + "position", + "product_count", + "sku", + "url_key", + "url_path", + "*.children_data.id", + "*.id" + ], + "excludeFields": [ + "sgn" + ], "filterFields": {}, "breadcrumbFilterFields": {}, "categoriesRootCategorylId": 2, "categoriesDynamicPrefetchLevel": 2, "categoriesDynamicPrefetch": true, - "validSearchOptionsFromRouteParams": ["url-key", "slug", "id"] + "validSearchOptionsFromRouteParams": [ + "url-key", + "slug", + "id" + ] }, "attribute": { - "includeFields": [ "activity", "attribute_code", "id", "entity_type_id", "options", "default_value", "is_user_defined", "frontend_label", "attribute_id", "default_frontend_label", "is_visible_on_front", "is_visible", "is_comparable", "tier_prices", "frontend_input" ] + "includeFields": [ + "activity", + "attribute_code", + "attribute_id", + "default_frontend_label", + "default_value", + "entity_type_id", + "frontend_input", + "frontend_label", + "id", + "is_user_defined", + "is_visible_on_front", + "is_visible", + "is_comparable", + "options", + "tier_prices" + ] }, "productList": { "sort": "updated_at:desc", - "includeFields": [ "activity", "type_id", "*sku", "product_links", "tax_class_id", "special_price", "special_to_date", "special_from_date", "name", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "url_path", "url_key", "status", "tier_prices", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "*image","*small_image", "configurable_children.color", "configurable_children.size", "configurable_children.tier_prices", "final_price", "configurable_children.final_price"], - "excludeFields": [ "description", "configurable_options", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options" ] + "includeFields": [ + "activity", + "configurable_children.id", + "configurable_children.final_price", + "configurable_children.color", + "configurable_children.original_price", + "configurable_children.original_price_incl_tax", + "configurable_children.price", + "configurable_children.price_incl_tax", + "configurable_children.size", + "configurable_children.sku", + "configurable_children.special_price", + "configurable_children.special_price_incl_tax", + "configurable_children.tier_prices", + "final_price", + "id", + "image", + "name", + "new", + "original_price_incl_tax", + "original_price", + "price", + "price_incl_tax", + "product_links", + "sale", + "special_price", + "special_to_date", + "special_from_date", + "special_price_incl_tax", + "status", + "tax_class_id", + "tier_prices", + "type_id", + "url_path", + "url_key", + "*image", + "*sku", + "*small_image" + ], + "excludeFields": [ + "configurable_options", + "description", + "sgn", + "*.sgn", + "msrp_display_actual_price_type", + "*.msrp_display_actual_price_type", + "required_options" + ] }, "productListWithChildren": { - "includeFields": [ "activity", "type_id", "sku", "name", "tax_class_id", "final_price", "special_price", "special_to_date", "special_from_date", "price", "price_incl_tax", "original_price_incl_tax", "original_price", "special_price_incl_tax", "id", "image", "sale", "new", "configurable_children.image", "configurable_children.sku", "configurable_children.price", "configurable_children.special_price", "configurable_children.price_incl_tax", "configurable_children.special_price_incl_tax", "configurable_children.original_price", "configurable_children.original_price_incl_tax", "configurable_children.color", "configurable_children.size", "configurable_children.id", "configurable_children.tier_prices", "product_links", "url_path", "url_key", "status", "tier_prices", "configurable_children.special_to_date", "configurable_children.special_from_date", "configurable_children.regular_price", "configurable_children.final_price"], - "excludeFields": [ "description", "sgn", "*.sgn", "msrp_display_actual_price_type", "*.msrp_display_actual_price_type", "required_options"] + "includeFields": [ + "activity", + "configurable_children.image", + "configurable_children.sku", + "configurable_children.price", + "configurable_children.special_price", + "configurable_children.price_incl_tax", + "configurable_children.special_price_incl_tax", + "configurable_children.original_price", + "configurable_children.original_price_incl_tax", + "configurable_children.color", + "configurable_children.size", + "configurable_children.id", + "configurable_children.tier_prices", + "configurable_children.special_to_date", + "configurable_children.special_from_date", + "configurable_children.regular_price", + "configurable_children.final_price", + "final_price", + "id", + "image", + "name", + "new", + "original_price", + "original_price_incl_tax", + "price", + "price_incl_tax", + "product_links", + "sale", + "sku", + "special_price", + "special_price_incl_tax", + "special_from_date", + "special_to_date", + "status", + "tax_class_id", + "tier_prices", + "type_id", + "url_path", + "url_key" + ], + "excludeFields": [ + "description", + "sgn", + "*.sgn", + "msrp_display_actual_price_type", + "*.msrp_display_actual_price_type", + "required_options" + ] }, "review": { - "excludeFields": ["review_entity", "review_status"] + "excludeFields": [ + "review_entity", + "review_status" + ] }, "product": { - "excludeFields": [ "*.msrp_display_actual_price_type", "required_options", "updated_at", "created_at", "attribute_set_id", "options_container", "msrp_display_actual_price_type", "has_options", "stock.manage_stock", "stock.use_config_min_qty", "stock.use_config_notify_stock_qty", "stock.stock_id", "stock.use_config_backorders", "stock.use_config_enable_qty_inc", "stock.enable_qty_increments", "stock.use_config_manage_stock", "stock.use_config_min_sale_qty", "stock.notify_stock_qty", "stock.use_config_max_sale_qty", "stock.use_config_max_sale_qty", "stock.qty_increments", "stock.stock_status_changed_auto", "stock.show_default_notification_message", "stock.use_config_qty_increments", "stock.is_decimal_divided", "small_image", "sgn", "*.sgn"], + "excludeFields": [ + "attribute_set_id", + "created_at", + "has_options", + "msrp_display_actual_price_type", + "*.msrp_display_actual_price_type", + "options_container", + "required_options", + "small_image", + "stock.enable_qty_increments", + "stock.is_decimal_divided", + "stock.manage_stock", + "stock.notify_stock_qty", + "stock.qty_increments", + "stock.show_default_notification_message", + "stock.stock_id", + "stock.stock_status_changed_auto", + "stock.use_config_qty_increments", + "stock.use_config_min_qty", + "stock.use_config_notify_stock_qty", + "stock.use_config_backorders", + "stock.use_config_enable_qty_inc", + "stock.use_config_manage_stock", + "stock.use_config_min_sale_qty", + "stock.use_config_max_sale_qty", + "sgn", + "*.sgn", + "updated_at" + ], "includeFields": null, "useDynamicAttributeLoader": true, "standardSystemFields": [ - "description", + "category", + "category_ids", + "color_options", + "configurable_children", "configurable_options", - "tsk", "custom_attributes", - "size_options", - "regular_price", + "custom_design_from", + "description", + "erin_recommends", + "errors", "final_price", "final_price_incl_tax", "final_price_tax", - "price", - "color_options", - "id", - "links", "gift_message_available", - "category_ids", - "sku", - "stock", + "id", "image", - "thumbnail", - "visibility", - "type_id", - "tax_class_id", - "media_gallery", - "url_key", - "url_path", + "info", + "is_configured", + "links", "max_price", + "max_regular_price", + "media_gallery", "minimal_regular_price", - "special_price", "minimal_price", "name", - "configurable_children", - "max_regular_price", - "category", - "status", - "price_tax", - "price_incl_tax", - "special_price_tax", - "special_price_incl_tax", - "_score", - "slug", - "errors", - "info", - "erin_recommends", - "special_from_date", "news_from_date", - "custom_design_from", "original_price", "original_price_incl_tax", - "parentSku", "options", + "parentSku", + "priceTax", + "priceInclTax", "product_option", + "price", + "price_incl_tax", + "price_tax", "qty", - "is_configured", - "priceInclTax", + "regular_price", + "size_options", + "sku", + "slug", "specialPriceInclTax", "specialPriceTax", - "priceTax", - "priceInclTax" + "special_price_tax", + "special_price_incl_tax", + "special_from_date", + "special_price", + "status", + "stock", + "_score", + "tax_class_id", + "thumbnail", + "tsk", + "type_id", + "url_key", + "url_path", + "visibility" ] } }, @@ -311,8 +533,15 @@ "waitForPlatformSync": false, "setupVariantByAttributeCode": true, "endpoint": "/api/product", - "defaultFilters": ["color", "size", "price", "erin_recommends"], - "systemFilterNames": ["sort"], + "defaultFilters": [ + "color", + "erin_recommends", + "price", + "size" + ], + "systemFilterNames": [ + "sort" + ], "maxFiltersQuerySize": 999, "routerFiltersSource": "query", "filterFieldMapping": { @@ -327,12 +556,16 @@ }, "sortByAttributes": { "Latest": "updated_at:desc", - "Price: Low to high":"final_price", - "Price: High to low":"final_price:desc" + "Price: Low to high": "final_price", + "Price: High to low": "final_price:desc" }, "gallery": { "mergeConfigurableChildren": true, - "imageAttributes": ["image","thumbnail","small_image"], + "imageAttributes": [ + "image", + "thumbnail", + "small_image" + ], "width": 600, "height": 744 }, @@ -362,9 +595,9 @@ }, "offline_orders": { "automatic_transmission_enabled": false, - "notification" : { + "notification": { "enabled": true, - "title" : "Order waiting!", + "title": "Order waiting!", "message": "Click here to confirm the order that you made offline.", "icon": "/assets/logo.png" } @@ -449,7 +682,9 @@ "i18n": { "defaultCountry": "US", "defaultLanguage": "EN", - "availableLocale": ["en-US"], + "availableLocale": [ + "en-US" + ], "defaultLocale": "en-US", "currencyCode": "USD", "currencySign": "$", @@ -483,7 +718,15 @@ "id": false, "debug": true, "product_attributes": [ - "name", "id", "sku", { "priceInclTax": "price" }, { "qty": "quantity" } + "name", + "id", + "sku", + { + "priceInclTax": "price" + }, + { + "qty": "quantity" + } ] }, "hotjar": { @@ -506,7 +749,7 @@ "filter": [ { "key": "category.name", - "value" : { "eq": "Performance Fabrics" } + "value": { "eq": "Performance Fabrics" } } ] }, @@ -514,7 +757,7 @@ "filter": [ { "key": "category.name", - "value" : { "eq": "Tees" } + "value": { "eq": "Tees" } } ] }, @@ -522,7 +765,7 @@ "filter": [ { "key": "category.name", - "value" : { "eq": "Tees" } + "value": { "eq": "Tees" } } ] } diff --git a/core/app.ts b/core/app.ts index 4e82eeac59..8dfb969e19 100755 --- a/core/app.ts +++ b/core/app.ts @@ -49,7 +49,7 @@ const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vu store.state.__DEMO_MODE__ = (config.demomode === true) if (ssrContext) { // @deprecated - we shouldn't share server context between requests - Vue.prototype.$ssrRequestContext = {output: {cacheTags: ssrContext.output.cacheTags}} + Vue.prototype.$ssrRequestContext = { output: { cacheTags: ssrContext.output.cacheTags } } Vue.prototype.$cacheTags = ssrContext.output.cacheTags } @@ -60,8 +60,10 @@ const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vu // @deprecated from 2.0 once('__VUE_EXTEND__', () => { Vue.use(Vuelidate) - Vue.use(VueLazyload, {attempt: 2, preLoad: 1.5}) - Vue.use(Meta) + Vue.use(VueLazyload, { attempt: 2, preLoad: 1.5 }) + Vue.use(Meta, { + ssrAppId: 1 + }) Vue.use(VueObserveVisibility) Object.keys(corePlugins).forEach(key => { @@ -85,7 +87,7 @@ const createApp = async (ssrContext, config, storeCode = null): Promise<{app: Vu } const apolloProvider = await getApolloProvider() - if (apolloProvider) Object.assign(vueOptions, {provider: apolloProvider}) + if (apolloProvider) Object.assign(vueOptions, { provider: apolloProvider }) const app = new Vue(vueOptions) diff --git a/core/client-entry.ts b/core/client-entry.ts index 4296766fa2..e197396125 100755 --- a/core/client-entry.ts +++ b/core/client-entry.ts @@ -90,7 +90,7 @@ const invokeClientEntry = async () => { const matched = router.getMatchedComponents(to) if (to) { // this is from url if (globalConfig.storeViews.multistore === true) { - const currentRoute = Object.assign({}, to, {host: window.location.host}) + const currentRoute = Object.assign({}, to, { host: window.location.host }) const storeCode = storeCodeFromRoute(currentRoute) const currentStore = currentStoreView() if (storeCode !== '' && storeCode !== null) { @@ -104,7 +104,7 @@ const invokeClientEntry = async () => { return next() } - store.dispatch('url/setCurrentRoute', {to, from}) + store.dispatch('url/setCurrentRoute', { to, from }) Promise.all(matched.map((c: any) => { // TODO: update me for mixins support const components = c.mixins && globalConfig.ssr.executeMixedinAsyncData ? Array.from(c.mixins) : [] diff --git a/core/data-resolver/CategoryService.ts b/core/data-resolver/CategoryService.ts index 8eed001af3..c1146f4882 100644 --- a/core/data-resolver/CategoryService.ts +++ b/core/data-resolver/CategoryService.ts @@ -18,30 +18,30 @@ const getCategories = async ({ }: DataResolver.CategorySearchOptions = {}): Promise => { let searchQuery = new SearchQuery() if (parentId) { - searchQuery = searchQuery.applyFilter({key: 'parent_id', value: {'eq': parentId}}) + searchQuery = searchQuery.applyFilter({ key: 'parent_id', value: { 'eq': parentId } }) } if (level) { - searchQuery = searchQuery.applyFilter({key: 'level', value: {'eq': level}}) + searchQuery = searchQuery.applyFilter({ key: 'level', value: { 'eq': level } }) } for (var [key, value] of Object.entries(filters)) { if (value !== null) { if (Array.isArray(value)) { - searchQuery = searchQuery.applyFilter({key: key, value: {'in': value}}) + searchQuery = searchQuery.applyFilter({ key: key, value: { 'in': value } }) } else if (typeof value === 'object') { - searchQuery = searchQuery.applyFilter({key: key, value: value}) + searchQuery = searchQuery.applyFilter({ key: key, value: value }) } else { - searchQuery = searchQuery.applyFilter({key: key, value: {'eq': value}}) + searchQuery = searchQuery.applyFilter({ key: key, value: { 'eq': value } }) } } } if (onlyActive === true) { - searchQuery = searchQuery.applyFilter({key: 'is_active', value: {'eq': true}}) + searchQuery = searchQuery.applyFilter({ key: 'is_active', value: { 'eq': true } }) } if (onlyNotEmpty === true) { - searchQuery = searchQuery.applyFilter({key: 'product_count', value: {'gt': 0}}) + searchQuery = searchQuery.applyFilter({ key: 'product_count', value: { 'gt': 0 } }) } const response = await quickSearchByQuery({ entityType: 'category', query: searchQuery, sort: sort, size: size, start: start, includeFields: includeFields, excludeFields: excludeFields }) return response.items as Category[] diff --git a/core/helpers/index.ts b/core/helpers/index.ts index 1d69132b2f..10df4ce9d2 100644 --- a/core/helpers/index.ts +++ b/core/helpers/index.ts @@ -7,6 +7,7 @@ import { sha3_224 } from 'js-sha3' import store from '@vue-storefront/core/store' import { adjustMultistoreApiUrl } from '@vue-storefront/core/lib/multistore' import { coreHooksExecutors } from '@vue-storefront/core/hooks'; +import omit from 'lodash-es/omit' export const processURLAddress = (url: string = '') => { if (url.startsWith('/')) return `${config.api.url}${url}` @@ -114,15 +115,15 @@ export function productThumbnailPath (product, ignoreConfig = false) { export function baseFilterProductsQuery (parentCategory, filters = []) { // TODO add aggregation of color_options and size_options fields let searchProductQuery = new SearchQuery() searchProductQuery = searchProductQuery - .applyFilter({key: 'visibility', value: {'in': [2, 3, 4]}}) - .applyFilter({key: 'status', value: {'in': [0, 1]}}) /* 2 = disabled, 4 = out of stock */ + .applyFilter({ key: 'visibility', value: { 'in': [2, 3, 4] } }) + .applyFilter({ key: 'status', value: { 'in': [0, 1] } }) /* 2 = disabled, 4 = out of stock */ if (config.products.listOutOfStockProducts === false) { - searchProductQuery = searchProductQuery.applyFilter({key: 'stock.is_in_stock', value: {'eq': true}}) + searchProductQuery = searchProductQuery.applyFilter({ key: 'stock.is_in_stock', value: { 'eq': true } }) } // Add available catalog filters for (let attrToFilter of filters) { - searchProductQuery = searchProductQuery.addAvailableFilter({field: attrToFilter, scope: 'catalog'}) + searchProductQuery = searchProductQuery.addAvailableFilter({ field: attrToFilter, scope: 'catalog' }) } let childCats = [parentCategory.id] @@ -145,7 +146,7 @@ export function baseFilterProductsQuery (parentCategory, filters = []) { // TODO } recurCatFinderBuilder(parentCategory) } - searchProductQuery = searchProductQuery.applyFilter({key: 'category_ids', value: {'in': childCats}}) + searchProductQuery = searchProductQuery.applyFilter({ key: 'category_ids', value: { 'in': childCats } }) return searchProductQuery } @@ -159,9 +160,9 @@ export function buildFilterProductsQuery (currentCategory, chosenFilters = {}, d if (Array.isArray(filter) && attributeCode !== 'price') { const values = filter.map(filter => filter.id) - filterQr = filterQr.applyFilter({key: attributeCode, value: {'in': values}, scope: 'catalog'}) + filterQr = filterQr.applyFilter({ key: attributeCode, value: { 'in': values }, scope: 'catalog' }) } else if (attributeCode !== 'price') { - filterQr = filterQr.applyFilter({key: attributeCode, value: {'eq': filter.id}, scope: 'catalog'}) + filterQr = filterQr.applyFilter({ key: attributeCode, value: { 'eq': filter.id }, scope: 'catalog' }) } else { // multi should be possible filter here? const rangeqr = {} const filterValues = Array.isArray(filter) ? filter : [filter] @@ -169,7 +170,7 @@ export function buildFilterProductsQuery (currentCategory, chosenFilters = {}, d if (singleFilter.from) rangeqr['gte'] = singleFilter.from if (singleFilter.to) rangeqr['lte'] = singleFilter.to }) - filterQr = filterQr.applyFilter({key: attributeCode, value: rangeqr, scope: 'catalog'}) + filterQr = filterQr.applyFilter({ key: attributeCode, value: rangeqr, scope: 'catalog' }) } } @@ -200,6 +201,9 @@ export const routerHelper = Vue.observable({ !isServer && window.addEventListener('online', () => { onlineHelper.isOnline = true }) !isServer && window.addEventListener('offline', () => { onlineHelper.isOnline = false }) !isServer && window.addEventListener('popstate', () => { routerHelper.popStateDetected = true }) +if (!isServer && 'scrollRestoration' in history) { + history.scrollRestoration = 'manual' +} /* * serial executes Promises sequentially. @@ -219,8 +223,13 @@ export const serial = async promises => { } // helper to calculate the hash of the shopping cart -export const calcItemsHmac = (items, token) => { - return sha3_224(JSON.stringify({ items, token: token })) +export const calcItemsHmac = (items = [], token) => { + return sha3_224(JSON.stringify({ + // we need to omit those properties because they are loaded async and added to product data + // and they are not needed to compare products + items: items.map(item => omit(item, ['stock', 'totals'])), + token: token + })) } export function extendStore (moduleName: string | string[], module: any) { diff --git a/core/helpers/router.ts b/core/helpers/router.ts index 5163a2f690..331beb48cf 100644 --- a/core/helpers/router.ts +++ b/core/helpers/router.ts @@ -1,3 +1,4 @@ +import rootStore from '@vue-storefront/core/store'; import VueRouter, { RouteConfig } from 'vue-router' import { RouterManager } from '@vue-storefront/core/lib/router-manager' import { ErrorHandler, RawLocation, Route } from 'vue-router/types/router' @@ -15,14 +16,15 @@ export const createRouter = (): VueRouter => { return new VueRouter({ mode: 'history', base: __dirname, - scrollBehavior: (to, from, savedPosition) => { + scrollBehavior: (to, from) => { if (to.hash) { return { selector: to.hash } } - if (savedPosition) { - return savedPosition + if (rootStore.getters['url/isBackRoute']) { + const { scrollPosition = { x: 0, y: 0 } } = rootStore.getters['url/getCurrentRoute'] + return scrollPosition } else if (to.path !== from.path) { // do not change scroll position when navigating on the same page (ex. change filters) return { x: 0, y: 0 } } diff --git a/core/i18n/package.json b/core/i18n/package.json index 3006d375ba..af4ce35a14 100644 --- a/core/i18n/package.json +++ b/core/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@vue-storefront/i18n", - "version": "1.11.2", + "version": "1.11.3", "description": "Vue Storefront i18n", "license": "MIT", "main": "index.ts", diff --git a/core/lib/logger.ts b/core/lib/logger.ts index 96781758db..588e7c987f 100644 --- a/core/lib/logger.ts +++ b/core/lib/logger.ts @@ -171,4 +171,4 @@ const logger = new Logger( buildTimeConfig.console.showErrorOnProduction ) -export {logger as Logger} +export { logger as Logger } diff --git a/core/lib/multistore.ts b/core/lib/multistore.ts index 354ead2751..cd163375e6 100644 --- a/core/lib/multistore.ts +++ b/core/lib/multistore.ts @@ -164,6 +164,42 @@ export function localizedDispatcherRouteName (routeName: string, storeCode: stri return routeName } +/** + * Returns route path with proper language prefix + * @param path - route path + * @param storeCode - language prefix specified in global config + */ +export function localizedRoutePath (path: string, storeCode: string): string { + const _path = path.startsWith('/') ? path.slice(1) : path + + return `/${storeCode}/${_path}` +} + +/** + * Returns transformed route config with language + * @param route - route config object + * @param storeCode - language prefix specified in global config + * @param isChildRoute - determines if route config is for child route + */ +export function localizedRouteConfig (route: RouteConfig, storeCode: string, isChildRoute: boolean = false): RouteConfig { + // note: we need shallow copy to prevent modifications in provided route object + const _route = { ...route } + + if (_route.name && storeCode) { + _route.name = `${storeCode}-${_route.name}` + } + + if (_route.path && !isChildRoute) { + _route.path = localizedRoutePath(_route.path, storeCode) + } + + if (_route.children) { + _route.children = _route.children.map(childRoute => localizedRouteConfig(childRoute, storeCode, true)) + } + + return _route +} + export function localizedRoute (routeObj: LocalizedRoute | string | RouteConfig | RawLocation, storeCode: string = null): any { if (!storeCode) { storeCode = currentStoreView().storeCode @@ -198,39 +234,3 @@ export function setupMultistoreRoutes (config, router: VueRouter, routes: RouteC } router.addRoutes(allRoutes, true, priority) } - -/** - * Returns transformed route config with language - * @param route - route config object - * @param storeCode - language prefix specified in global config - * @param isChildRoute - determines if route config is for child route - */ -export function localizedRouteConfig (route: RouteConfig, storeCode: string, isChildRoute: boolean = false): RouteConfig { - // note: we need shallow copy to prevent modifications in provided route object - const _route = {...route} - - if (_route.name && storeCode) { - _route.name = `${storeCode}-${_route.name}` - } - - if (_route.path && !isChildRoute) { - _route.path = localizedRoutePath(_route.path, storeCode) - } - - if (_route.children) { - _route.children = _route.children.map(childRoute => localizedRouteConfig(childRoute, storeCode, true)) - } - - return _route -} - -/** - * Returns route path with proper language prefix - * @param path - route path - * @param storeCode - language prefix specified in global config - */ -export function localizedRoutePath (path: string, storeCode: string): string { - const _path = path.startsWith('/') ? path.slice(1) : path - - return `/${storeCode}/${_path}` -} diff --git a/core/lib/search/adapter/api/elasticsearch/score.js b/core/lib/search/adapter/api/elasticsearch/score.js index 4ddb8974b3..c3d0b2a049 100644 --- a/core/lib/search/adapter/api/elasticsearch/score.js +++ b/core/lib/search/adapter/api/elasticsearch/score.js @@ -23,7 +23,7 @@ export default function getFunctionScores () { } } if (filter.length) { - return {'functions': filter, + return { 'functions': filter, 'score_mode': config.score_mode ? config.score_mode : 'multiply', 'boost_mode': config.boost_mode ? config.boost_mode : 'multiply', 'max_boost': config.max_boost ? config.max_boost : 100, diff --git a/core/lib/search/adapter/api/elasticsearchQuery.js b/core/lib/search/adapter/api/elasticsearchQuery.js index 3ba4e1081e..fbcf64eb4e 100644 --- a/core/lib/search/adapter/api/elasticsearchQuery.js +++ b/core/lib/search/adapter/api/elasticsearchQuery.js @@ -91,7 +91,7 @@ export async function prepareElasticsearchQueryBody (searchQuery) { } // Get searchable fields based on user-defined config. let getQueryBody = function (b) { - let searchableAttributes = config.elasticsearch.hasOwnProperty('searchableAttributes') ? config.elasticsearch.searchableAttributes : {'name': {'boost': 1}} + let searchableAttributes = config.elasticsearch.hasOwnProperty('searchableAttributes') ? config.elasticsearch.searchableAttributes : { 'name': { 'boost': 1 } } let searchableFields = [ ] for (const attribute of Object.keys(searchableAttributes)) { diff --git a/core/lib/search/adapter/api/searchAdapter.ts b/core/lib/search/adapter/api/searchAdapter.ts index d5c1ed683a..c64fe343f3 100644 --- a/core/lib/search/adapter/api/searchAdapter.ts +++ b/core/lib/search/adapter/api/searchAdapter.ts @@ -1,9 +1,9 @@ import map from 'lodash-es/map' -import { prepareElasticsearchQueryBody } from './elasticsearchQuery' +import { prepareElasticsearchQueryBody } from '@vue-storefront/core/lib/search/adapter/api/elasticsearchQuery' import fetch from 'isomorphic-fetch' import { slugify, processURLAddress } from '@vue-storefront/core/helpers' import queryString from 'query-string' -import { currentStoreView, prepareStoreView } from '../../../multistore' +import { currentStoreView, prepareStoreView } from '@vue-storefront/core/lib/multistore' import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' import HttpQuery from '@vue-storefront/core/types/search/HttpQuery' import { SearchResponse } from '@vue-storefront/core/types/search/SearchResponse' diff --git a/core/lib/search/adapter/graphql/searchAdapter.ts b/core/lib/search/adapter/graphql/searchAdapter.ts index 099cd7c846..56dfb495a1 100644 --- a/core/lib/search/adapter/graphql/searchAdapter.ts +++ b/core/lib/search/adapter/graphql/searchAdapter.ts @@ -1,7 +1,7 @@ import { prepareQueryVars } from './gqlQuery' import { currentStoreView, prepareStoreView } from '../../../multistore' import fetch from 'isomorphic-fetch' -import {processESResponseType, processProductsType, processCmsType} from './processor/processType' +import { processESResponseType, processProductsType, processCmsType } from './processor/processType' import SearchQuery from '../../searchQuery' import config from 'config' diff --git a/core/lib/search/adapter/test/unit/searchAdapterFactory.spec.ts b/core/lib/search/adapter/test/unit/searchAdapterFactory.spec.ts index 749856d716..9ffbb54f5b 100644 --- a/core/lib/search/adapter/test/unit/searchAdapterFactory.spec.ts +++ b/core/lib/search/adapter/test/unit/searchAdapterFactory.spec.ts @@ -1,7 +1,7 @@ -import {getSearchAdapter} from '@vue-storefront/core/lib/search/adapter/searchAdapterFactory' +import { getSearchAdapter } from '@vue-storefront/core/lib/search/adapter/searchAdapterFactory' jest.mock('config', () => { - return {server: {api: 'api'}}; + return { server: { api: 'api' } }; }); jest.mock('@vue-storefront/core/lib/logger', () => ({ Logger: { @@ -40,7 +40,7 @@ describe('Search adapter factory tests', () => { () => { return {}; }, - {virtual: true} + { virtual: true } ) await expect(getSearchAdapter('virtual')).rejects.toThrowError(new Error('Search adapter class is not provided')) @@ -60,7 +60,7 @@ describe('Search adapter factory tests', () => { }) } }, - {virtual: true} + { virtual: true } ) await expect(getSearchAdapter('invalidSearchMethod')) @@ -83,7 +83,7 @@ describe('Search adapter factory tests', () => { }) } }, - {virtual: true} + { virtual: true } ) await expect(getSearchAdapter('invalidRegisterEntityTypeMethod')) diff --git a/core/lib/search/searchQuery.js b/core/lib/search/searchQuery.js index 27ea8dfd5c..8eec238a8b 100644 --- a/core/lib/search/searchQuery.js +++ b/core/lib/search/searchQuery.js @@ -32,7 +32,7 @@ class SearchQuery { * @param {Object} * @return {Object} */ - applyFilter ({key, value, scope = 'default', options = Object}) { + applyFilter ({ key, value, scope = 'default', options = Object }) { this._appliedFilters.push({ attribute: key, value: value, @@ -47,7 +47,7 @@ class SearchQuery { * @param {Object} * @return {Object} */ - addAvailableFilter ({field, scope = 'default', options = {}}) { + addAvailableFilter ({ field, scope = 'default', options = {} }) { // value can has only String, Array or numeric type this._availableFilters.push({ field: field, diff --git a/core/lib/test/unit/logger.spec.ts b/core/lib/test/unit/logger.spec.ts index f231fcf0ad..6713f7a1ad 100644 --- a/core/lib/test/unit/logger.spec.ts +++ b/core/lib/test/unit/logger.spec.ts @@ -43,7 +43,7 @@ describe('Logger', () => { jest.isolateModules(() => { const Logger = require('../../logger').Logger - expect(Logger.convertToString({foo: 'bar'})).toBe('{"foo":"bar"}') + expect(Logger.convertToString({ foo: 'bar' })).toBe('{"foo":"bar"}') }) }) @@ -51,7 +51,7 @@ describe('Logger', () => { jest.isolateModules(() => { const Logger = require('../../logger').Logger - expect(Logger.convertToString({message: 'foo'})).toBe('foo') + expect(Logger.convertToString({ message: 'foo' })).toBe('foo') }) }) it('returns primitive payloads unchanged', () => { diff --git a/core/lib/test/unit/multistore.spec.ts b/core/lib/test/unit/multistore.spec.ts index 91ce20566a..d2cf2b2f2b 100644 --- a/core/lib/test/unit/multistore.spec.ts +++ b/core/lib/test/unit/multistore.spec.ts @@ -20,12 +20,12 @@ jest.mock('@vue-storefront/core/app', () => ({ } })) jest.mock('../../../store', () => ({})) -jest.mock('@vue-storefront/i18n', () => ({loadLanguageAsync: jest.fn()})) -jest.mock('../../sync/task', () => ({initializeSyncTaskStorage: jest.fn()})) +jest.mock('@vue-storefront/i18n', () => ({ loadLanguageAsync: jest.fn() })) +jest.mock('../../sync/task', () => ({ initializeSyncTaskStorage: jest.fn() })) jest.mock('@vue-storefront/core/hooks', () => ({ coreHooksExecutors: { beforeStoreViewChanged: jest.fn(args => args), afterStoreViewChanged: jest.fn(args => args) -}})) +} })) jest.mock('@vue-storefront/core/lib/logger', () => ({ Logger: {} })) diff --git a/core/modules/breadcrumbs/index.ts b/core/modules/breadcrumbs/index.ts index 5243571e58..fbf2320cb0 100644 --- a/core/modules/breadcrumbs/index.ts +++ b/core/modules/breadcrumbs/index.ts @@ -1,6 +1,6 @@ import { breadcrumbsStore } from './store' import { StorefrontModule } from '@vue-storefront/core/lib/modules' -export const BreadcrumbsModule: StorefrontModule = function ({store}) { +export const BreadcrumbsModule: StorefrontModule = function ({ store }) { store.registerModule('breadcrumbs', breadcrumbsStore) } diff --git a/core/modules/breadcrumbs/test/unit/parseCategoryPath.spec.ts b/core/modules/breadcrumbs/test/unit/parseCategoryPath.spec.ts index 2fb7119ca0..7e357c8e2c 100644 --- a/core/modules/breadcrumbs/test/unit/parseCategoryPath.spec.ts +++ b/core/modules/breadcrumbs/test/unit/parseCategoryPath.spec.ts @@ -19,7 +19,7 @@ describe('parseCategoryPath method', () => { beforeEach(() => { jest.clearAllMocks(); - (currentStoreView as jest.Mock).mockImplementation(() => ({storeCode: ''})); + (currentStoreView as jest.Mock).mockImplementation(() => ({ storeCode: '' })); categories = [ { path: '1/2', @@ -90,7 +90,7 @@ describe('parseCategoryPath method', () => { beforeEach(() => { jest.clearAllMocks(); - (currentStoreView as jest.Mock).mockImplementation(() => ({storeCode: ''})); + (currentStoreView as jest.Mock).mockImplementation(() => ({ storeCode: '' })); categories = [ { path: '1/2', diff --git a/core/modules/cart/helpers/productChecksum.ts b/core/modules/cart/helpers/productChecksum.ts index 21c27ae3a1..4798da845f 100644 --- a/core/modules/cart/helpers/productChecksum.ts +++ b/core/modules/cart/helpers/productChecksum.ts @@ -6,10 +6,11 @@ import cloneDeep from 'lodash-es/cloneDeep'; const replaceNumberToString = obj => { Object.keys(obj).forEach(key => { - if (typeof obj[key] === 'object') { + if (obj[key] !== null && typeof obj[key] === 'object') { return replaceNumberToString(obj[key]); + } else if (typeof obj[key] === 'number') { + obj[key] = String(obj[key]); } - obj[key] = String(obj[key]); }); return obj; } diff --git a/core/modules/cart/helpers/syncCartWhenLocalStorageChange.ts b/core/modules/cart/helpers/syncCartWhenLocalStorageChange.ts index e8fa004461..ee82c996de 100644 --- a/core/modules/cart/helpers/syncCartWhenLocalStorageChange.ts +++ b/core/modules/cart/helpers/syncCartWhenLocalStorageChange.ts @@ -1,9 +1,9 @@ import rootStore from '@vue-storefront/core/store'; -function getItemsFromStorage ({key}) { +function getItemsFromStorage ({ key }) { if (key === 'shop/cart/current-cart') { const storedItems = JSON.parse(localStorage[key]) - rootStore.dispatch('cart/syncCartWhenLocalStorageChange', {items: storedItems}) + rootStore.dispatch('cart/syncCartWhenLocalStorageChange', { items: storedItems }) } } diff --git a/core/modules/cart/index.ts b/core/modules/cart/index.ts index 788cd316b6..edb536a488 100644 --- a/core/modules/cart/index.ts +++ b/core/modules/cart/index.ts @@ -5,7 +5,7 @@ import { isServer } from '@vue-storefront/core/helpers' import Vue from 'vue' import { StorageManager } from '@vue-storefront/core/lib/storage-manager' -export const CartModule: StorefrontModule = function ({store}) { +export const CartModule: StorefrontModule = function ({ store }) { StorageManager.init('cart') store.registerModule('cart', cartStore) diff --git a/core/modules/cart/store/actions/connectActions.ts b/core/modules/cart/store/actions/connectActions.ts index 03d91d252e..9b0ce22df7 100644 --- a/core/modules/cart/store/actions/connectActions.ts +++ b/core/modules/cart/store/actions/connectActions.ts @@ -69,7 +69,7 @@ const connectActions = { const cartToken = getters['getCartToken'] if (storedItems.length && !cartToken) { Logger.info('Creating server cart token', 'cart')() - await dispatch('connect', { guestCart: false }) + return dispatch('connect', { guestCart: false }) } } } diff --git a/core/modules/cart/store/actions/couponActions.ts b/core/modules/cart/store/actions/couponActions.ts index 1cebd576ea..cdb7005f09 100644 --- a/core/modules/cart/store/actions/couponActions.ts +++ b/core/modules/cart/store/actions/couponActions.ts @@ -1,22 +1,31 @@ import { CartService } from '@vue-storefront/core/data-resolver' +import * as types from '@vue-storefront/core/modules/cart/store/mutation-types' const couponActions = { - async removeCoupon ({ getters, dispatch }, { sync = true } = {}) { + async removeCoupon ({ getters, dispatch, commit }, { sync = true } = {}) { if (getters.canSyncTotals) { const { result } = await CartService.removeCoupon() if (result && sync) { await dispatch('syncTotals', { forceServerSync: true }) + + // 'getCurrentCartHash' has been changed (it's based on cart items data) + // so we need to update it in vuex and StorageManager + commit(types.CART_SET_ITEMS_HASH, getters.getCurrentCartHash) return result } } }, - async applyCoupon ({ getters, dispatch }, couponCode) { + async applyCoupon ({ getters, dispatch, commit }, couponCode) { if (couponCode && getters.canSyncTotals) { const { result } = await CartService.applyCoupon(couponCode) if (result) { await dispatch('syncTotals', { forceServerSync: true }) + + // 'getCurrentCartHash' has been changed (it's based on cart items data) + // so we need to update it in vuex and StorageManager + commit(types.CART_SET_ITEMS_HASH, getters.getCurrentCartHash) } return result } diff --git a/core/modules/cart/store/actions/itemActions.ts b/core/modules/cart/store/actions/itemActions.ts index b658494d5b..fcaf2d6ddb 100644 --- a/core/modules/cart/store/actions/itemActions.ts +++ b/core/modules/cart/store/actions/itemActions.ts @@ -50,7 +50,7 @@ const itemActions = { const record = getters.getCartItems.find(p => productsEquals(p, product)) const qty = record ? record.qty + 1 : (product.qty ? product.qty : 1) - return dispatch('stock/queueCheck', { product, qty }, {root: true}) + return dispatch('stock/queueCheck', { product, qty }, { root: true }) }, async addItems ({ commit, dispatch, getters }, { productsToAdd, forceServerSilence = false }) { let productIndex = 0 @@ -80,9 +80,18 @@ const itemActions = { productIndex++ } } - await dispatch('create') + + let newDiffLog = await dispatch('create') + if (newDiffLog !== undefined) { + diffLog.merge(newDiffLog) + } + if (getters.isCartSyncEnabled && getters.isCartConnected && !forceServerSilence) { - return dispatch('sync', { forceClientState: true }) + const syncDiffLog = await dispatch('sync', { forceClientState: true }) + + if (!syncDiffLog.isEmpty()) { + diffLog.merge(syncDiffLog) + } } return diffLog diff --git a/core/modules/cart/store/actions/methodsActions.ts b/core/modules/cart/store/actions/methodsActions.ts index 5eb415925d..e839481dd3 100644 --- a/core/modules/cart/store/actions/methodsActions.ts +++ b/core/modules/cart/store/actions/methodsActions.ts @@ -60,10 +60,10 @@ const methodsActions = { } }, async updateShippingMethods ({ dispatch }, { shippingMethods }) { - if (shippingMethods.length > 0) { - const newShippingMethods = shippingMethods.map(method => ({ ...method, is_server_method: true })) - await dispatch('checkout/replaceShippingMethods', newShippingMethods, { root: true }) - } + const newShippingMethods = shippingMethods + .map(method => ({ ...method, is_server_method: true })) + .filter(method => !method.hasOwnProperty('available') || method.available) + await dispatch('checkout/replaceShippingMethods', newShippingMethods, { root: true }) }, async syncShippingMethods ({ getters, rootGetters, dispatch }, { forceServerSync = false }) { if (getters.canUpdateMethods && (getters.isTotalsSyncRequired || forceServerSync)) { @@ -80,7 +80,7 @@ const methodsActions = { postcode: shippingDetails.zipCode, city: shippingDetails.city, region_code: shippingDetails.region_code ? shippingDetails.region_code : '' - } : {country_id: storeView.tax.defaultCountry} + } : { country_id: storeView.tax.defaultCountry } const { result } = await CartService.getShippingMethods(address) await dispatch('updateShippingMethods', { shippingMethods: result }) diff --git a/core/modules/cart/store/actions/productActions.ts b/core/modules/cart/store/actions/productActions.ts index b698c6438f..f3f4ec28d9 100644 --- a/core/modules/cart/store/actions/productActions.ts +++ b/core/modules/cart/store/actions/productActions.ts @@ -4,7 +4,7 @@ const productActions = { async findProductOption ({ dispatch }, { serverItem }) { if (serverItem.product_type === 'configurable') { let query = new SearchQuery() - query = query.applyFilter({key: 'configurable_children.sku', value: {'eq': serverItem.sku}}) + 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 }) diff --git a/core/modules/cart/store/actions/synchronizeActions.ts b/core/modules/cart/store/actions/synchronizeActions.ts index cf4b8b4773..eb625f634f 100644 --- a/core/modules/cart/store/actions/synchronizeActions.ts +++ b/core/modules/cart/store/actions/synchronizeActions.ts @@ -20,7 +20,7 @@ const synchronizeActions = { cartHooksExecutors.afterLoad(storedItems) }, - syncCartWhenLocalStorageChange ({commit}, {items}) { + syncCartWhenLocalStorageChange ({ commit }, { items }) { commit(types.CART_LOAD_CART, items) }, async synchronizeCart ({ commit, dispatch }, { forceClientState }) { diff --git a/core/modules/cart/test/unit/components/AddToCart.spec.ts b/core/modules/cart/test/unit/components/AddToCart.spec.ts index 1bd6397015..a09a411320 100644 --- a/core/modules/cart/test/unit/components/AddToCart.spec.ts +++ b/core/modules/cart/test/unit/components/AddToCart.spec.ts @@ -10,7 +10,7 @@ jest.mock('@vue-storefront/core/lib/logger', () => ({ } })); jest.mock('@vue-storefront/core/app', () => ({ createApp: jest.fn() })) -jest.mock('@vue-storefront/i18n', () => ({loadLanguageAsync: jest.fn()})) +jest.mock('@vue-storefront/i18n', () => ({ loadLanguageAsync: jest.fn() })) jest.mock('@vue-storefront/core/helpers', () => ({ once: jest.fn() })); diff --git a/core/modules/cart/test/unit/components/Product.spec.ts b/core/modules/cart/test/unit/components/Product.spec.ts index 220d5528d6..10dff6749d 100644 --- a/core/modules/cart/test/unit/components/Product.spec.ts +++ b/core/modules/cart/test/unit/components/Product.spec.ts @@ -1,4 +1,4 @@ -import {mountMixin, mountMixinWithStore} from '@vue-storefront/unit-tests/utils'; +import { mountMixin, mountMixinWithStore } from '@vue-storefront/unit-tests/utils'; import Product from '@vue-storefront/core/modules/catalog/types/Product'; import { productThumbnailPath, getThumbnailPath } from '@vue-storefront/core/helpers'; import config from 'config' diff --git a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts index 33aaee0d74..c53ee9c6e9 100644 --- a/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts +++ b/core/modules/cart/test/unit/helpers/cartCacheHandler.spec.ts @@ -13,12 +13,12 @@ const StorageManager = { }; const cartCacheHandlerFactory = require('../../../helpers/cartCacheHandler').cartCacheHandlerFactory -jest.mock('@vue-storefront/core/lib/storage-manager', () => ({StorageManager})) +jest.mock('@vue-storefront/core/lib/storage-manager', () => ({ StorageManager })) jest.mock('@vue-storefront/core/helpers', () => ({ isServer: () => false })); jest.mock('@vue-storefront/core/app', () => ({ createApp: jest.fn() })) -jest.mock('@vue-storefront/i18n', () => ({loadLanguageAsync: jest.fn()})) +jest.mock('@vue-storefront/i18n', () => ({ loadLanguageAsync: jest.fn() })) Vue.use(Vuex); diff --git a/core/modules/cart/test/unit/store/connectActions.spec.ts b/core/modules/cart/test/unit/store/connectActions.spec.ts index fe248332ba..4679d9a9b7 100644 --- a/core/modules/cart/test/unit/store/connectActions.spec.ts +++ b/core/modules/cart/test/unit/store/connectActions.spec.ts @@ -27,7 +27,7 @@ jest.mock('@vue-storefront/core/lib/logger', () => ({ })); jest.mock('@vue-storefront/core/data-resolver', () => ({ CartService: { getCartToken: jest.fn() -}})); +} })); jest.mock('@vue-storefront/core/lib/storage-manager', () => ({ StorageManager: { get: jest.fn() @@ -168,14 +168,14 @@ describe('Cart connectActions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: { getCartItems: [{id: 1}], getCartToken: '' } + getters: { getCartItems: [{ id: 1 }], getCartToken: '' } }; const wrapper = (actions: any) => actions.create(contextMock); await wrapper(cartActions); - expect(contextMock.dispatch).toBeCalledWith('connect', {guestCart: false}); + expect(contextMock.dispatch).toBeCalledWith('connect', { guestCart: false }); }) it('doesn\'t create cart token when there are NO products in cart', async () => { const contextMock = { @@ -194,7 +194,7 @@ describe('Cart connectActions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: { getCartItems: [{id: 1}], getCartToken: 'xyz' } + getters: { getCartItems: [{ id: 1 }], getCartToken: 'xyz' } }; const wrapper = (actions: any) => actions.create(contextMock); diff --git a/core/modules/cart/test/unit/store/couponActions.spec.ts b/core/modules/cart/test/unit/store/couponActions.spec.ts index 21adaca9d0..61a8d9922e 100644 --- a/core/modules/cart/test/unit/store/couponActions.spec.ts +++ b/core/modules/cart/test/unit/store/couponActions.spec.ts @@ -24,7 +24,7 @@ jest.mock('@vue-storefront/core/lib/logger', () => ({ jest.mock('@vue-storefront/core/data-resolver', () => ({ CartService: { applyCoupon: async () => ({ result: true }), removeCoupon: async () => ({ result: true }) -}})); +} })); jest.mock('@vue-storefront/core/lib/storage-manager', () => ({ StorageManager: { get: jest.fn() diff --git a/core/modules/cart/test/unit/store/getters.spec.ts b/core/modules/cart/test/unit/store/getters.spec.ts index 3eb4517109..5da051496a 100644 --- a/core/modules/cart/test/unit/store/getters.spec.ts +++ b/core/modules/cart/test/unit/store/getters.spec.ts @@ -26,21 +26,21 @@ describe('Cart getters', () => { it('totals returns platform total segments if they has been saved in store and client is online', () => { const stateMock = { platformTotalSegments: [ - {'code': 'subtotal', 'title': 'Subtotal', 'value': 39.36}, - {'code': 'shipping', 'title': 'Shipping & Handling (Flat Rate - Fixed)', 'value': 5}, - {'code': 'discount', 'title': 'Discount', 'value': -4.8}, - {'code': 'tax', + { 'code': 'subtotal', 'title': 'Subtotal', 'value': 39.36 }, + { 'code': 'shipping', 'title': 'Shipping & Handling (Flat Rate - Fixed)', 'value': 5 }, + { 'code': 'discount', 'title': 'Discount', 'value': -4.8 }, + { 'code': 'tax', 'title': 'Tax', 'value': 6.26, 'area': 'taxes', 'extension_attributes': { 'tax_grandtotal_details': [{ 'amount': 6.26, - 'rates': [{'percent': '23', 'title': 'VAT23-PL'}], + 'rates': [{ 'percent': '23', 'title': 'VAT23-PL' }], 'group_id': 1 }] - }}, - {'code': 'grand_total', 'title': 'Grand Total', 'value': 38.46, 'area': 'footer'} + } }, + { 'code': 'grand_total', 'title': 'Grand Total', 'value': 38.46, 'area': 'footer' } ] }; const wrapper = (getters: any) => getters.getTotals(stateMock, getters); @@ -52,8 +52,8 @@ describe('Cart getters', () => { nor additional prices`, () => { const stateMock = { cartItems: [ - {qty: 1, price_incl_tax: 1}, - {qty: 2, price_incl_tax: 2} + { qty: 1, price_incl_tax: 1 }, + { qty: 2, price_incl_tax: 2 } ] }; const wrapper = (getters: any) => getters.getTotals(stateMock, { @@ -63,8 +63,8 @@ describe('Cart getters', () => { }); expect(wrapper(cartGetters)).toEqual([ - {'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5}, - {'code': 'grand_total', 'title': 'Grand total', 'value': 5} + { 'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5 }, + { 'code': 'grand_total', 'title': 'Grand total', 'value': 5 } ]); }); @@ -72,12 +72,12 @@ describe('Cart getters', () => { isOnlineSpy.mockReturnValueOnce(false); const stateMock = { platformTotalSegments: [ - {'code': 'subtotal', 'title': 'Subtotal', 'value': 39.36}, - {'code': 'shipping', 'title': 'Shipping & Handling (Flat Rate - Fixed)', 'value': 5} + { 'code': 'subtotal', 'title': 'Subtotal', 'value': 39.36 }, + { 'code': 'shipping', 'title': 'Shipping & Handling (Flat Rate - Fixed)', 'value': 5 } ], cartItems: [ - {qty: 1, price_incl_tax: 1}, - {qty: 2, price_incl_tax: 2} + { qty: 1, price_incl_tax: 1 }, + { qty: 2, price_incl_tax: 2 } ] }; const wrapper = (getters: any) => getters.getTotals(stateMock, { @@ -87,8 +87,8 @@ describe('Cart getters', () => { }); expect(wrapper(cartGetters)).toEqual([ - {'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5}, - {'code': 'grand_total', 'title': 'Grand total', 'value': 5} + { 'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5 }, + { 'code': 'grand_total', 'title': 'Grand total', 'value': 5 } ]); }); @@ -96,8 +96,8 @@ describe('Cart getters', () => { but no platformTotalSegments`, () => { const stateMock = { cartItems: [ - {qty: 1, price_incl_tax: 1}, - {qty: 2, price_incl_tax: 2} + { qty: 1, price_incl_tax: 1 }, + { qty: 2, price_incl_tax: 2 } ], payment: { title: 'payment', @@ -115,10 +115,10 @@ describe('Cart getters', () => { }); expect(wrapper(cartGetters)).toEqual([ - {'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5}, - {'code': 'grand_total', 'title': 'Grand total', 'value': 21}, - {'code': 'payment', 'title': 'payment', 'value': 4}, - {'code': 'shipping', 'title': 'shipping', 'value': 8} + { 'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5 }, + { 'code': 'grand_total', 'title': 'Grand total', 'value': 21 }, + { 'code': 'payment', 'title': 'payment', 'value': 4 }, + { 'code': 'shipping', 'title': 'shipping', 'value': 8 } ]); }); @@ -126,8 +126,8 @@ describe('Cart getters', () => { but no platformTotalSegments`, () => { const stateMock = { cartItems: [ - {qty: 1, price_incl_tax: 1}, - {qty: 2, price_incl_tax: 2} + { qty: 1, price_incl_tax: 1 }, + { qty: 2, price_incl_tax: 2 } ], payment: [ { @@ -157,10 +157,10 @@ describe('Cart getters', () => { }); expect(wrapper(cartGetters)).toEqual([ - {'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5}, - {'code': 'grand_total', 'title': 'Grand total', 'value': 21}, - {'code': 'payment', 'title': 'payment', 'value': 4}, - {'code': 'shipping', 'title': 'shipping', 'value': 8} + { 'code': 'subtotal_incl_tax', 'title': 'Subtotal incl. tax', 'value': 5 }, + { 'code': 'grand_total', 'title': 'Grand total', 'value': 21 }, + { 'code': 'payment', 'title': 'payment', 'value': 4 }, + { 'code': 'shipping', 'title': 'shipping', 'value': 8 } ]); }); @@ -170,8 +170,8 @@ describe('Cart getters', () => { } const stateMock = { cartItems: [ - {qty: 1}, - {qty: 2} + { qty: 1 }, + { qty: 2 } ] }; @@ -187,8 +187,8 @@ describe('Cart getters', () => { const stateMock = { cartItems: [ - {qty: 1}, - {qty: 2} + { qty: 1 }, + { qty: 2 } ] }; @@ -222,8 +222,8 @@ describe('Cart getters', () => { it('isVirtualCart returns true given only virtual items in cart', () => { const stateMock = { cartItems: [ - {type_id: 'virtual'}, - {type_id: 'downloadable'} + { type_id: 'virtual' }, + { type_id: 'downloadable' } ] }; const wrapper = (getters: any) => getters.isVirtualCart(stateMock); @@ -234,8 +234,8 @@ describe('Cart getters', () => { it('isVirtualCart returns false given any non virtual items in cart', () => { const stateMock = { cartItems: [ - {type_id: 'virtual'}, - {type_id: 'definitely-not-virtual'} + { type_id: 'virtual' }, + { type_id: 'definitely-not-virtual' } ] }; const wrapper = (getters: any) => getters.isVirtualCart(stateMock); diff --git a/core/modules/cart/test/unit/store/itemActions.spec.ts b/core/modules/cart/test/unit/store/itemActions.spec.ts index 2dfffbea87..a68bd04443 100644 --- a/core/modules/cart/test/unit/store/itemActions.spec.ts +++ b/core/modules/cart/test/unit/store/itemActions.spec.ts @@ -27,7 +27,7 @@ jest.mock('@vue-storefront/core/lib/logger', () => ({ jest.mock('@vue-storefront/core/data-resolver', () => ({ CartService: { applyCoupon: async () => ({ result: true }), removeCoupon: async () => ({ result: true }) -}})); +} })); jest.mock('@vue-storefront/core/lib/storage-manager', () => ({ StorageManager: { get: jest.fn() @@ -46,7 +46,8 @@ jest.mock('@vue-storefront/core/modules/cart/helpers', () => ({ createNotifications: jest.fn() }, createDiffLog: () => ({ - pushNotifications: jest.fn() + pushNotifications: jest.fn(), + merge: jest.fn() }) })); jest.mock('@vue-storefront/core/helpers', () => ({ @@ -140,7 +141,12 @@ describe('Cart itemActions', () => { } }) - contextMock.dispatch.mockImplementationOnce(() => Promise.resolve({ status: 'ok', onlineCheckTaskId: 1 })) + // The third 'dispatch' call gets an instance of DiffLog class, which has the isEmpty() method. + // The return value of the second 'dispatch' call is not used at all, so it can be left empty. + contextMock.dispatch + .mockImplementationOnce(() => Promise.resolve({ status: 'ok', onlineCheckTaskId: 1 })) + .mockImplementationOnce(() => Promise.resolve({})) + .mockImplementationOnce(() => Promise.resolve({ isEmpty: () => { return true } })) await (cartActions as any).addItems(contextMock, { productsToAdd: [product] }) expect(contextMock.commit).toBeCalledWith(types.CART_ADD_ITEM, { product: { ...product, onlineStockCheckid: 1 } }) diff --git a/core/modules/cart/test/unit/store/methodsActions.spec.ts b/core/modules/cart/test/unit/store/methodsActions.spec.ts index 907410a941..3fa70c4ce4 100644 --- a/core/modules/cart/test/unit/store/methodsActions.spec.ts +++ b/core/modules/cart/test/unit/store/methodsActions.spec.ts @@ -159,4 +159,10 @@ describe('Cart methodsActions', () => { await (cartActions as any).updateShippingMethods(contextMock, { shippingMethods: [{ method: 1 }] }); expect(contextMock.dispatch).toBeCalledWith('checkout/replaceShippingMethods', [{ is_server_method: true, method: 1 }], { root: true }) }) + + it('doesn\'t add not available method', async () => { + const contextMock = createContextMock() + await (cartActions as any).updateShippingMethods(contextMock, { shippingMethods: [{ method: 1, available: false }] }); + expect(contextMock.dispatch).toBeCalledWith('checkout/replaceShippingMethods', [], { root: true }) + }) }); diff --git a/core/modules/cart/test/unit/store/mutations.spec.ts b/core/modules/cart/test/unit/store/mutations.spec.ts index 9eb2fc0941..fa21430147 100644 --- a/core/modules/cart/test/unit/store/mutations.spec.ts +++ b/core/modules/cart/test/unit/store/mutations.spec.ts @@ -114,7 +114,7 @@ describe('Cart mutations', () => { } ] } - const wrapper = (mutations: any) => mutations[types.CART_ADD_ITEM](stateMock, {product}) + const wrapper = (mutations: any) => mutations[types.CART_ADD_ITEM](stateMock, { product }) wrapper(cartMutations) @@ -138,7 +138,7 @@ describe('Cart mutations', () => { const wrapper = (mutations: any) => mutations[types.CART_DEL_ITEM]( stateMock, { - product: {sku: 'foo'}, + product: { sku: 'foo' }, removeByParentSku: false } ) @@ -151,7 +151,7 @@ describe('Cart mutations', () => { sku: 'foo' }] }) - expect(EventBus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-after-delete', { items: expectedState.cartItems }) expect(stateMock).toEqual(expectedState) }) @@ -170,7 +170,7 @@ describe('Cart mutations', () => { const wrapper = (mutations: any) => mutations[types.CART_DEL_ITEM]( stateMock, { - product: {parentSku: 'foo'} + product: { parentSku: 'foo' } } ) @@ -182,7 +182,7 @@ describe('Cart mutations', () => { sku: 'foo' }] }) - expect(EventBus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-after-delete', { items: expectedState.cartItems }) expect(stateMock).toEqual(expectedState) }) }) @@ -202,7 +202,7 @@ describe('Cart mutations', () => { const wrapper = (mutations: any) => mutations[types.CART_DEL_NON_CONFIRMED_ITEM]( stateMock, { - product: {sku: 'foo'}, + product: { sku: 'foo' }, removeByParentSku: false } ) @@ -214,7 +214,7 @@ describe('Cart mutations', () => { sku: 'foo' }] }) - expect(EventBus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-after-delete', { items: expectedState.cartItems }) expect(stateMock).toEqual(expectedState) }) @@ -233,7 +233,7 @@ describe('Cart mutations', () => { const wrapper = (mutations: any) => mutations[types.CART_DEL_NON_CONFIRMED_ITEM]( stateMock, { - product: {parentSku: 'foo'} + product: { parentSku: 'foo' } } ) @@ -245,7 +245,7 @@ describe('Cart mutations', () => { sku: 'foo' }] }) - expect(EventBus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-after-delete', { items: expectedState.cartItems }) expect(stateMock).toEqual(expectedState) }) @@ -271,15 +271,15 @@ describe('Cart mutations', () => { const wrapper = (mutations: any) => mutations[types.CART_DEL_NON_CONFIRMED_ITEM]( stateMock, { - product: {sku: 'foo'}, + product: { sku: 'foo' }, removeByParentSku: false } ) wrapper(cartMutations) - expect(EventBus.$emit).toBeCalledWith('cart-before-delete', {items: stateMock.cartItems}) - expect(EventBus.$emit).toBeCalledWith('cart-after-delete', {items: expectedState.cartItems}) + expect(EventBus.$emit).toBeCalledWith('cart-before-delete', { items: stateMock.cartItems }) + expect(EventBus.$emit).toBeCalledWith('cart-after-delete', { items: expectedState.cartItems }) expect(stateMock).toEqual(expectedState) }) }) @@ -331,7 +331,7 @@ describe('Cart mutations', () => { const wrapper = (mutations: any) => mutations[types.CART_UPD_ITEM]( stateMock, { - product: {sku: 'qux'}, + product: { sku: 'qux' }, qty: 20 } ) @@ -366,7 +366,7 @@ describe('Cart mutations', () => { const wrapper = (mutations: any) => mutations[types.CART_UPD_ITEM_PROPS]( stateMock, { - product: {sku: 'foo', someProp: 'baz', qty: 20} + product: { sku: 'foo', someProp: 'baz', qty: 20 } } ) let firstEmitCall = [] @@ -406,7 +406,7 @@ describe('Cart mutations', () => { const wrapper = (mutations: any) => mutations[types.CART_UPD_ITEM_PROPS]( stateMock, { - product: {server_item_id: 123, sku: 'bar', someProp: 'baz', qty: 20} + product: { server_item_id: 123, sku: 'bar', someProp: 'baz', qty: 20 } } ) let firstEmitCall = [] @@ -436,7 +436,7 @@ describe('Cart mutations', () => { const wrapper = (mutations: any) => mutations[types.CART_UPD_ITEM_PROPS]( stateMock, { - product: {sku: 'qux', someProp: 'baz', qty: 20} + product: { sku: 'qux', someProp: 'baz', qty: 20 } } ) @@ -528,8 +528,8 @@ describe('Cart mutations', () => { bar: 1 /** @todo replace with real alike data to show what it can be filled with */ }, platformTotalSegments: [ - {'code': 'subtotal', 'title': 'Subtotal', 'value': 39.36}, - {'code': 'grand_total', 'title': 'Grand Total', 'value': 39.36, 'area': 'footer'} + { 'code': 'subtotal', 'title': 'Subtotal', 'value': 39.36 }, + { 'code': 'grand_total', 'title': 'Grand Total', 'value': 39.36, 'area': 'footer' } ] } const wrapper = (mutations: any) => mutations[types.CART_UPD_TOTALS]( diff --git a/core/modules/catalog-next/helpers/filterHelpers.ts b/core/modules/catalog-next/helpers/filterHelpers.ts index 700669d130..5b29e3dd4d 100644 --- a/core/modules/catalog-next/helpers/filterHelpers.ts +++ b/core/modules/catalog-next/helpers/filterHelpers.ts @@ -7,7 +7,7 @@ export const getSystemFilterNames: string[] = config.products.systemFilterNames /** * Creates new filtersQuery (based on currentQuery) by modifying specific filter variant. */ -export const changeFilterQuery = ({currentQuery = {}, filterVariant}: {currentQuery?: any, filterVariant?: FilterVariant} = {}) => { +export const changeFilterQuery = ({ currentQuery = {}, filterVariant }: {currentQuery?: any, filterVariant?: FilterVariant} = {}) => { const newQuery = JSON.parse(JSON.stringify(currentQuery)) if (!filterVariant) return newQuery if (getSystemFilterNames.includes(filterVariant.type)) { @@ -33,7 +33,7 @@ export const changeFilterQuery = ({currentQuery = {}, filterVariant}: {currentQu return newQuery } -export const getFiltersFromQuery = ({filtersQuery = {}, availableFilters = {}} = {}): { filters: Filters } => { +export const getFiltersFromQuery = ({ filtersQuery = {}, availableFilters = {} } = {}): { filters: Filters } => { const searchQuery = { filters: {} } @@ -50,7 +50,7 @@ export const getFiltersFromQuery = ({filtersQuery = {}, availableFilters = {}} = const variant = filter.find(filterVariant => filterVariant.id === singleValue) if (!variant) return if (!Array.isArray(searchQuery.filters[filterKey])) searchQuery.filters[filterKey] = [] - searchQuery.filters[filterKey].push({...variant, attribute_code: filterKey}) + searchQuery.filters[filterKey].push({ ...variant, attribute_code: filterKey }) }) } }) diff --git a/core/modules/catalog-next/index.ts b/core/modules/catalog-next/index.ts index 0e0c4b4a5a..5ea5cd1222 100644 --- a/core/modules/catalog-next/index.ts +++ b/core/modules/catalog-next/index.ts @@ -1,6 +1,6 @@ import { categoryModule } from './store/category' import { StorefrontModule } from '@vue-storefront/core/lib/modules'; -export const CatalogNextModule: StorefrontModule = function ({store}) { +export const CatalogNextModule: StorefrontModule = function ({ store }) { store.registerModule('category-next', categoryModule) } diff --git a/core/modules/catalog-next/store/category/actions.ts b/core/modules/catalog-next/store/category/actions.ts index a81a9fe2a0..01dbfea9d7 100644 --- a/core/modules/catalog-next/store/category/actions.ts +++ b/core/modules/catalog-next/store/category/actions.ts @@ -34,14 +34,14 @@ const actions: ActionTree = { } const searchQuery = getters.getCurrentFiltersFrom(route[products.routerFiltersSource], categoryMappedFilters) let filterQr = buildFilterProductsQuery(searchCategory, searchQuery.filters) - const {items, perPage, start, total, aggregations} = await quickSearchByQuery({ + const { items, perPage, start, total, aggregations } = await quickSearchByQuery({ query: filterQr, sort: searchQuery.sort || `${products.defaultSortBy.attribute}:${products.defaultSortBy.order}`, includeFields: entities.productList.includeFields, excludeFields: entities.productList.excludeFields, size: pageSize }) - await dispatch('loadAvailableFiltersFrom', {aggregations, category: searchCategory, filters: searchQuery.filters}) + await dispatch('loadAvailableFiltersFrom', { aggregations, category: searchCategory, filters: searchQuery.filters }) commit(types.CATEGORY_SET_SEARCH_PRODUCTS_STATS, { perPage, start, total }) const configuredProducts = await dispatch('processCategoryProducts', { products: items, filters: searchQuery.filters }) commit(types.CATEGORY_SET_PRODUCTS, configuredProducts) @@ -97,18 +97,18 @@ const actions: ActionTree = { * Configures products */ async processCategoryProducts ({ dispatch, rootState }, { products = [], filters = {} } = {}) { - await dispatch('tax/calculateTaxes', { products: products }, { root: true }) + const configuredProducts = await dispatch('configureProducts', { products, filters }) dispatch('registerCategoryProductsMapping', products) // we don't need to wait for this - return dispatch('configureProducts', { products, filters }) + return dispatch('tax/calculateTaxes', { products: configuredProducts }, { root: true }) }, /** * Configure configurable products to have first available options selected * so they can be added to cart/wishlist/compare without manual configuring */ - async configureProducts ({ rootState }, { products = [], filters = {} } = {}) { + async configureProducts ({ rootState }, { products = [], filters = {}, populateRequestCacheTags = config.server.useOutputCacheTagging } = {}) { return products.map(product => { - product = Object.assign({}, preConfigureProduct({ product, populateRequestCacheTags: config.server.useOutputCacheTagging })) - const configuredProductVariant = configureProductAsync({rootState, state: {current_configuration: {}}}, {product, configuration: filters, selectDefaultVariant: false, fallbackToDefaultWhenNoAvailable: true, setProductErorrs: false}) + product = Object.assign({}, preConfigureProduct({ product, populateRequestCacheTags })) + const configuredProductVariant = configureProductAsync({ rootState, state: { current_configuration: {} } }, { product, configuration: filters, selectDefaultVariant: false, fallbackToDefaultWhenNoAvailable: true, setProductErorrs: false }) return Object.assign(product, omit(configuredProductVariant, ['visibility'])) }) }, @@ -171,14 +171,14 @@ const actions: ActionTree = { async loadCategoryFilters ({ dispatch, getters }, category) { const searchCategory = category || getters.getCurrentCategory let filterQr = buildFilterProductsQuery(searchCategory) - const {aggregations} = await quickSearchByQuery({ + const { aggregations } = await quickSearchByQuery({ query: filterQr, size: config.products.maxFiltersQuerySize, excludeFields: ['*'] }) - await dispatch('loadAvailableFiltersFrom', {aggregations, category}) + await dispatch('loadAvailableFiltersFrom', { aggregations, category }) }, - async loadAvailableFiltersFrom ({ commit, getters }, {aggregations, category, filters = {}}) { + async loadAvailableFiltersFrom ({ commit, getters }, { aggregations, category, filters = {} }) { const aggregationFilters = getters.getAvailableFiltersFrom(aggregations) const currentCategory = category || getters.getCurrentCategory const categoryMappedFilters = getters.getFiltersMap[currentCategory.id] @@ -187,20 +187,20 @@ const actions: ActionTree = { if (categoryMappedFilters && filtersKeys.length) { resultFilters = Object.assign(cloneDeep(categoryMappedFilters), cloneDeep(omit(aggregationFilters, filtersKeys))) } - commit(types.CATEGORY_SET_CATEGORY_FILTERS, {category, filters: resultFilters}) + commit(types.CATEGORY_SET_CATEGORY_FILTERS, { category, filters: resultFilters }) }, async switchSearchFilters ({ dispatch }, filterVariants: FilterVariant[] = []) { let currentQuery = router.currentRoute[products.routerFiltersSource] filterVariants.forEach(filterVariant => { - currentQuery = changeFilterQuery({currentQuery, filterVariant}) + currentQuery = changeFilterQuery({ currentQuery, filterVariant }) }) await dispatch('changeRouterFilterParameters', currentQuery) }, - async resetSearchFilters ({dispatch}) { + async resetSearchFilters ({ dispatch }) { await dispatch('changeRouterFilterParameters', {}) }, async changeRouterFilterParameters (context, query) { - router.push({[products.routerFiltersSource]: query}) + router.push({ [products.routerFiltersSource]: query }) }, async loadCategoryBreadcrumbs ({ dispatch, getters }, { category, currentRouteName, omitCurrent = false }) { if (!category) return diff --git a/core/modules/catalog-next/store/category/getters.ts b/core/modules/catalog-next/store/category/getters.ts index a7463a735e..8b5bde50b8 100644 --- a/core/modules/catalog-next/store/category/getters.ts +++ b/core/modules/catalog-next/store/category/getters.ts @@ -118,7 +118,7 @@ const getters: GetterTree = { getCurrentFiltersFrom: (state, getters, rootState) => (filters, categoryFilters) => { const currentQuery = filters || rootState.route[products.routerFiltersSource] const availableFilters = categoryFilters || getters.getAvailableFilters - return getFiltersFromQuery({availableFilters, filtersQuery: currentQuery}) + return getFiltersFromQuery({ availableFilters, filtersQuery: currentQuery }) }, getCurrentSearchQuery: (state, getters, rootState) => getters.getCurrentFiltersFrom(rootState.route[products.routerFiltersSource]), getCurrentFilters: (state, getters) => getters.getCurrentSearchQuery.filters, diff --git a/core/modules/catalog-next/store/category/mutations.ts b/core/modules/catalog-next/store/category/mutations.ts index 7dc398d087..4580128adf 100644 --- a/core/modules/catalog-next/store/category/mutations.ts +++ b/core/modules/catalog-next/store/category/mutations.ts @@ -33,7 +33,7 @@ const mutations: MutationTree = { [types.CATEGORY_ADD_NOT_FOUND_CATEGORY_IDS] (state, categoryIds: string[] = []) { state.notFoundCategoryIds = [...state.notFoundCategoryIds, ...categoryIds] }, - [types.CATEGORY_SET_CATEGORY_FILTERS] (state, {category, filters}) { + [types.CATEGORY_SET_CATEGORY_FILTERS] (state, { category, filters }) { Vue.set(state.filtersMap, category.id, filters) }, [types.CATEGORY_SET_SEARCH_PRODUCTS_STATS] (state, stats = {}) { diff --git a/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts b/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts index 2b432cad16..6f0b607a9c 100644 --- a/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts +++ b/core/modules/catalog-next/test/unit/getFiltersFromQuery.spec.ts @@ -91,7 +91,7 @@ describe('getFiltersFromQuery method', () => { const filtersQuery = { color: '49' } - const result = getFiltersFromQuery({availableFilters, filtersQuery}) + const result = getFiltersFromQuery({ availableFilters, filtersQuery }) expect(result).toEqual({ filters: { color: [ @@ -110,7 +110,7 @@ describe('getFiltersFromQuery method', () => { const filtersQuery = { color: ['49', '50'] } - const result = getFiltersFromQuery({availableFilters, filtersQuery}) + const result = getFiltersFromQuery({ availableFilters, filtersQuery }) expect(result).toEqual({ filters: { color: [ @@ -135,7 +135,7 @@ describe('getFiltersFromQuery method', () => { const filtersQuery = { color: '111' } - const result = getFiltersFromQuery({availableFilters, filtersQuery}) + const result = getFiltersFromQuery({ availableFilters, filtersQuery }) expect(result).toEqual({ filters: {} }) @@ -145,7 +145,7 @@ describe('getFiltersFromQuery method', () => { const filtersQuery = { sort: 'updated_at' } - const result = getFiltersFromQuery({availableFilters, filtersQuery}) + const result = getFiltersFromQuery({ availableFilters, filtersQuery }) expect(result).toEqual({ filters: {}, sort: 'updated_at' diff --git a/core/modules/catalog-next/test/unit/prefetchStockItems.spec.ts b/core/modules/catalog-next/test/unit/prefetchStockItems.spec.ts index 60662a9ff1..12b2ed2b66 100644 --- a/core/modules/catalog-next/test/unit/prefetchStockItems.spec.ts +++ b/core/modules/catalog-next/test/unit/prefetchStockItems.spec.ts @@ -1,4 +1,4 @@ -import {prefetchStockItems} from '../../helpers/cacheProductsHelper'; +import { prefetchStockItems } from '../../helpers/cacheProductsHelper'; import config from 'config'; describe('prefetchStockItems method', () => { @@ -19,17 +19,17 @@ describe('prefetchStockItems method', () => { it('returns the skus of the children of a configurable', () => { const cachedProductsResponse = { items: [ - {sku: 'foo'}, + { sku: 'foo' }, { sku: 'bar', type_id: 'configurable', configurable_children: [ - {sku: 'bar.foo'}, - {sku: 'bar.bar'}, - {sku: 'bar.baz'} + { sku: 'bar.foo' }, + { sku: 'bar.bar' }, + { sku: 'bar.baz' } ] }, - {sku: 'baz'} + { sku: 'baz' } ] } const result = prefetchStockItems(cachedProductsResponse) @@ -39,9 +39,9 @@ describe('prefetchStockItems method', () => { it('returns the same skus of the provided simple products', () => { const cachedProductsResponse = { items: [ - {sku: 'foo'}, - {sku: 'bar'}, - {sku: 'baz'} + { sku: 'foo' }, + { sku: 'bar' }, + { sku: 'baz' } ] } const result = prefetchStockItems(cachedProductsResponse) @@ -51,20 +51,20 @@ describe('prefetchStockItems method', () => { it('ignores the pre-cached skus of children of a configurable', () => { const cachedProductsResponse = { items: [ - {sku: 'foo'}, + { sku: 'foo' }, { sku: 'bar', type_id: 'configurable', configurable_children: [ - {sku: 'bar.foo', id: 1337}, - {sku: 'bar.bar'}, - {sku: 'bar.baz', id: 4711} + { sku: 'bar.foo', id: 1337 }, + { sku: 'bar.bar' }, + { sku: 'bar.baz', id: 4711 } ] }, - {sku: 'baz'} + { sku: 'baz' } ] } - const result = prefetchStockItems(cachedProductsResponse, {1337: {}, 4711: {}}) + const result = prefetchStockItems(cachedProductsResponse, { 1337: {}, 4711: {} }) expect(result).toEqual(['foo', 'bar', 'bar.bar', 'baz']); }) }) diff --git a/core/modules/catalog/components/ProductBundleOptions.ts b/core/modules/catalog/components/ProductBundleOptions.ts index 84f5d71820..240a3a1ecb 100644 --- a/core/modules/catalog/components/ProductBundleOptions.ts +++ b/core/modules/catalog/components/ProductBundleOptions.ts @@ -61,11 +61,11 @@ export const ProductBundleOptions = { } } }, - optionChanged ({fieldName, option, qty, value}) { + optionChanged ({ fieldName, option, qty, value }) { if (!fieldName) return this.setBundleOptionValue({ optionId: option.option_id, optionQty: parseInt(qty), optionSelections: [parseInt(value.id)] }) this.$store.dispatch('product/setBundleOptions', { product: this.product, bundleOptions: this.$store.state.product.current_bundle_options }) // TODO: move it to "AddToCart" - this.selectedOptions[fieldName] = {qty, value} + this.selectedOptions[fieldName] = { qty, value } const valueId = value ? value.id : null if (this.validateField(option, qty, valueId)) { this.$bus.$emit('product-after-bundleoptions', { product: this.product, option: option, optionValues: this.selectedOptions }) diff --git a/core/modules/catalog/events.ts b/core/modules/catalog/events.ts index 8eb005a116..fe2f0ded64 100644 --- a/core/modules/catalog/events.ts +++ b/core/modules/catalog/events.ts @@ -17,7 +17,7 @@ export const productAfterPriceupdate = async (product, store) => { export const filterChangedProduct = async (filterOption, store, router) => { EventBus.$emit('product-before-configure', { filterOption: filterOption, configuration: store.getters['product/getCurrentProductConfiguration'] }) const prevOption = store.getters['product/getCurrentProductConfiguration'][filterOption.attribute_code] - let changedConfig = Object.assign({}, store.getters['product/getCurrentProductConfiguration'], {[filterOption.attribute_code]: filterOption}) + let changedConfig = Object.assign({}, store.getters['product/getCurrentProductConfiguration'], { [filterOption.attribute_code]: filterOption }) const selectedVariant = await store.dispatch('product/configure', { product: store.getters['product/getCurrentProduct'], configuration: changedConfig, @@ -26,7 +26,7 @@ export const filterChangedProduct = async (filterOption, store, router) => { setProductErorrs: true }, { root: true }) if (config.products.setFirstVarianAsDefaultInURL) { - router.push({params: { childSku: selectedVariant.sku }}) + router.push({ params: { childSku: selectedVariant.sku } }) } if (!selectedVariant) { if (prevOption) { diff --git a/core/modules/catalog/helpers/createAttributesListQuery.ts b/core/modules/catalog/helpers/createAttributesListQuery.ts index 3dd25310ca..dedeabc16a 100644 --- a/core/modules/catalog/helpers/createAttributesListQuery.ts +++ b/core/modules/catalog/helpers/createAttributesListQuery.ts @@ -14,13 +14,13 @@ const createAttributesListQuery = ({ let searchQuery = new SearchQuery() if (filterValues) { - searchQuery = searchQuery.applyFilter({key: filterField, value: {'in': filterValues}}) + searchQuery = searchQuery.applyFilter({ key: filterField, value: { 'in': filterValues } }) } if (onlyDefinedByUser) { - searchQuery = searchQuery.applyFilter({key: 'is_user_defined', value: {'in': [true, '1']}}) + searchQuery = searchQuery.applyFilter({ key: 'is_user_defined', value: { 'in': [true, '1'] } }) } if (onlyVisible) { - searchQuery = searchQuery.applyFilter({key: 'is_visible', value: {'in': [true, '1']}}) + searchQuery = searchQuery.applyFilter({ key: 'is_visible', value: { 'in': [true, '1'] } }) } return searchQuery diff --git a/core/modules/catalog/helpers/createCategoryListQuery.ts b/core/modules/catalog/helpers/createCategoryListQuery.ts index d06ac7eae4..0ba89ff8ed 100644 --- a/core/modules/catalog/helpers/createCategoryListQuery.ts +++ b/core/modules/catalog/helpers/createCategoryListQuery.ts @@ -7,12 +7,12 @@ const createCategoryListQuery = ({ parent, level, key, value, onlyActive, onlyNo let searchQuery = new SearchQuery() if (parent) { - searchQuery = searchQuery.applyFilter({key: 'parent_id', value: { 'eq': typeof parent === 'object' ? parent.id : parent }}) + searchQuery = searchQuery.applyFilter({ key: 'parent_id', value: { 'eq': typeof parent === 'object' ? parent.id : parent } }) isCustomizedQuery = true } if (level !== null) { - searchQuery = searchQuery.applyFilter({key: 'level', value: {'eq': level}}) + searchQuery = searchQuery.applyFilter({ key: 'level', value: { 'eq': level } }) if (level !== config.entities.category.categoriesDynamicPrefetchLevel && !isServer) { isCustomizedQuery = true } @@ -20,19 +20,19 @@ const createCategoryListQuery = ({ parent, level, key, value, onlyActive, onlyNo if (key !== null) { if (Array.isArray(value)) { - searchQuery = searchQuery.applyFilter({key: key, value: { 'in': value }}) + searchQuery = searchQuery.applyFilter({ key: key, value: { 'in': value } }) } else { - searchQuery = searchQuery.applyFilter({key: key, value: { 'eq': value }}) + searchQuery = searchQuery.applyFilter({ key: key, value: { 'eq': value } }) } isCustomizedQuery = true } if (onlyActive === true) { - searchQuery = searchQuery.applyFilter({key: 'is_active', value: { 'eq': true }}) + searchQuery = searchQuery.applyFilter({ key: 'is_active', value: { 'eq': true } }) } if (onlyNotEmpty === true) { - searchQuery = searchQuery.applyFilter({key: 'product_count', value: { 'gt': 0 }}) + searchQuery = searchQuery.applyFilter({ key: 'product_count', value: { 'gt': 0 } }) isCustomizedQuery = true } diff --git a/core/modules/catalog/helpers/filters.ts b/core/modules/catalog/helpers/filters.ts index fbabfd45c4..000157ec72 100644 --- a/core/modules/catalog/helpers/filters.ts +++ b/core/modules/catalog/helpers/filters.ts @@ -6,8 +6,8 @@ const getAvailableFiltersByProduct = (product: Product) => { if (product && product.configurable_options) { product.configurable_options.forEach(configurableOption => { const type = configurableOption.attribute_code - const filterVariants = configurableOption.values.map(({value_index, label}) => { - return {id: value_index, label, type} + const filterVariants = configurableOption.values.map(({ value_index, label }) => { + return { id: value_index, label, type } }) filtersMap[type] = filterVariants }) diff --git a/core/modules/catalog/helpers/index.ts b/core/modules/catalog/helpers/index.ts index 7c39e42682..57e5c37c70 100644 --- a/core/modules/catalog/helpers/index.ts +++ b/core/modules/catalog/helpers/index.ts @@ -142,7 +142,7 @@ export function filterOutUnavailableVariants (context, product) { } Logger.debug('Cached stock items and delta' + stockItems + confChildSkus)() if (confChildSkus.length > 0) { - context.dispatch('stock/list', { skus: confChildSkus }, {root: true}).then((task) => { + context.dispatch('stock/list', { skus: confChildSkus }, { root: true }).then((task) => { if (task && task.resultCode === 200) { const diffLog = [] _filterChildrenByStockitem(context, union(task.result, stockItems), product, diffLog) @@ -166,7 +166,7 @@ export function filterOutUnavailableVariants (context, product) { } const rootStockCached = context.rootState.stock.cache[product.id] if (!rootStockCached) { - context.dispatch('stock/list', { skus: [product.sku] }, {root: true}).then((task) => { + context.dispatch('stock/list', { skus: [product.sku] }, { root: true }).then((task) => { _filterRootProductByStockitem(context, task && task.result && task.result.length ? task.result[0] : null, product, reject) Logger.debug('Filtered root product stock with the network call')() _filterConfigurableHelper() diff --git a/core/modules/catalog/helpers/slugifyCategories.ts b/core/modules/catalog/helpers/slugifyCategories.ts index b8eb6a08ff..0436de07c0 100644 --- a/core/modules/catalog/helpers/slugifyCategories.ts +++ b/core/modules/catalog/helpers/slugifyCategories.ts @@ -14,7 +14,7 @@ const slugifyCategories = (category: Category | ChildrenData): Category | Childr if (category.children_data) { for (let subcat of category.children_data) { if (subcat.name && !subcat.slug) { - slugifyCategories({...subcat, slug: createSlug(subcat)} as any as ChildrenData) + slugifyCategories({ ...subcat, slug: createSlug(subcat) } as any as ChildrenData) } } } diff --git a/core/modules/catalog/helpers/taxCalc.ts b/core/modules/catalog/helpers/taxCalc.ts index b705ae2cf8..27c8130983 100644 --- a/core/modules/catalog/helpers/taxCalc.ts +++ b/core/modules/catalog/helpers/taxCalc.ts @@ -89,7 +89,7 @@ export function updateProductPrices ({ product, rate, sourcePriceInclTax = false // save original prices if (!hasOriginalPrices) { - assignPrice({product, target: 'original_price', ...priceWithTax, deprecatedPriceFieldsSupport}) + assignPrice({ product, target: 'original_price', ...priceWithTax, deprecatedPriceFieldsSupport }) if (specialPriceWithTax.price) { product.original_special_price = specialPriceWithTax.price @@ -112,12 +112,12 @@ export function updateProductPrices ({ product, rate, sourcePriceInclTax = false if (product.final_price) { if (product.final_price < product.price) { // compare the prices with the product final price if provided; final prices is used in case of active catalog promo rules for example - assignPrice({product, target: 'price', ...finalPriceWithTax, deprecatedPriceFieldsSupport}) + assignPrice({ product, target: 'price', ...finalPriceWithTax, deprecatedPriceFieldsSupport }) if (product.special_price && product.final_price < product.special_price) { // for VS - special_price is any price lowered than regular price (`price`); in Magento there is a separate mechanism for setting the `special_prices` - assignPrice({product, target: 'price', ...specialPriceWithTax, deprecatedPriceFieldsSupport}) // if the `final_price` is lower than the original `special_price` - it means some catalog rules were applied over it - assignPrice({product, target: 'special_price', ...finalPriceWithTax, deprecatedPriceFieldsSupport}) + assignPrice({ product, target: 'price', ...specialPriceWithTax, deprecatedPriceFieldsSupport }) // if the `final_price` is lower than the original `special_price` - it means some catalog rules were applied over it + assignPrice({ product, target: 'special_price', ...finalPriceWithTax, deprecatedPriceFieldsSupport }) } else { - assignPrice({product, target: 'price', ...finalPriceWithTax, deprecatedPriceFieldsSupport}) + assignPrice({ product, target: 'price', ...finalPriceWithTax, deprecatedPriceFieldsSupport }) } } } diff --git a/core/modules/catalog/index.ts b/core/modules/catalog/index.ts index 9d57578722..33ff1e321c 100644 --- a/core/modules/catalog/index.ts +++ b/core/modules/catalog/index.ts @@ -11,7 +11,7 @@ import { filterChangedProduct, productAfterCustomoptions, productAfterBundleopti import { isServer } from '@vue-storefront/core/helpers' import uniq from 'lodash-es/uniq' -export const CatalogModule: StorefrontModule = async function ({store, router, appConfig}) { +export const CatalogModule: StorefrontModule = async function ({ store, router, appConfig }) { StorageManager.init('categories') StorageManager.init('attributes') StorageManager.init('products') diff --git a/core/modules/catalog/queries/common.js b/core/modules/catalog/queries/common.js index 44f541c96b..a77db5faca 100644 --- a/core/modules/catalog/queries/common.js +++ b/core/modules/catalog/queries/common.js @@ -1,7 +1,7 @@ import SearchQuery from '@vue-storefront/core/lib/search/searchQuery' import config from 'config' -export function prepareQuery ({queryText = '', filters = [], queryConfig = ''}) { +export function prepareQuery ({ queryText = '', filters = [], queryConfig = '' }) { let query = new SearchQuery() // prepare filters and searchText if (filters.length === 0 && queryConfig !== '') { @@ -21,7 +21,7 @@ export function prepareQuery ({queryText = '', filters = [], queryConfig = ''}) // Process filters and searchText if exists if (filters.length > 0) { filters.forEach(filter => { - query = query.applyFilter({key: filter.key, value: filter.value}) // Tees category + query = query.applyFilter({ key: filter.key, value: filter.value }) // Tees category }) } @@ -31,8 +31,8 @@ export function prepareQuery ({queryText = '', filters = [], queryConfig = ''}) // Add basic filters query = query - .applyFilter({key: 'visibility', value: {'in': [2, 3, 4]}}) - .applyFilter({key: 'status', value: {'in': [0, 1]}}) + .applyFilter({ key: 'visibility', value: { 'in': [2, 3, 4] } }) + .applyFilter({ key: 'status', value: { 'in': [0, 1] } }) return query } diff --git a/core/modules/catalog/queries/related.js b/core/modules/catalog/queries/related.js index 369a30f8c3..8bda79a1a2 100644 --- a/core/modules/catalog/queries/related.js +++ b/core/modules/catalog/queries/related.js @@ -4,14 +4,14 @@ import config from 'config' export function prepareRelatedQuery (key, sku) { let relatedProductsQuery = new SearchQuery() - relatedProductsQuery = relatedProductsQuery.applyFilter({key: key, value: {'in': sku}}) + relatedProductsQuery = relatedProductsQuery.applyFilter({ key: key, value: { 'in': sku } }) relatedProductsQuery = relatedProductsQuery - .applyFilter({key: 'visibility', value: {'in': [2, 3, 4]}}) - .applyFilter({key: 'status', value: {'in': [1]}}) + .applyFilter({ key: 'visibility', value: { 'in': [2, 3, 4] } }) + .applyFilter({ key: 'status', value: { 'in': [1] } }) if (config.products.listOutOfStockProducts === false) { - relatedProductsQuery = relatedProductsQuery.applyFilter({key: 'stock.is_in_stock', value: {'eq': true}}) + relatedProductsQuery = relatedProductsQuery.applyFilter({ key: 'stock.is_in_stock', value: { 'eq': true } }) } return relatedProductsQuery diff --git a/core/modules/catalog/queries/searchPanel.js b/core/modules/catalog/queries/searchPanel.js index f2142906b5..f8fad4b753 100644 --- a/core/modules/catalog/queries/searchPanel.js +++ b/core/modules/catalog/queries/searchPanel.js @@ -6,11 +6,11 @@ export function prepareQuickSearchQuery (queryText) { searchQuery = searchQuery .setSearchText(queryText) - .applyFilter({key: 'visibility', value: {'in': [3, 4]}}) - .applyFilter({key: 'status', value: {'in': [0, 1]}})/* 2 = disabled, 3 = out of stock */ + .applyFilter({ key: 'visibility', value: { 'in': [3, 4] } }) + .applyFilter({ key: 'status', value: { 'in': [0, 1] } })/* 2 = disabled, 3 = out of stock */ if (config.products.listOutOfStockProducts === false) { - searchQuery = searchQuery.applyFilter({key: 'stock.is_in_stock', value: {'eq': true}}) + searchQuery = searchQuery.applyFilter({ key: 'stock.is_in_stock', value: { 'eq': true } }) } return searchQuery diff --git a/core/modules/catalog/store/category/actions.ts b/core/modules/catalog/store/category/actions.ts index ea228e6476..ba590a658a 100644 --- a/core/modules/catalog/store/category/actions.ts +++ b/core/modules/catalog/store/category/actions.ts @@ -353,8 +353,8 @@ const actions: ActionTree = { } return productPromise }, - addAvailableFilter ({commit}, {key, options} = {}) { - if (key) commit(types.CATEGORY_ADD_AVAILABLE_FILTER, {key, options}) + addAvailableFilter ({ commit }, { key, options } = {}) { + if (key) commit(types.CATEGORY_ADD_AVAILABLE_FILTER, { key, options }) }, resetFilters (context) { context.commit(types.CATEGORY_REMOVE_FILTERS) @@ -362,10 +362,10 @@ const actions: ActionTree = { searchProductQuery (context, productQuery) { context.commit(types.CATEGORY_UPD_SEARCH_PRODUCT_QUERY, productQuery) }, - setSearchOptions ({commit}, searchOptions) { + setSearchOptions ({ commit }, searchOptions) { commit(types.CATEGORY_SET_SEARCH_OPTIONS, searchOptions) }, - mergeSearchOptions ({commit}, searchOptions) { + mergeSearchOptions ({ commit }, searchOptions) { commit(types.CATEGORY_MERGE_SEARCH_OPTIONS, searchOptions) } } diff --git a/core/modules/catalog/store/product/actions.ts b/core/modules/catalog/store/product/actions.ts index 35c9290383..26a1363af7 100644 --- a/core/modules/catalog/store/product/actions.ts +++ b/core/modules/catalog/store/product/actions.ts @@ -47,6 +47,7 @@ const actions: ActionTree = { * Setup product breadcrumbs path */ async setupBreadcrumbs (context, { product }) { + console.warn('deprecated, will be removed in 1.13') let breadcrumbsName = null let setBreadcrumbRoutesFromPath = (path) => { if (path.findIndex(itm => { @@ -200,14 +201,14 @@ const actions: ActionTree = { * This is fix for https://github.com/DivanteLtd/vue-storefront/issues/508 * TODO: probably it would be better to have "parent_id" for simple products or to just ensure configurable variants are not visible in categories/search */ - checkConfigurableParent (context, {product}) { + checkConfigurableParent (context, { product }) { if (product.type_id === 'simple') { Logger.log('Checking configurable parent')() let searchQuery = new SearchQuery() - searchQuery = searchQuery.applyFilter({key: 'configurable_children.sku', value: {'eq': context.getters.getCurrentProduct.sku}}) + searchQuery = searchQuery.applyFilter({ key: 'configurable_children.sku', value: { 'eq': context.getters.getCurrentProduct.sku } }) - return context.dispatch('list', {query: searchQuery, start: 0, size: 1, updateState: false}).then((resp) => { + return context.dispatch('list', { query: searchQuery, start: 0, size: 1, updateState: false }).then((resp) => { if (resp.items.length >= 1) { const parentProduct = resp.items[0] context.commit(types.PRODUCT_SET_PARENT, parentProduct) @@ -317,6 +318,7 @@ const actions: ActionTree = { } }, preConfigureProduct (context, { product, populateRequestCacheTags, configuration }) { + console.warn('deprecated, will be removed in 1.13') let prod = preConfigureProduct({ product, populateRequestCacheTags }) if (configuration) { @@ -327,19 +329,21 @@ const actions: ActionTree = { return prod }, async configureLoadedProducts (context, { products, isCacheable, cacheByKey, populateRequestCacheTags, configuration }) { - if (products.items && products.items.length) { // preconfigure products; eg: after filters - for (let product of products.items) { - product = await context.dispatch('preConfigureProduct', { product, populateRequestCacheTags, configuration }) // preConfigure(product) - } - } - - await context.dispatch('tax/calculateTaxes', { products: products.items }, { root: true }) + const configuredProducts = await context.dispatch( + 'category-next/configureProducts', + { + products: products.items, + filters: configuration || {}, + populateRequestCacheTags + }, + { root: true } + ) - for (let prod of products.items) { // we store each product separately in cache to have offline access to products/single method - prod = configureChildren(prod) + await context.dispatch('tax/calculateTaxes', { products: configuredProducts }, { root: true }) + for (let product of configuredProducts) { // we store each product separately in cache to have offline access to products/single method if (isCacheable) { // store cache only for full loads - storeProductToCache(prod, cacheByKey) + storeProductToCache(product, cacheByKey) } } @@ -355,7 +359,7 @@ const actions: ActionTree = { }, async findConfigurableParent (context, { product, configuration }) { const searchQuery = new SearchQuery() - const query = searchQuery.applyFilter({key: 'configurable_children.sku', value: { 'eq': product.sku }}) + const query = searchQuery.applyFilter({ key: 'configurable_children.sku', value: { 'eq': product.sku } }) const products = await context.dispatch('findProducts', { query, configuration }) return products.items && products.items.length > 0 ? products.items[0] : null }, @@ -434,7 +438,7 @@ const actions: ActionTree = { const syncProducts = () => { let searchQuery = new SearchQuery() - searchQuery = searchQuery.applyFilter({key: key, value: {'eq': options[key]}}) + searchQuery = searchQuery.applyFilter({ key: key, value: { 'eq': options[key] } }) return context.dispatch('list', { // product list syncs the platform price on it's own query: searchQuery, @@ -623,7 +627,7 @@ const actions: ActionTree = { * Load the product data and sets current product */ async loadProduct ({ dispatch }, { parentSku, childSku = null, route = null }) { - Logger.info('Fetching product data asynchronously', 'product', {parentSku, childSku})() + Logger.info('Fetching product data asynchronously', 'product', { parentSku, childSku })() EventBus.$emit('product-before-load', { store: rootStore, route: route }) await dispatch('reset') // pass both id and sku to render a product diff --git a/core/modules/catalog/store/product/mutations.ts b/core/modules/catalog/store/product/mutations.ts index 5a4abe7f54..2c81ada342 100644 --- a/core/modules/catalog/store/product/mutations.ts +++ b/core/modules/catalog/store/product/mutations.ts @@ -28,7 +28,7 @@ const mutations: MutationTree = { state.related = Object.assign( {}, state.related, - {[key]: items} + { [key]: items } ) }, [types.PRODUCT_SET_CURRENT] (state, product) { @@ -39,7 +39,7 @@ const mutations: MutationTree = { state.current_configuration = {} state.offlineImage = null state.parent = null - state.current_options = {color: [], size: []} + state.current_options = { color: [], size: [] } state.current_bundle_options = {} state.current_custom_options = {} }, @@ -59,10 +59,10 @@ const mutations: MutationTree = { state.current_custom_options = Object.assign( {}, state.current_custom_options, - {[optionId]: { + { [optionId]: { option_id: optionId, option_value: optionValue - }} + } } ) }, [types.PRODUCT_SET_BUNDLE_OPTION] (state, { optionId, optionQty, optionSelections }) { @@ -74,14 +74,14 @@ const mutations: MutationTree = { state.current_bundle_options = Object.assign( {}, state.current_bundle_options, - {[optionId]: option} + { [optionId]: option } ) }, [types.PRODUCT_SET_CUSTOM_OPTION_VALIDATOR] (state, { validationRule, validatorFunction }) { state.custom_options_validators = Object.assign( {}, state.custom_options_validators, - {[validationRule]: validatorFunction} + { [validationRule]: validatorFunction } ) }, [types.PRODUCT_SET_GALLERY] (state, productGallery) { diff --git a/core/modules/checkout/components/Shipping.ts b/core/modules/checkout/components/Shipping.ts index 4ba41bb131..d34af6a377 100644 --- a/core/modules/checkout/components/Shipping.ts +++ b/core/modules/checkout/components/Shipping.ts @@ -172,7 +172,7 @@ export const Shipping = { changeShippingMethod () { let currentShippingMethod = this.getCurrentShippingMethod() if (currentShippingMethod) { - this.shipping = Object.assign(this.shipping, {shippingCarrier: currentShippingMethod.carrier_code}) + this.shipping = Object.assign(this.shipping, { shippingCarrier: currentShippingMethod.carrier_code }) this.$bus.$emit('checkout-after-shippingMethodChanged', { country: this.shipping.country, method_code: currentShippingMethod.method_code, diff --git a/core/modules/checkout/index.ts b/core/modules/checkout/index.ts index e6ff6ee64d..18047616b1 100644 --- a/core/modules/checkout/index.ts +++ b/core/modules/checkout/index.ts @@ -5,7 +5,7 @@ import { shippingModule } from './store/shipping' import * as types from './store/checkout/mutation-types' import { StorageManager } from '@vue-storefront/core/lib/storage-manager' -export const CheckoutModule: StorefrontModule = function ({store}) { +export const CheckoutModule: StorefrontModule = function ({ store }) { StorageManager.init('checkout') store.registerModule('shipping', shippingModule) diff --git a/core/modules/checkout/store/checkout/actions.ts b/core/modules/checkout/store/checkout/actions.ts index 753ebb67bd..b8c9869d9b 100644 --- a/core/modules/checkout/store/checkout/actions.ts +++ b/core/modules/checkout/store/checkout/actions.ts @@ -12,7 +12,7 @@ const actions: ActionTree = { if (!result.resultCode || result.resultCode === 200) { await dispatch('updateOrderTimestamp') // clear cart without sync, because after order cart will be already cleared on backend - await dispatch('cart/clear', { sync: false }, {root: true}) + await dispatch('cart/clear', { sync: false }, { root: true }) await dispatch('dropPassword') } } catch (e) { diff --git a/core/modules/cms/helpers/createLoadingBlockQuery.ts b/core/modules/cms/helpers/createLoadingBlockQuery.ts index efb913fdc5..02ea841a96 100644 --- a/core/modules/cms/helpers/createLoadingBlockQuery.ts +++ b/core/modules/cms/helpers/createLoadingBlockQuery.ts @@ -4,7 +4,7 @@ const createLoadingBlockQuery = ({ filterField, filterValues }): SearchQuery => let query = new SearchQuery() if (filterValues) { - query = query.applyFilter({key: filterField, value: { like: filterValues }}) + query = query.applyFilter({ key: filterField, value: { like: filterValues } }) } return query diff --git a/core/modules/cms/index.ts b/core/modules/cms/index.ts index 0e9853970f..baaa06fb0b 100644 --- a/core/modules/cms/index.ts +++ b/core/modules/cms/index.ts @@ -5,7 +5,7 @@ import cmsPersistPlugin from './store/cmsPersistPlugin' import { StorefrontModule } from '@vue-storefront/core/lib/modules'; import { StorageManager } from '@vue-storefront/core/lib/storage-manager' -export const CmsModule: StorefrontModule = function ({store}) { +export const CmsModule: StorefrontModule = function ({ store }) { StorageManager.init('cms') store.registerModule('cmsPage', cmsPageModule) store.registerModule('cmsBlock', cmsBlockModule) diff --git a/core/modules/cms/store/hierarchy/actions.ts b/core/modules/cms/store/hierarchy/actions.ts index 741ca07dea..b556fa567f 100644 --- a/core/modules/cms/store/hierarchy/actions.ts +++ b/core/modules/cms/store/hierarchy/actions.ts @@ -5,7 +5,7 @@ import CmsHierarchyState from '../../types/CmsHierarchyState' import { createHierarchyLoadQuery } from '@vue-storefront/core/modules/cms/helpers' const actions: ActionTree = { - list (context, {id, entityType = 'cms_hierarchy', excludeFields = null, includeFields = null}) { + list (context, { id, entityType = 'cms_hierarchy', excludeFields = null, includeFields = null }) { return quickSearchByQuery({ query: createHierarchyLoadQuery({ id }), entityType, diff --git a/core/modules/cms/test/unit/blockActions.spec.ts b/core/modules/cms/test/unit/blockActions.spec.ts index 3f6d78d424..766b4293bd 100644 --- a/core/modules/cms/test/unit/blockActions.spec.ts +++ b/core/modules/cms/test/unit/blockActions.spec.ts @@ -28,7 +28,7 @@ describe('Block actions', () => { const filter = {}; const items = ['item1', 'item2', 'item3']; - (quickSearchByQuery as any).mockResolvedValue({items}); + (quickSearchByQuery as any).mockResolvedValue({ items }); const wrapper = (actions: any) => actions.list(contextMock, filter) let listAction = await wrapper(blockActions) @@ -75,7 +75,7 @@ describe('Block actions', () => { } const filter = {}; - (quickSearchByQuery as any).mockResolvedValue({items: ['item1', 'item2']}); + (quickSearchByQuery as any).mockResolvedValue({ items: ['item1', 'item2'] }); const wrapper = (actions: any) => actions.single(contextMock, filter) const singleAction = await wrapper(blockActions) @@ -87,7 +87,7 @@ describe('Block actions', () => { it('should add single block if cache is NOT skipped', async () => { const contextMock = { commit: jest.fn(), - getters: { findCmsBlocks: jest.fn(() => [{key: 'key1', value: 'val1'}]) } + getters: { findCmsBlocks: jest.fn(() => [{ key: 'key1', value: 'val1' }]) } } const filter = { skipCache: true }; @@ -105,7 +105,7 @@ describe('Block actions', () => { commit: jest.fn(), getters: { findCmsBlocks: jest.fn(() => [{ test: 'val1' }]) } } - const filter = {key: 'test', value: 'val1'}; + const filter = { key: 'test', value: 'val1' }; const wrapper = (actions: any) => actions.single(contextMock, filter) const singleAction = await wrapper(blockActions) diff --git a/core/modules/cms/test/unit/hierarchyActions.spec.ts b/core/modules/cms/test/unit/hierarchyActions.spec.ts index edbd8893d0..77242031c2 100644 --- a/core/modules/cms/test/unit/hierarchyActions.spec.ts +++ b/core/modules/cms/test/unit/hierarchyActions.spec.ts @@ -14,7 +14,7 @@ describe('Hierarchy actions', () => { it('should list hierarchy', async () => { const contextMock = {}; - const filter = {id: 1, entityType: 'cms_hierarchy', excludeFields: null, includeFields: null} + const filter = { id: 1, entityType: 'cms_hierarchy', excludeFields: null, includeFields: null } const wrapper = (actions: any) => actions.list(contextMock, filter); const listAction = await wrapper(hierarchyActions) diff --git a/core/modules/cms/test/unit/pageActions.spec.ts b/core/modules/cms/test/unit/pageActions.spec.ts index 9273039c9b..bcf14f34b8 100644 --- a/core/modules/cms/test/unit/pageActions.spec.ts +++ b/core/modules/cms/test/unit/pageActions.spec.ts @@ -29,7 +29,7 @@ describe('Page actions', () => { commit: jest.fn() }; - (quickSearchByQuery as any).mockResolvedValue({items: items}) + (quickSearchByQuery as any).mockResolvedValue({ items: items }) const wrapper = (actions: any) => actions.list(contextMock, filter) const listAction = await wrapper(pageActions) @@ -51,7 +51,7 @@ describe('Page actions', () => { dispatch: jest.fn() }; - (quickSearchByQuery as any).mockResolvedValue({items: ['item1']}) + (quickSearchByQuery as any).mockResolvedValue({ items: ['item1'] }) const wrapper = (actions: any) => actions.single(contextMock, filter) const singleAction = await wrapper(pageActions) @@ -71,7 +71,7 @@ describe('Page actions', () => { dispatch: jest.fn() }; - (quickSearchByQuery as any).mockResolvedValue({items: ['item1']}) + (quickSearchByQuery as any).mockResolvedValue({ items: ['item1'] }) const wrapper = (actions: any) => actions.single(contextMock, filter) const singleAction = await wrapper(pageActions) @@ -92,7 +92,7 @@ describe('Page actions', () => { dispatch: jest.fn() }; - (quickSearchByQuery as any).mockResolvedValue({items: ['item1']}) + (quickSearchByQuery as any).mockResolvedValue({ items: ['item1'] }) const wrapper = (actions: any) => actions.single(contextMock, filter) const singleAction = await wrapper(pageActions) @@ -112,7 +112,7 @@ describe('Page actions', () => { dispatch: jest.fn() }; - (quickSearchByQuery as any).mockResolvedValue({items: ['item1']}) + (quickSearchByQuery as any).mockResolvedValue({ items: ['item1'] }) const wrapper = (actions: any) => actions.single(contextMock, filter) const singleAction = await wrapper(pageActions) @@ -132,7 +132,7 @@ describe('Page actions', () => { dispatch: jest.fn() }; - (quickSearchByQuery as any).mockResolvedValue({items: ['item1']}) + (quickSearchByQuery as any).mockResolvedValue({ items: ['item1'] }) const wrapper = (actions: any) => actions.single(contextMock, filter) try { @@ -167,23 +167,23 @@ describe('Page actions', () => { }) it('should return cached response and set the page as current', async () => { - const filter = {key: 'test', value: 'value', setCurrent: true} + const filter = { key: 'test', value: 'value', setCurrent: true } const contextMock = { commit: jest.fn() } const wrapper = (actions: any) => actions.loadFromCache(contextMock, filter); (StorageManager as any).get.mockImplementationOnce((...args) => { return { - getItem: (...args) => Promise.resolve([{test: 'value'}]) + getItem: (...args) => Promise.resolve([{ test: 'value' }]) } }) const loadFromCacheAction = await wrapper(pageActions) - expect(contextMock.commit).toHaveBeenCalledWith(types.CMS_PAGE_SET_CURRENT, {test: 'value'}) - expect(loadFromCacheAction).toEqual({test: 'value'}) + expect(contextMock.commit).toHaveBeenCalledWith(types.CMS_PAGE_SET_CURRENT, { test: 'value' }) + expect(loadFromCacheAction).toEqual({ test: 'value' }) }) it('should return cached response and NOT set the page as current', async () => { - const filter = {key: 'test', value: 'value', setCurrent: false} + const filter = { key: 'test', value: 'value', setCurrent: false } const contextMock = { commit: jest.fn() } const wrapper = (actions: any) => actions.loadFromCache(contextMock, filter); (StorageManager as any).get.mockImplementationOnce((...args) => { @@ -194,16 +194,16 @@ describe('Page actions', () => { const loadFromCacheAction = await wrapper(pageActions) - expect(contextMock.commit).not.toHaveBeenCalledWith(types.CMS_PAGE_SET_CURRENT, {test: 'value'}) - expect(loadFromCacheAction).toEqual({test: 'value'}) + expect(contextMock.commit).not.toHaveBeenCalledWith(types.CMS_PAGE_SET_CURRENT, { test: 'value' }) + expect(loadFromCacheAction).toEqual({ test: 'value' }) }) it('should throw error when storedItems are empty', async () => { - const filter = {key: 'test', value: 'value', setCurrent: false} + const filter = { key: 'test', value: 'value', setCurrent: false } const contextMock = { commit: jest.fn() } const wrapper = (actions: any) => actions.loadFromCache(contextMock, filter); (StorageManager as any).get.mockImplementationOnce((...args: any) => { - return ({getItem: (...args: any) => Promise.resolve(undefined)}) + return ({ getItem: (...args: any) => Promise.resolve(undefined) }) }) try { @@ -216,11 +216,11 @@ describe('Page actions', () => { describe('loadFromCache action', () => { it('should throw error when cannot find given element in stored items', async () => { - const filter = {key: 'test', value: 'value', setCurrent: false} + const filter = { key: 'test', value: 'value', setCurrent: false } const contextMock = { commit: jest.fn() } const wrapper = (actions: any) => actions.loadFromCache(contextMock, filter); (StorageManager as any).get.mockImplementationOnce((...args: any) => { - return ({getItem: (...args: any) => Promise.resolve([])}) + return ({ getItem: (...args: any) => Promise.resolve([]) }) }) try { diff --git a/core/modules/compare/index.ts b/core/modules/compare/index.ts index 6a4ae61657..a33cb82560 100644 --- a/core/modules/compare/index.ts +++ b/core/modules/compare/index.ts @@ -4,7 +4,7 @@ import cachePersistPlugin from './store/plugin' import { StorefrontModule } from '@vue-storefront/core/lib/modules'; import { StorageManager } from '@vue-storefront/core/lib/storage-manager' -export const CompareModule: StorefrontModule = function ({store}) { +export const CompareModule: StorefrontModule = function ({ store }) { StorageManager.init('compare') store.registerModule('compare', compareStore) store.subscribe(cachePersistPlugin) diff --git a/core/modules/compare/store/actions.ts b/core/modules/compare/store/actions.ts index b9b1477885..37f2718b89 100644 --- a/core/modules/compare/store/actions.ts +++ b/core/modules/compare/store/actions.ts @@ -26,7 +26,7 @@ const actions: ActionTree = { async removeItem ({ commit }, product) { commit(types.COMPARE_DEL_ITEM, { product }) }, - async clear ({commit}) { + async clear ({ commit }) { commit(types.COMPARE_LOAD_COMPARE, []) } } diff --git a/core/modules/compare/store/mutations.ts b/core/modules/compare/store/mutations.ts index 3b2c0c8137..117b4936fc 100644 --- a/core/modules/compare/store/mutations.ts +++ b/core/modules/compare/store/mutations.ts @@ -7,13 +7,13 @@ const mutations: MutationTree = { * Add product to Compare * @param {Object} product data format for products is described in /doc/ElasticSearch data formats.md */ - [types.COMPARE_ADD_ITEM] (state, {product}) { + [types.COMPARE_ADD_ITEM] (state, { product }) { const record = state.items.find(p => p.sku === product.sku) if (!record) { state.items.push(product) } }, - [types.COMPARE_DEL_ITEM] (state, {product}) { + [types.COMPARE_DEL_ITEM] (state, { product }) { state.items = state.items.filter(p => p.sku !== product.sku) }, [types.COMPARE_LOAD_COMPARE] (state, storedItems) { diff --git a/core/modules/compare/test/unit/store/actions.spec.ts b/core/modules/compare/test/unit/store/actions.spec.ts index a41b71b17f..93cd16e885 100644 --- a/core/modules/compare/test/unit/store/actions.spec.ts +++ b/core/modules/compare/test/unit/store/actions.spec.ts @@ -23,7 +23,7 @@ let product describe('Compare actions', () => { beforeEach(() => { jest.clearAllMocks(); - product = {id: 'xyz'}; + product = { id: 'xyz' }; }); describe('load', () => { diff --git a/core/modules/mailer/index.ts b/core/modules/mailer/index.ts index b052161b2e..bcfc61ad2b 100644 --- a/core/modules/mailer/index.ts +++ b/core/modules/mailer/index.ts @@ -1,6 +1,6 @@ import { StorefrontModule } from '@vue-storefront/core/lib/modules' import { mailerStore } from './store' -export const MailerModule: StorefrontModule = function ({store}) { +export const MailerModule: StorefrontModule = function ({ store }) { store.registerModule('mailer', mailerStore) } diff --git a/core/modules/newsletter/index.ts b/core/modules/newsletter/index.ts index 991b482b6f..1650a2301c 100644 --- a/core/modules/newsletter/index.ts +++ b/core/modules/newsletter/index.ts @@ -2,7 +2,7 @@ import { newsletterStore } from './store' import { StorefrontModule } from '@vue-storefront/core/lib/modules'; import { StorageManager } from '@vue-storefront/core/lib/storage-manager' -export const NewsletterModule: StorefrontModule = function ({store}) { +export const NewsletterModule: StorefrontModule = function ({ store }) { StorageManager.init('newsletter') store.registerModule('newsletter', newsletterStore) } diff --git a/core/modules/notification/index.ts b/core/modules/notification/index.ts index a619b90ab4..3bf77ae235 100644 --- a/core/modules/notification/index.ts +++ b/core/modules/notification/index.ts @@ -1,6 +1,6 @@ import { notificationStore } from './store' import { StorefrontModule } from '@vue-storefront/core/lib/modules'; -export const NotificationModule: StorefrontModule = function ({store}) { +export const NotificationModule: StorefrontModule = function ({ store }) { store.registerModule('notification', notificationStore) } diff --git a/core/modules/order/index.ts b/core/modules/order/index.ts index fcabee6311..ed972d3e86 100644 --- a/core/modules/order/index.ts +++ b/core/modules/order/index.ts @@ -10,7 +10,7 @@ import { StorageManager } from '@vue-storefront/core/lib/storage-manager' import { isServer } from '@vue-storefront/core/helpers' import { StorefrontModule } from '@vue-storefront/core/lib/modules'; -export const OrderModule: StorefrontModule = function ({store}) { +export const OrderModule: StorefrontModule = function ({ store }) { StorageManager.init('orders') if (!isServer) { diff --git a/core/modules/order/test/unit/store/actions.spec.ts b/core/modules/order/test/unit/store/actions.spec.ts index 47401ac81c..453672c7d2 100644 --- a/core/modules/order/test/unit/store/actions.spec.ts +++ b/core/modules/order/test/unit/store/actions.spec.ts @@ -1107,7 +1107,7 @@ describe('Order actions', () => { (task) ); const contextMock = createContextMock(); - const order = {'transmited': true} + const order = { 'transmited': true } const order1 = { order_id: 'orderId', created_at: '10-29-2019', diff --git a/core/modules/recently-viewed/components/RecentlyViewed.js b/core/modules/recently-viewed/components/RecentlyViewed.js index c222f233c9..c402f9a307 100644 --- a/core/modules/recently-viewed/components/RecentlyViewed.js +++ b/core/modules/recently-viewed/components/RecentlyViewed.js @@ -1,4 +1,4 @@ -import {mapState} from 'vuex' +import { mapState } from 'vuex' export default { name: 'RecentlyViewed', diff --git a/core/modules/recently-viewed/index.ts b/core/modules/recently-viewed/index.ts index 7538ef3c76..3de14433c5 100644 --- a/core/modules/recently-viewed/index.ts +++ b/core/modules/recently-viewed/index.ts @@ -6,7 +6,7 @@ import { isServer } from '@vue-storefront/core/helpers' export const cacheStorage = StorageManager.init('recently-viewed') -export const RecentlyViewedModule: StorefrontModule = function ({store}) { +export const RecentlyViewedModule: StorefrontModule = function ({ store }) { store.registerModule('recently-viewed', recentlyViewedStore) store.subscribe(plugin) diff --git a/core/modules/recently-viewed/test/unit/actions.spec.ts b/core/modules/recently-viewed/test/unit/actions.spec.ts index 92ab857fc8..5e95bff9cb 100644 --- a/core/modules/recently-viewed/test/unit/actions.spec.ts +++ b/core/modules/recently-viewed/test/unit/actions.spec.ts @@ -13,7 +13,7 @@ let product describe('RecentlyViewed actions', () => { beforeEach(() => { jest.clearAllMocks(); - product = {id: 'xyz'}; + product = { id: 'xyz' }; }); describe('addItem', () => { diff --git a/core/modules/review/helpers/createLoadReviewsQuery.ts b/core/modules/review/helpers/createLoadReviewsQuery.ts index 73c4318286..8e127dfeb0 100644 --- a/core/modules/review/helpers/createLoadReviewsQuery.ts +++ b/core/modules/review/helpers/createLoadReviewsQuery.ts @@ -4,11 +4,11 @@ const createLoadReviewsQuery = ({ productId, approved }) => { let query = new SearchQuery() if (productId) { - query = query.applyFilter({key: 'product_id', value: {'eq': productId}}) + query = query.applyFilter({ key: 'product_id', value: { 'eq': productId } }) } if (approved) { - query = query.applyFilter({key: 'review_status', value: {'eq': 1}}) + query = query.applyFilter({ key: 'review_status', value: { 'eq': 1 } }) } return query diff --git a/core/modules/review/index.ts b/core/modules/review/index.ts index cf72bfa12b..ae53aa64d7 100644 --- a/core/modules/review/index.ts +++ b/core/modules/review/index.ts @@ -1,6 +1,6 @@ import { StorefrontModule } from '@vue-storefront/core/lib/modules' import { reviewStore } from './store' -export const ReviewModule: StorefrontModule = function ({store}) { +export const ReviewModule: StorefrontModule = function ({ store }) { store.registerModule('review', reviewStore) } diff --git a/core/modules/review/store/actions.ts b/core/modules/review/store/actions.ts index 5fee4b1b6a..55503d3fac 100644 --- a/core/modules/review/store/actions.ts +++ b/core/modules/review/store/actions.ts @@ -10,7 +10,7 @@ import { createLoadReviewsQuery } from '@vue-storefront/core/modules/review/help import { ReviewsService } from '@vue-storefront/core/data-resolver' const actions: ActionTree = { - async list (context, {productId, approved = true, start = 0, size = 50, entityType = 'review', sort = '', excludeFields = null, includeFields = null}) { + async list (context, { productId, approved = true, start = 0, size = 50, entityType = 'review', sort = '', excludeFields = null, includeFields = null }) { const query = createLoadReviewsQuery({ productId, approved }) const reviewResponse = await quickSearchByQuery({ query, start, size, entityType, sort, excludeFields, includeFields }) diff --git a/core/modules/review/test/unit/helpers/createLoadReviewsQuery.spec.ts b/core/modules/review/test/unit/helpers/createLoadReviewsQuery.spec.ts index c67cc97145..73c2d2652e 100644 --- a/core/modules/review/test/unit/helpers/createLoadReviewsQuery.spec.ts +++ b/core/modules/review/test/unit/helpers/createLoadReviewsQuery.spec.ts @@ -15,14 +15,14 @@ describe('createLoadReviewsQuery', () => { createLoadReviewsQuery({ productId: 123, approved: false }) expect(SearchQuery.applyFilter).toBeCalledTimes(1) - expect(SearchQuery.applyFilter).toBeCalledWith({key: 'product_id', value: {'eq': 123}}); + expect(SearchQuery.applyFilter).toBeCalledWith({ key: 'product_id', value: { 'eq': 123 } }); }); it('add filter for productId and approved arguments', () => { createLoadReviewsQuery({ productId: 123, approved: true }) expect(SearchQuery.applyFilter).toBeCalledTimes(2) - expect(SearchQuery.applyFilter).toBeCalledWith({key: 'product_id', value: {'eq': 123}}); - expect(SearchQuery.applyFilter).toBeCalledWith({key: 'review_status', value: {'eq': 1}}); + expect(SearchQuery.applyFilter).toBeCalledWith({ key: 'product_id', value: { 'eq': 123 } }); + expect(SearchQuery.applyFilter).toBeCalledWith({ key: 'review_status', value: { 'eq': 1 } }); }); }) diff --git a/core/modules/review/test/unit/store/actions.spec.ts b/core/modules/review/test/unit/store/actions.spec.ts index 05085e91a5..9d67aa46cb 100644 --- a/core/modules/review/test/unit/store/actions.spec.ts +++ b/core/modules/review/test/unit/store/actions.spec.ts @@ -32,7 +32,7 @@ jest.mock('@vue-storefront/core/lib/search/searchQuery', () => ({ })); jest.mock('@vue-storefront/core/lib/sync', () => ({ TaskQueue: { - execute: jest.fn(() => Promise.resolve({code: 200})) + execute: jest.fn(() => Promise.resolve({ code: 200 })) } })) jest.mock('@vue-storefront/core/data-resolver', () => ({ @@ -58,7 +58,7 @@ describe('Review actions', () => { await wrapper(reviewActions); - expect(createLoadReviewsQuery).toBeCalledWith({...payload, approved: true}); + expect(createLoadReviewsQuery).toBeCalledWith({ ...payload, approved: true }); }); it('make quick search by query with default values', async () => { diff --git a/core/modules/review/test/unit/store/mutations.spec.ts b/core/modules/review/test/unit/store/mutations.spec.ts index cd5affac74..4e7a70c034 100644 --- a/core/modules/review/test/unit/store/mutations.spec.ts +++ b/core/modules/review/test/unit/store/mutations.spec.ts @@ -11,7 +11,7 @@ describe('Review mutations', () => { const stateMock = { items: [] } - const reviewItem = {foo: '123'} + const reviewItem = { foo: '123' } const expectedState = { items: [ reviewItem diff --git a/core/modules/url/index.ts b/core/modules/url/index.ts index 8f4f45386f..7bf79ef533 100644 --- a/core/modules/url/index.ts +++ b/core/modules/url/index.ts @@ -5,7 +5,7 @@ import { StorageManager } from '@vue-storefront/core/lib/storage-manager' export const cacheStorage = StorageManager.init('url') -export const UrlModule: StorefrontModule = function ({store, router}) { +export const UrlModule: StorefrontModule = function ({ store, router }) { store.registerModule('url', urlStore) router.beforeEach(beforeEachGuard) } diff --git a/core/modules/url/store/actions.ts b/core/modules/url/store/actions.ts index 2532b8d6df..276c705971 100644 --- a/core/modules/url/store/actions.ts +++ b/core/modules/url/store/actions.ts @@ -1,3 +1,4 @@ +import { isServer } from '@vue-storefront/core/helpers'; import { UrlState } from '../types/UrlState' import { ActionTree } from 'vuex'; import * as types from './mutation-types' @@ -10,6 +11,7 @@ import { preProcessDynamicRoutes, normalizeUrlPath, parametrizeRouteData, getFal import { removeStoreCodeFromRoute, currentStoreView, localizedDispatcherRouteName } from '@vue-storefront/core/lib/multistore' import storeCodeFromRoute from '@vue-storefront/core/lib/storeCodeFromRoute' import isEqual from 'lodash-es/isEqual' +import omit from 'lodash-es/omit' // it's a good practice for all actions to return Promises with effect of their execution export const actions: ActionTree = { @@ -71,7 +73,7 @@ export const actions: ActionTree = { const { storeCode, appendStoreCode } = currentStoreView() const productQuery = new SearchQuery() url = (removeStoreCodeFromRoute(url.startsWith('/') ? url.slice(1) : url) as string) - productQuery.applyFilter({key: 'url_path', value: {'eq': url}}) // Tees category + productQuery.applyFilter({ key: 'url_path', value: { 'eq': url } }) // Tees category const products = await dispatch('product/list', { query: productQuery }, { root: true }) if (products && products.items && products.items.length) { const product = products.items[0] @@ -95,9 +97,28 @@ export const actions: ActionTree = { } } }, - setCurrentRoute ({ commit, state }, {to, from} = {}) { - commit(types.SET_CURRENT_ROUTE, to) - commit(types.IS_BACK_ROUTE, isEqual(state.prevRoute, state.currentRoute) && state.currentRoute.path !== from.path) - commit(types.SET_PREV_ROUTE, from) + setCurrentRoute ({ commit, state, rootGetters }, { to, from } = {}) { + commit(types.SET_CURRENT_ROUTE, { + ...to, + scrollPosition: {...state.prevRoute.scrollPosition}, + categoryPageSize: state.prevRoute.categoryPageSize + }) + + const sameAsPrevRoute = isEqual( + omit(state.prevRoute, ['scrollPosition', 'categoryPageSize']), + omit(state.currentRoute, ['scrollPosition', 'categoryPageSize']) + ) + const hasDifferentPath = (state.currentRoute && state.currentRoute.path) !== (from && from.path) + commit(types.IS_BACK_ROUTE, sameAsPrevRoute && hasDifferentPath) + + const scrollPosition = { + x: !isServer ? window.pageXOffset : 0, + y: !isServer ? window.pageYOffset : 0 + } + commit(types.SET_PREV_ROUTE, { + ...from, + scrollPosition, + categoryPageSize: rootGetters['category-next/getCategoryProducts'].length + }) } } diff --git a/core/modules/url/store/getters.ts b/core/modules/url/store/getters.ts index ee3e1a36c4..9de326e23c 100644 --- a/core/modules/url/store/getters.ts +++ b/core/modules/url/store/getters.ts @@ -1,4 +1,5 @@ export const getters = { getCurrentRoute: (state) => state.currentRoute, - isBackRoute: (state) => state.isBackRoute + isBackRoute: (state) => state.isBackRoute, + getPrevRoute: (state) => state.prevRoute } diff --git a/core/modules/url/store/mutations.ts b/core/modules/url/store/mutations.ts index 6523420c47..abbabf26d9 100644 --- a/core/modules/url/store/mutations.ts +++ b/core/modules/url/store/mutations.ts @@ -7,10 +7,10 @@ export const mutations: MutationTree = { state.dispatcherMap = Object.assign({}, state.dispatcherMap, { [payload.url]: payload.routeData }) }, [types.SET_CURRENT_ROUTE] (state, payload = {}) { - state.currentRoute = omit(payload, ['matched']) + state.currentRoute = omit({...payload}, ['matched']) }, [types.SET_PREV_ROUTE] (state, payload = {}) { - state.prevRoute = omit(payload, ['matched']) + state.prevRoute = omit({...payload}, ['matched']) }, [types.IS_BACK_ROUTE] (state, payload) { state.isBackRoute = payload diff --git a/core/modules/url/test/unit/helpers/formatCategoryLink.spec.ts b/core/modules/url/test/unit/helpers/formatCategoryLink.spec.ts index 487e706235..d18bd96794 100644 --- a/core/modules/url/test/unit/helpers/formatCategoryLink.spec.ts +++ b/core/modules/url/test/unit/helpers/formatCategoryLink.spec.ts @@ -20,7 +20,7 @@ describe('formatCategoryLink method', () => { beforeEach(() => { jest.clearAllMocks(); jest.mock('config', () => ({})); - (currentStoreView as jest.Mock).mockImplementation(() => ({storeCode: ''})); + (currentStoreView as jest.Mock).mockImplementation(() => ({ storeCode: '' })); category = { path: '1/2', is_active: true, @@ -71,7 +71,7 @@ describe('formatCategoryLink method', () => { describe('with default storeCode set to \'de\'', () => { beforeEach(() => { - (currentStoreView as jest.Mock).mockImplementation(() => ({storeCode: 'de'})); + (currentStoreView as jest.Mock).mockImplementation(() => ({ storeCode: 'de' })); }); it('should return formatted category url_path', () => { @@ -115,7 +115,7 @@ describe('formatCategoryLink method', () => { describe('with default storeCode set to \'de\'', () => { beforeEach(() => { - (currentStoreView as jest.Mock).mockImplementation(() => ({storeCode: 'de'})); + (currentStoreView as jest.Mock).mockImplementation(() => ({ storeCode: 'de' })); }); it('should return formatted category url_path', () => { @@ -131,7 +131,7 @@ describe('formatCategoryLink method', () => { describe('with default storeCode set to \'de\' and appendStoreCode is false', () => { beforeEach(() => { - (currentStoreView as jest.Mock).mockImplementation(() => ({storeCode: 'de', appendStoreCode: false})); + (currentStoreView as jest.Mock).mockImplementation(() => ({ storeCode: 'de', appendStoreCode: false })); }); it('should return formatted category url_path', () => { diff --git a/core/modules/url/test/unit/store/actions.spec.ts b/core/modules/url/test/unit/store/actions.spec.ts index 454b417fdf..bdbd29b02f 100644 --- a/core/modules/url/test/unit/store/actions.spec.ts +++ b/core/modules/url/test/unit/store/actions.spec.ts @@ -8,6 +8,7 @@ const SearchQuery = { applyFilter: jest.fn() }; +jest.mock('@vue-storefront/core/store', () => ({ Module: jest.fn() })) jest.mock('@vue-storefront/core/lib/search/searchQuery', () => () => SearchQuery ); @@ -228,7 +229,7 @@ describe('Url actions', () => { slug: 'shorts-19' }; - contextMock.dispatch.mockImplementation(() => Promise.resolve({slug: 'shorts-19'})) + contextMock.dispatch.mockImplementation(() => Promise.resolve({ slug: 'shorts-19' })) const result = await (urlActions as any).mappingFallback(contextMock, { url, params }); diff --git a/core/modules/url/test/unit/store/mutations.spec.ts b/core/modules/url/test/unit/store/mutations.spec.ts index 4f890d3a31..e5f0ee1a38 100644 --- a/core/modules/url/test/unit/store/mutations.spec.ts +++ b/core/modules/url/test/unit/store/mutations.spec.ts @@ -13,11 +13,11 @@ describe('url mutations', () => { } const payloadData = { url: 'https://www.example.com', - routeData: {name: 'example'} + routeData: { name: 'example' } } const expectedState = { dispatcherMap: { - 'https://www.example.com': {name: 'example'} + 'https://www.example.com': { name: 'example' } } } const wrapper = (mutations: any) => mutations[types.REGISTER_MAPPING](stateMock, payloadData) diff --git a/core/modules/url/types/UrlState.ts b/core/modules/url/types/UrlState.ts index 20c65b976c..bc4d3138ce 100644 --- a/core/modules/url/types/UrlState.ts +++ b/core/modules/url/types/UrlState.ts @@ -1,11 +1,19 @@ import { Route } from 'vue-router'; import { LocalizedRoute } from '@vue-storefront/core/lib/types' +interface UrlModuleRoute extends Partial { + scrollPosition?: { + x: number, + y: number + }, + categoryPageSize?: number +} + // This object should represent structure of your modules Vuex state // It's a good practice is to name this interface accordingly to the KET (for example mailchimpState) export interface UrlState { dispatcherMap: { [path: string]: LocalizedRoute}, - currentRoute: Partial, - prevRoute: Partial, + currentRoute: UrlModuleRoute, + prevRoute: UrlModuleRoute, isBackRoute: boolean } diff --git a/core/modules/user/components/UserShippingDetails.ts b/core/modules/user/components/UserShippingDetails.ts index d9aacfc805..8f9eeaa8b9 100644 --- a/core/modules/user/components/UserShippingDetails.ts +++ b/core/modules/user/components/UserShippingDetails.ts @@ -97,7 +97,7 @@ export const UserShippingDetails = { } else { updatedShippingDetails.addresses = updatedShippingDetails.addresses.map((address) => toString(address.id) === toString(this.currentUser.default_shipping) - ? {...address, ...updatedShippingDetailsAddress} // update default address if already exist + ? { ...address, ...updatedShippingDetailsAddress } // update default address if already exist : address ) } diff --git a/core/modules/user/index.ts b/core/modules/user/index.ts index cad4de1547..7d864b4735 100644 --- a/core/modules/user/index.ts +++ b/core/modules/user/index.ts @@ -5,7 +5,7 @@ import { isServer } from '@vue-storefront/core/helpers' import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' import * as types from './store/mutation-types' -export const UserModule: StorefrontModule = async function ({store}) { +export const UserModule: StorefrontModule = async function ({ store }) { StorageManager.init('user') store.registerModule('user', userStore) if (!isServer) { diff --git a/core/modules/user/store/actions.ts b/core/modules/user/store/actions.ts index 1b13787d00..16561ec8a9 100644 --- a/core/modules/user/store/actions.ts +++ b/core/modules/user/store/actions.ts @@ -213,7 +213,7 @@ const actions: ActionTree = { commit(types.USER_GROUP_CHANGED, null) commit(types.USER_INFO_LOADED, null) dispatch('wishlist/clear', null, { root: true }) - dispatch('compare/clear', null, {root: true}) + dispatch('compare/clear', null, { root: true }) dispatch('checkout/savePersonalDetails', {}, { root: true }) dispatch('checkout/saveShippingDetails', {}, { root: true }) dispatch('checkout/savePaymentDetails', {}, { root: true }) diff --git a/core/modules/user/test/unit/store/actions.spec.ts b/core/modules/user/test/unit/store/actions.spec.ts index e8f5bf2749..65dde3b43b 100644 --- a/core/modules/user/test/unit/store/actions.spec.ts +++ b/core/modules/user/test/unit/store/actions.spec.ts @@ -1,11 +1,11 @@ import * as types from '../../../store/mutation-types' import * as data from './data' import userActions from '../../../store/actions' -import {StorageManager} from '@vue-storefront/core/lib/storage-manager' -import {UserService} from '@vue-storefront/core/data-resolver' +import { StorageManager } from '@vue-storefront/core/lib/storage-manager' +import { UserService } from '@vue-storefront/core/data-resolver' import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' -jest.mock('@vue-storefront/i18n', () => ({t: jest.fn(str => str)})); +jest.mock('@vue-storefront/i18n', () => ({ t: jest.fn(str => str) })); jest.mock('@vue-storefront/core/lib/logger', () => ({ Logger: { log: jest.fn(() => () => { @@ -67,7 +67,7 @@ describe('User actions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: {isLocalDataLoaded: true} + getters: { isLocalDataLoaded: true } }; const wrapper = (actions: any) => actions.startSession(contextMock); @@ -83,7 +83,7 @@ describe('User actions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: {isLocalDataLoaded: false} + getters: { isLocalDataLoaded: false } }; const wrapper = (actions: any) => actions.startSession(contextMock); @@ -101,13 +101,13 @@ describe('User actions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: {isLocalDataLoaded: false} + getters: { isLocalDataLoaded: false } }; const wrapper = (actions: any) => actions.startSession(contextMock); await wrapper(userActions); - expect(contextMock.commit).toBeCalledWith(types.USER_TOKEN_CHANGED, {newToken: data.lastUserToken}) + expect(contextMock.commit).toBeCalledWith(types.USER_TOKEN_CHANGED, { newToken: data.lastUserToken }) }) it('should call setUserGroup action', async () => { (StorageManager.get as jest.Mock).mockImplementation(() => ({ @@ -117,7 +117,7 @@ describe('User actions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: {isLocalDataLoaded: false} + getters: { isLocalDataLoaded: false } }; const wrapper = (actions: any) => actions.startSession(contextMock); @@ -133,7 +133,7 @@ describe('User actions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: {isLocalDataLoaded: false} + getters: { isLocalDataLoaded: false } }; const wrapper = (actions: any) => actions.startSession(contextMock); @@ -152,10 +152,10 @@ describe('User actions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: {isLocalDataLoaded: false} + getters: { isLocalDataLoaded: false } }; const email = data.email; - const result = (userActions as any).resetPassword(contextMock, {email}); + const result = (userActions as any).resetPassword(contextMock, { email }); expect(result).toEqual(data.responseOb) }) @@ -170,16 +170,16 @@ describe('User actions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: {isLocalDataLoaded: false} + getters: { isLocalDataLoaded: false } }; const refreshValue = data.refresh; const useCacheValue = !data.useCache; const rootValue = true; const username = data.username; const password = data.password; - const result = await (userActions as any).login(contextMock, {username, password}); + const result = await (userActions as any).login(contextMock, { username, password }); - expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'resetUserInvalidateLock', {}, {root: rootValue}) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'resetUserInvalidateLock', {}, { root: rootValue }) expect(contextMock.commit).toHaveBeenCalledWith(types.USER_TOKEN_CHANGED, { newToken: data.responseOb.result, meta: data.responseOb.meta @@ -202,11 +202,11 @@ describe('User actions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: {isLocalDataLoaded: false} + getters: { isLocalDataLoaded: false } }; const password = data.password; const customer = data.customer; - const result = await (userActions as any).register(contextMock, {password, customer}); + const result = await (userActions as any).register(contextMock, { password, customer }); expect(result).toEqual(data.responseOb) }) @@ -227,7 +227,7 @@ describe('User actions', () => { const newToken = data.lastUserToken const result = await (userActions as any).refresh(contextMock) - expect(contextMock.commit).toBeCalledWith(types.USER_TOKEN_CHANGED, {newToken}); + expect(contextMock.commit).toBeCalledWith(types.USER_TOKEN_CHANGED, { newToken }); expect(result).toEqual(newToken) }) }); @@ -255,20 +255,20 @@ describe('User actions', () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: {isLocalDataLoaded: false} + getters: { isLocalDataLoaded: false } }; const result = await (userActions as any).restoreCurrentUserFromCache(contextMock) expect(contextMock.commit).toHaveBeenCalledWith(types.USER_INFO_LOADED, data.user) expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'setUserGroup', data.user) - expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'cart/authorize', {}, {root: true}) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'cart/authorize', {}, { root: true }) expect(result).toEqual(data.user) }) it('should return null if is not cached', async () => { const contextMock = { commit: jest.fn(), dispatch: jest.fn(), - getters: {isLocalDataLoaded: false} + getters: { isLocalDataLoaded: false } }; const result = await (userActions as any).restoreCurrentUserFromCache(contextMock) @@ -290,14 +290,14 @@ describe('User actions', () => { it('should load current user profile if getToken is not empty', async () => { const contextMock = { dispatch: jest.fn(), - getters: {getToken: data.lastUserToken} + getters: { getToken: data.lastUserToken } } const resolvedFromCache = !data.resolvedFromCache await (userActions as any).me(contextMock) expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'restoreCurrentUserFromCache') - expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'refreshUserProfile', {resolvedFromCache}) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'refreshUserProfile', { resolvedFromCache }) }) }); @@ -313,7 +313,7 @@ describe('User actions', () => { await (userActions as any).handleUpdateProfile(contextMock, responseOb) - expect(contextMock.dispatch).toHaveBeenCalledWith('user/setCurrentUser', responseOb.result, {root: true}) + expect(contextMock.dispatch).toHaveBeenCalledWith('user/setCurrentUser', responseOb.result, { root: true }) }) }); @@ -337,7 +337,7 @@ describe('User actions', () => { const contextMock = { dispatch: jest.fn(), - getters: {getUserEmail: data.email} + getters: { getUserEmail: data.email } } const passwordData = { currentPassword: data.password, @@ -375,8 +375,8 @@ describe('User actions', () => { expect(contextMock.dispatch).toBeCalledWith('notification/spawnNotification', { type: 'error', message: responseOb.result.errorMessage, - action1: {label: 'OK'} - }, {root: true}) + action1: { label: 'OK' } + }, { root: true }) }) }); @@ -393,11 +393,11 @@ describe('User actions', () => { expect(contextMock.commit).toHaveBeenNthCalledWith(2, types.USER_GROUP_TOKEN_CHANGED, '') expect(contextMock.commit).toHaveBeenNthCalledWith(3, types.USER_GROUP_CHANGED, null) expect(contextMock.commit).toHaveBeenNthCalledWith(4, types.USER_INFO_LOADED, null) - expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'wishlist/clear', null, {root: true}) - expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'compare/clear', null, {root: true}) - expect(contextMock.dispatch).toHaveBeenNthCalledWith(3, 'checkout/savePersonalDetails', {}, {root: true}) - expect(contextMock.dispatch).toHaveBeenNthCalledWith(4, 'checkout/saveShippingDetails', {}, {root: true}) - expect(contextMock.dispatch).toHaveBeenNthCalledWith(5, 'checkout/savePaymentDetails', {}, {root: true}) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'wishlist/clear', null, { root: true }) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'compare/clear', null, { root: true }) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(3, 'checkout/savePersonalDetails', {}, { root: true }) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(4, 'checkout/saveShippingDetails', {}, { root: true }) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(5, 'checkout/savePaymentDetails', {}, { root: true }) }) }); @@ -412,14 +412,14 @@ describe('User actions', () => { await (userActions as any).logout(contextMock, silent) expect(contextMock.commit).toBeCalledWith(types.USER_END_SESSION) - expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'cart/disconnect', {}, {root: true}) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'cart/disconnect', {}, { root: true }) expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'clearCurrentUser') - expect(contextMock.dispatch).toHaveBeenNthCalledWith(3, 'cart/clear', { sync: false }, {root: true}) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(3, 'cart/clear', { sync: false }, { root: true }) expect(contextMock.dispatch).toHaveBeenNthCalledWith(4, 'notification/spawnNotification', { type: 'success', message: "You're logged out", - action1: {label: 'OK'} - }, {root: true}) + action1: { label: 'OK' } + }, { root: true }) }) }); @@ -504,7 +504,7 @@ describe('User actions', () => { contextMock.dispatch.mockImplementationOnce(() => Promise.resolve(data.ordersHistory)) - await (userActions as any).getOrdersHistory(contextMock, {refresh, useCache, pageSize, currentPage}) + await (userActions as any).getOrdersHistory(contextMock, { refresh, useCache, pageSize, currentPage }) expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'loadOrdersFromCache') expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'refreshOrdersHistory', { @@ -523,10 +523,10 @@ describe('User actions', () => { const refresh = data.refresh; const useCache = data.useCache; - await (userActions as any).sessionAfterAuthorized(contextMock, {refresh, useCache}) + await (userActions as any).sessionAfterAuthorized(contextMock, { refresh, useCache }) - expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'me', {refresh, useCache}) - expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'getOrdersHistory', {refresh, useCache}) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(1, 'me', { refresh, useCache }) + expect(contextMock.dispatch).toHaveBeenNthCalledWith(2, 'getOrdersHistory', { refresh, useCache }) }) }) }) diff --git a/core/modules/user/test/unit/store/data.ts b/core/modules/user/test/unit/store/data.ts index 85347ec418..0ee35070ac 100644 --- a/core/modules/user/test/unit/store/data.ts +++ b/core/modules/user/test/unit/store/data.ts @@ -54,15 +54,15 @@ let user = { ], 'disable_auto_group_change': 0 }; -let lastUserToken: string = 'current-refresh-token'; +let lastUserToken = 'current-refresh-token'; let responseOb = { code: 200, result: lastUserToken, meta: 'meta' }; -let email: string = 'examplename@example.com'; -let username: string = 'username'; -let password: string = 'Password456'; +let email = 'examplename@example.com'; +let username = 'username'; +let password = 'Password456'; let customer = { email: 'examplename@example.com', firstname: 'ExampleFirstName', @@ -70,11 +70,11 @@ let customer = { addresses: 'addr' }; let ordersHistory = 'orders-history'; -let refresh: boolean = true; -let useCache: boolean = true; -let resolvedFromCache: boolean = true; -let pageSize: number = 20; -let currentPage: number = 1; +let refresh = true; +let useCache = true; +let resolvedFromCache = true; +let pageSize = 20; +let currentPage = 1; export { user, lastUserToken, responseOb, email, username, password, customer, diff --git a/core/modules/user/test/unit/store/mutations.spec.ts b/core/modules/user/test/unit/store/mutations.spec.ts index f1bb0f6bf7..6fd20ec91a 100644 --- a/core/modules/user/test/unit/store/mutations.spec.ts +++ b/core/modules/user/test/unit/store/mutations.spec.ts @@ -22,7 +22,7 @@ describe('User mutations', () => { const expectedState = { token: data.lastUserToken } - const wrapper = (mutations: any) => mutations[types.USER_TOKEN_CHANGED](stateMock, {newToken: data.lastUserToken}) + const wrapper = (mutations: any) => mutations[types.USER_TOKEN_CHANGED](stateMock, { newToken: data.lastUserToken }) wrapper(userMutations) @@ -39,7 +39,7 @@ describe('User mutations', () => { } const wrapper = (mutations: any) => mutations[types.USER_TOKEN_CHANGED](stateMock, { newToken: data.lastUserToken, - meta: {refreshToken: 'refresh-token'} + meta: { refreshToken: 'refresh-token' } }) wrapper(userMutations) diff --git a/core/modules/wishlist/index.ts b/core/modules/wishlist/index.ts index 1183dd8d42..0b54107bb3 100644 --- a/core/modules/wishlist/index.ts +++ b/core/modules/wishlist/index.ts @@ -3,7 +3,7 @@ import { wishlistStore } from './store' import whishListPersistPlugin from './store/whishListPersistPlugin' import { StorageManager } from '@vue-storefront/core/lib/storage-manager' -export const WishlistModule: StorefrontModule = function ({store}) { +export const WishlistModule: StorefrontModule = function ({ store }) { StorageManager.init('wishlist') store.registerModule('wishlist', wishlistStore) store.subscribe(whishListPersistPlugin) diff --git a/core/package.json b/core/package.json index 950a554eaa..c7c7654453 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "@vue-storefront/core", - "version": "1.11.2", + "version": "1.11.3", "description": "Vue Storefront Core", "license": "MIT", "main": "app.js", diff --git a/core/pages/Product.js b/core/pages/Product.js index 2601e94315..439cd9d882 100644 --- a/core/pages/Product.js +++ b/core/pages/Product.js @@ -182,7 +182,7 @@ export default { onAfterFilterChanged (filterOption) { this.$bus.$emit('product-before-configure', { filterOption: filterOption, configuration: this.configuration }) const prevOption = this.configuration[filterOption.attribute_code] - let changedConfig = Object.assign({}, this.configuration, {[filterOption.attribute_code]: filterOption}) + let changedConfig = Object.assign({}, this.configuration, { [filterOption.attribute_code]: filterOption }) this.$forceUpdate() // this is to update the available options regarding current selection this.$store.dispatch('product/configure', { product: this.product, @@ -192,7 +192,7 @@ export default { setProductErorrs: true }).then((selectedVariant) => { if (config.products.setFirstVarianAsDefaultInURL) { - this.$router.push({params: { childSku: selectedVariant.sku }}) + this.$router.push({ params: { childSku: selectedVariant.sku } }) } if (!selectedVariant) { if (typeof prevOption !== 'undefined' && prevOption) { diff --git a/core/scripts/installer.js b/core/scripts/installer.js index f8dc04fb0b..e7a2f72ec8 100644 --- a/core/scripts/installer.js +++ b/core/scripts/installer.js @@ -59,7 +59,7 @@ class Message { message([ ...text - ], {color: 'blue', border: false, marginTop: 1}) + ], { color: 'blue', border: false, marginTop: 1 }) } /** @@ -88,7 +88,7 @@ class Message { ...text, '', logDetailsInfo - ], {borderColor: 'red', marginBottom: 1}) + ], { borderColor: 'red', marginBottom: 1 }) shell.exit(1) } @@ -104,7 +104,7 @@ class Message { message([ 'WARNING:', ...text - ], {color: 'yellow', border: false, marginTop: 1}) + ], { color: 'yellow', border: false, marginTop: 1 }) } /** @@ -118,7 +118,7 @@ class Message { message([ ...text - ], Object.assign(isLastMessage ? {marginTop: 1} : {}, {borderColor: 'green', marginBottom: 1})) + ], Object.assign(isLastMessage ? { marginTop: 1 } : {}, { borderColor: 'green', marginBottom: 1 })) } } @@ -270,7 +270,7 @@ class Backend extends Abstract { config.magento2.api.accessToken = this.answers.m2_api_access_token || config.magento2.api.accessToken config.magento2.api.accessTokenSecret = this.answers.m2_api_access_token_secret || config.magento2.api.accessTokenSecret - jsonFile.writeFileSync(TARGET_BACKEND_CONFIG_FILE, config, {spaces: 2}) + jsonFile.writeFileSync(TARGET_BACKEND_CONFIG_FILE, config, { spaces: 2 }) } catch (e) { reject(new Error('Can\'t create backend config. Original error: ' + e)) } @@ -462,7 +462,7 @@ class Storefront extends Abstract { backend_dir: this.answers.backend_dir || false } - jsonFile.writeFileSync(TARGET_FRONTEND_CONFIG_FILE, config, {spaces: 2}) + jsonFile.writeFileSync(TARGET_FRONTEND_CONFIG_FILE, config, { spaces: 2 }) } catch (e) { reject(new Error('Can\'t create storefront config.')) } @@ -536,7 +536,7 @@ class Manager extends Abstract { Message.info('Trying to create log files...') try { - mkdirp.sync(LOG_DIR, {mode: parseInt('0755', 8)}) + mkdirp.sync(LOG_DIR, { mode: parseInt('0755', 8) }) let logFiles = [ INSTALL_LOG_FILE, @@ -681,7 +681,7 @@ let questions = [ }, validate: function (value) { try { - mkdirp.sync(value, {mode: parseInt('0755', 8)}) + mkdirp.sync(value, { mode: parseInt('0755', 8) }) if (!isEmptyDir.sync(value)) { return 'Please provide path to empty directory.' diff --git a/core/server/hooks.ts b/core/server/hooks.ts index f7941c7955..6308713433 100644 --- a/core/server/hooks.ts +++ b/core/server/hooks.ts @@ -8,7 +8,7 @@ const { executor: afterProcessStartedExecutor } = createListenerHook() -interface beforeCacheInvalidatedParamter { +interface BeforeCacheInvalidatedParamter { tags: string[], req: Request } @@ -16,7 +16,7 @@ interface beforeCacheInvalidatedParamter { const { hook: beforeCacheInvalidatedHook, executor: beforeCacheInvalidatedExecutor -} = createListenerHook() +} = createListenerHook() const { hook: afterCacheInvalidatedHook, diff --git a/docs/package.json b/docs/package.json index e2242812a0..b7315a7711 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,7 +1,7 @@ { "name": "@vue-storefront/docs", "private": true, - "version": "1.11.2", + "version": "1.11.3", "scripts": { "docs:dev": "vuepress dev", "docs:build": "vuepress build", diff --git a/package.json b/package.json index b8d13fd5d3..bf98970556 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-storefront", - "version": "1.11.2", + "version": "1.11.3", "description": "A Vue.js, PWA eCommerce frontend", "private": true, "engines": { @@ -123,7 +123,7 @@ "detect-installed": "^2.0.4", "empty-dir": "^1.0.0", "eslint": "^5.0.0", - "eslint-config-standard": "^11.0.0", + "eslint-config-standard": "^12.0.0", "eslint-friendly-formatter": "^4.0.1", "eslint-loader": "^2.0.0", "eslint-plugin-import": "^2.13.0", diff --git a/src/modules/amp-renderer/index.ts b/src/modules/amp-renderer/index.ts index 92d659b4ae..f3bdf71469 100644 --- a/src/modules/amp-renderer/index.ts +++ b/src/modules/amp-renderer/index.ts @@ -10,7 +10,7 @@ const ampRendererStore = { } } -export const AmpRendererModule: StorefrontModule = function ({store, router}) { +export const AmpRendererModule: StorefrontModule = function ({ store, router }) { store.registerModule('amp-renderer', ampRendererStore) setupMultistoreRoutes(config, router, moduleRoutes, 10) } diff --git a/src/modules/google-analytics/index.ts b/src/modules/google-analytics/index.ts index ce7ccd9a82..5a20b46fd7 100644 --- a/src/modules/google-analytics/index.ts +++ b/src/modules/google-analytics/index.ts @@ -11,7 +11,7 @@ const googleAnalyticsStore = { } } -export const GoogleAnalyticsModule: StorefrontModule = function ({store, router, appConfig}) { +export const GoogleAnalyticsModule: StorefrontModule = function ({ store, router, appConfig }) { if (appConfig.analytics.id && !isServer) { once('__VUE_EXTEND_ANALYTICS__', () => { Vue.use(VueAnalytics, { diff --git a/src/modules/google-tag-manager/index.ts b/src/modules/google-tag-manager/index.ts index b50ab6cf3d..236c80ef15 100644 --- a/src/modules/google-tag-manager/index.ts +++ b/src/modules/google-tag-manager/index.ts @@ -10,7 +10,7 @@ import { afterRegistration, isEnabled } from './hooks/afterRegistration' export const KEY = 'google-tag-manager' -export const GoogleTagManagerModule: StorefrontModule = function ({store, router, appConfig}) { +export const GoogleTagManagerModule: StorefrontModule = function ({ store, router, appConfig }) { if (isEnabled(appConfig.googleTagManager.id)) { once('__VUE_EXTEND_GTM__', () => { Vue.use(VueGtm, { diff --git a/src/modules/hotjar/index.ts b/src/modules/hotjar/index.ts index f2aadceab7..850aba3d31 100644 --- a/src/modules/hotjar/index.ts +++ b/src/modules/hotjar/index.ts @@ -14,7 +14,7 @@ const hotjarSnippet = (hjid) => (function (h, o, t, j, a, r) { function () { (h.hj.q = h.hj.q || []).push(arguments); }; - h._hjSettings = {hjid, hjsv: 6}; + h._hjSettings = { hjid, hjsv: 6 }; a = o.getElementsByTagName('head')[0]; r = o.createElement('script'); r.async = 1; @@ -22,7 +22,7 @@ const hotjarSnippet = (hjid) => (function (h, o, t, j, a, r) { a.appendChild(r); })(window as any, document, '//static.hotjar.com/c/hotjar-', '.js?sv='); -export const HotjarModule: StorefrontModule = function ({store, appConfig}) { +export const HotjarModule: StorefrontModule = function ({ store, appConfig }) { store.registerModule('hotjar', hotjarStore) if (!isServer && appConfig.hotjar && appConfig.hotjar.id) { diff --git a/src/modules/instant-checkout/components/InstantCheckout.vue b/src/modules/instant-checkout/components/InstantCheckout.vue index 86f4f9d2b9..461ebb499a 100644 --- a/src/modules/instant-checkout/components/InstantCheckout.vue +++ b/src/modules/instant-checkout/components/InstantCheckout.vue @@ -143,14 +143,14 @@ export default { .show() .then(response => { // TODO handle payment - this.$store.dispatch('order/placeOrder', this.createOrder(response), {root: true}).then(result => { + this.$store.dispatch('order/placeOrder', this.createOrder(response), { root: true }).then(result => { if (!result.resultCode || result.resultCode === 200) { response.complete() this.$store.dispatch('checkout/setThankYouPage', true) this.$store.commit('ui/setMicrocart', false) this.$router.push(this.localizedRoute('/checkout')) // clear cart without sync, because after order cart will be already cleared on backend - this.$store.dispatch('cart/clear', { sync: false }, {root: true}) + this.$store.dispatch('cart/clear', { sync: false }, { root: true }) } }) }) diff --git a/src/modules/payment-backend-methods/index.ts b/src/modules/payment-backend-methods/index.ts index 30b99085d1..ab1617afc8 100644 --- a/src/modules/payment-backend-methods/index.ts +++ b/src/modules/payment-backend-methods/index.ts @@ -15,7 +15,7 @@ const PaymentBackendMethodsStore = { } } -export const PaymentBackendMethodsModule: StorefrontModule = function ({store}) { +export const PaymentBackendMethodsModule: StorefrontModule = function ({ store }) { store.registerModule('payment-backend-methods', PaymentBackendMethodsStore) let correctPaymentMethod = false diff --git a/src/modules/payment-cash-on-delivery/index.ts b/src/modules/payment-cash-on-delivery/index.ts index c7507bb5e4..d9645a46d0 100644 --- a/src/modules/payment-cash-on-delivery/index.ts +++ b/src/modules/payment-cash-on-delivery/index.ts @@ -4,7 +4,7 @@ import Vue from 'vue'; import InfoComponent from './components/Info.vue' import EventBus from '@vue-storefront/core/compatibility/plugins/event-bus' -export const PaymentCashOnDeliveryModule: StorefrontModule = function ({store}) { +export const PaymentCashOnDeliveryModule: StorefrontModule = function ({ store }) { // Place the order. Payload is empty as we don't have any specific info to add for this payment method '{}' let correctPaymentMethod = false const placeOrder = () => { diff --git a/src/themes/default-amp/package.json b/src/themes/default-amp/package.json index 6eda02a9a6..a04ddf3c35 100755 --- a/src/themes/default-amp/package.json +++ b/src/themes/default-amp/package.json @@ -1,6 +1,6 @@ { "name": "@vue-storefront/theme-default-amp", - "version": "1.11.2", + "version": "1.11.3", "description": "Default AMP theme for Vue Storefront", "main": "index.js", "scripts": { diff --git a/src/themes/default/components/core/CookieNotification.vue b/src/themes/default/components/core/CookieNotification.vue index 2716d39280..68ad22f71a 100644 --- a/src/themes/default/components/core/CookieNotification.vue +++ b/src/themes/default/components/core/CookieNotification.vue @@ -57,14 +57,14 @@ export default { this.isOpen = false }, setVisited () { - this.$store.dispatch('claims/set', {claimCode: 'cookiesAccepted', value: true}) + this.$store.dispatch('claims/set', { claimCode: 'cookiesAccepted', value: true }) } }, mounted () { - this.$store.dispatch('claims/check', {claimCode: 'cookiesAccepted'}).then((cookieClaim) => { + this.$store.dispatch('claims/check', { claimCode: 'cookiesAccepted' }).then((cookieClaim) => { if (!cookieClaim) { this.isOpen = true - this.$store.dispatch('claims/set', {claimCode: 'cookiesAccepted', value: false}) + this.$store.dispatch('claims/set', { claimCode: 'cookiesAccepted', value: false }) } else { this.isOpen = !cookieClaim.value } diff --git a/src/themes/default/components/core/ProductCustomOptions.vue b/src/themes/default/components/core/ProductCustomOptions.vue index a3ebba2fbf..a6eea550cd 100644 --- a/src/themes/default/components/core/ProductCustomOptions.vue +++ b/src/themes/default/components/core/ProductCustomOptions.vue @@ -23,11 +23,11 @@ type="radio" class="m0 no-outline" :name="('customOption_' + option.option_id)" - :id="('customOption_' + opval.option_type_id)" + :id="('customOption_' + option.option_id + '_' + opval.option_type_id)" focus :value="opval.option_type_id" v-model="inputValues[('customOption_' + option.option_id)]" - >