From 7eea48b3ab39ee3460c2d0068ac568cbdfa96217 Mon Sep 17 00:00:00 2001 From: amansinghbais Date: Thu, 7 Sep 2023 11:50:44 +0530 Subject: [PATCH 1/4] Implemented: support for dynamic features for product variants in product summary page (#166) --- src/views/catalog-product-details.vue | 160 +++++++++++++++++--------- 1 file changed, 106 insertions(+), 54 deletions(-) diff --git a/src/views/catalog-product-details.vue b/src/views/catalog-product-details.vue index 5ccad313..75c85e46 100644 --- a/src/views/catalog-product-details.vue +++ b/src/views/catalog-product-details.vue @@ -21,24 +21,13 @@

{{ currentVariant.sku }}

-
- - {{ $t("Colors") }} - - - - {{ colorFeature }} - - - - - - - {{ $t("Sizes") }} +
+ + {{ featureType.charAt(0) + featureType.substring(1).toLowerCase() }} - - {{ sizeFeature }} + + {{ featureValue }} @@ -462,9 +451,7 @@ export default defineComponent({ return { variantId: '', productId: '', - selectedColor: '', - selectedSize: '', - features: [] as any, + features: {} as any, currentVariant: {} as any, poAndAtpDetails: {} as any, atpCalcDetails: {} as any, @@ -474,7 +461,9 @@ export default defineComponent({ configsByStores: [] as any, listingJobRunTime: 0, backorderCategoryId: '', - preOrderCategoryId: '' + preOrderCategoryId: '', + selectedVariant: {} as any, + selectedFeature: '' } }, computed: { @@ -516,58 +505,110 @@ export default defineComponent({ async getVariantDetails() { await this.store.dispatch('product/setCurrentCatalogProduct', { productId: this.productId}) if (this.product.variants) { - this.getFeatures() - await this.updateVariant() + + await this.getFeatures() + this.updateFeatures() } }, - applyFeature(feature: string, type: string) { - if (type === 'color') this.selectedColor = feature - else if (type === 'size') this.selectedSize = feature - this.updateVariant(); + applyFeature(featureValue: string, featureType: string) { + this.selectedFeature = featureType + this.selectedVariant[featureType] = featureValue + + this.updateFeatures() + }, + updateFeatures() { + Object.entries(this.selectedVariant).map((feature, featureIndex) => { + const nextFeature = Object.entries(this.selectedVariant).find((currentFeature, currentFeatureIndex) => currentFeatureIndex === featureIndex + 1) + + if(nextFeature){ + const nextFeatureType = nextFeature[0] + const availableVariants = this.product.variants.filter((variant: any) => { + let isVariantAvailable = true + Object.entries(this.selectedVariant).map((currentFeature, currentFeatureIndex) => { + if(currentFeatureIndex <= featureIndex && getFeature(variant.featureHierarchy, `1/${currentFeature[0]}`) != currentFeature[1]){ + isVariantAvailable = false + } + }) + return isVariantAvailable + }) + + const nextFeatureAvailableValues = [] as any + availableVariants.map((variant: any) => { + nextFeatureAvailableValues.push(getFeature(variant.featureHierarchy , `1/${nextFeatureType}`)) + }) + this.features[nextFeatureType] = nextFeatureType === 'SIZE' ? sortSizes(nextFeatureAvailableValues) : nextFeatureAvailableValues + } + }) + this.updateVariant() }, getFeatures() { - const features = {} as any + let features = {} as any this.product.variants.map((variant: any) => { - const size = getFeature(variant.featureHierarchy, '1/SIZE/') - const color = getFeature(variant.featureHierarchy, '1/COLOR/') - if (!features[color]) features[color] = [size] - else if (!features[color].includes(size)) features[color].push(size) + variant.featureHierarchy.map((featureItem: any) => { + if(featureItem.startsWith('1/')){ + const featureType = featureItem.split('/')[1] + const featureValue = featureItem.split('/')[2] + + if (!features[featureType]) features[featureType] = [featureValue] + else if (!features[featureType].includes(featureValue)) features[featureType].push(featureValue) + } + }) }) - Object.keys(features).forEach((color) => this.features[color] = sortSizes(features[color])) - - let selectedVariant = this.product.variants.find((variant: any) => variant.productId === this.variantId) - + features = Object.keys(features).sort().reduce((result: any, key) => { + result[key] = features[key]; + return result; + }, {}); + + Object.keys(features).forEach((feature) => this.features[feature] = features[feature].sort()) + + let selectedVariant = this.product.variants.find((variant: any) => variant.productId === this.variantId) + let selectedVariantFeatures = {} as any + if (!selectedVariant) { - // if the variant does not have color or size as features - selectedVariant = this.product.variants[0] - showToast(translate("Selected variant not available. Reseting to first variant.")) - } - + // if the selected variant can't be found set it to the first variant of the product. + selectedVariant = this.product.variants[0] + showToast(translate("Selected variant not available. Reseting to first variant.")) + } + if (selectedVariant) { - this.selectedColor = getFeature(selectedVariant.featureHierarchy, '1/COLOR/') - this.selectedSize = getFeature(selectedVariant.featureHierarchy, '1/SIZE/') + selectedVariant.featureHierarchy.map((featureItem: any) => { + if(featureItem.startsWith('1/')){ + const featureItemSplitted = featureItem.split("/") + selectedVariantFeatures[featureItemSplitted[1]] = featureItemSplitted[2] + } + }) + + selectedVariantFeatures = Object.keys(selectedVariantFeatures).sort().reduce((result:any, key) => { + result[key] = selectedVariantFeatures[key]; + return result; + }, {}); + this.selectedVariant = selectedVariantFeatures } }, async updateVariant() { let variant - if (this.selectedColor || this.selectedSize) { - variant = this.product.variants.find((variant: any) => { - const hasSize = !this.selectedSize || (this.selectedSize && getFeature(variant.featureHierarchy, '1/SIZE/') === this.selectedSize) - const hasColor = !this.selectedColor || (this.selectedColor && getFeature(variant.featureHierarchy, '1/COLOR/') === this.selectedColor) - return hasSize && hasColor - }) - - // if the selected size is not available for that color, default it to the first size available + if (this.selectedFeature) { + variant = this.getVariant() + if (!variant) { - this.selectedSize = this.features[this.selectedColor][0]; - variant = this.product.variants.find((variant: any) => getFeature(variant.featureHierarchy, '1/SIZE/') === this.selectedSize) + // Updating the selected features value to first available feature. + let isVariantAvailable = true; + Object.entries(this.features).map(([featureType, featureValue] : any) => { + if(!isVariantAvailable){ + this.selectedVariant[featureType] = featureValue[0] + }else if(featureType === this.selectedFeature){ + isVariantAvailable = false + } + }) + + variant = this.getVariant() showToast(translate("Selected variant not available")) } } - // if the variant does not have color or size as features + this.currentVariant = variant || this.product.variants[0] - this.variantId = this.currentVariant.variantId + this.variantId = this.currentVariant.productId this.$route.query.variantId !== this.currentVariant.productId && (this.router.replace({path: this.$route.path, query: { variantId: this.currentVariant.productId } })); await this.getPoDetails() await this.getAtpCalcDetails() @@ -575,6 +616,17 @@ export default defineComponent({ await this.prepareShopListings() await this.preparePoSummary() }, + getVariant() { + return this.product.variants.find((variant: any) => { + let isFeatureAvailable = true + Object.entries(this.selectedVariant).map(([featureType,featureValue]) => { + if(getFeature(variant.featureHierarchy, `1/${featureType}`) != featureValue){ + isFeatureAvailable = false + } + }) + return isFeatureAvailable + }) + }, async getCtgryAndBrkrngJobs() { const systemJobEnumIds = JSON.parse(process.env.VUE_APP_CTGRY_AND_BRKRNG_JOB) await this.store.dispatch('job/fetchCtgryAndBrkrngJobs', { systemJobEnumIds }) From ddb5e14cd08f756f39d8e001491bfc556be7f678 Mon Sep 17 00:00:00 2001 From: amansinghbais Date: Thu, 7 Sep 2023 12:39:52 +0530 Subject: [PATCH 2/4] Fixed: added missing comma in catalog-product-details page (#166) --- src/views/catalog-product-details.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/catalog-product-details.vue b/src/views/catalog-product-details.vue index eefbb3d3..eb955e03 100644 --- a/src/views/catalog-product-details.vue +++ b/src/views/catalog-product-details.vue @@ -441,7 +441,7 @@ export default defineComponent({ backorderCategoryId: '', preOrderCategoryId: '', selectedVariant: {} as any, - selectedFeature: '' + selectedFeature: '', isCtgryAndBrkrngJobsLoaded: false } }, From 4fa17fcd2d4aea52d467a3c16ccd30db392ca877 Mon Sep 17 00:00:00 2001 From: amansinghbais Date: Wed, 25 Oct 2023 09:49:18 +0530 Subject: [PATCH 3/4] Improved: code to avoid duplication of feature option (#620) --- src/views/catalog-product-details.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/views/catalog-product-details.vue b/src/views/catalog-product-details.vue index a9e83e9c..c8cb3f79 100644 --- a/src/views/catalog-product-details.vue +++ b/src/views/catalog-product-details.vue @@ -509,7 +509,9 @@ export default defineComponent({ const nextFeatureAvailableValues = [] as any availableVariants.map((variant: any) => { - nextFeatureAvailableValues.push(getFeature(variant.featureHierarchy , `1/${nextFeatureType}`)) + if(!nextFeatureAvailableValues.includes(getFeature(variant.featureHierarchy , `1/${nextFeatureType}`))){ + nextFeatureAvailableValues.push(getFeature(variant.featureHierarchy , `1/${nextFeatureType}`)) + } }) this.features[nextFeatureType] = nextFeatureType === 'SIZE' ? sortSizes(nextFeatureAvailableValues) : nextFeatureAvailableValues } From 67bea3d4267dbc92ae02c20dd7e4425e89219df5 Mon Sep 17 00:00:00 2001 From: amansinghbais Date: Wed, 25 Oct 2023 11:24:23 +0530 Subject: [PATCH 4/4] Improved: code for making more optimal (#166) --- src/store/modules/product/actions.ts | 12 +++ src/views/catalog-product-details.vue | 109 ++++++++++++-------------- 2 files changed, 62 insertions(+), 59 deletions(-) diff --git a/src/store/modules/product/actions.ts b/src/store/modules/product/actions.ts index 49da7505..d626aae1 100644 --- a/src/store/modules/product/actions.ts +++ b/src/store/modules/product/actions.ts @@ -248,6 +248,18 @@ const actions: ActionTree = { product = resp.data.response.docs.find((product: any) => product.productId === payload.productId) variants = resp.data.response.docs.filter((product: any) => product.productId !== payload.productId) } + const features = [['0/COLOR/', '1/COLOR/Black/', '0/SIZE/', '1/SIZE/29/', '0/TYPE/', '1/TYPE/Z/'], + ['0/COLOR/', '1/COLOR/Black/', '0/SIZE/', '1/SIZE/28/', '0/TYPE/', '1/TYPE/X/'], + ['0/COLOR/', '1/COLOR/Black/', '0/SIZE/', '1/SIZE/28/', '0/TYPE/', '1/TYPE/Y/'], + ['0/COLOR/', '1/COLOR/Orange/', '0/SIZE/', '1/SIZE/28/', '0/TYPE/', '1/TYPE/Y/'], + ['0/COLOR/', '1/COLOR/Orange/', '0/SIZE/', '1/SIZE/29/', '0/TYPE/', '1/TYPE/Z/'], + ['0/COLOR/', '1/COLOR/White/', '0/SIZE/', '1/SIZE/29/', '0/TYPE/', '1/TYPE/Z/']] + + let ind = 0 + variants.map((variant: any) => { + variant.featureHierarchy = features[ind] + ind++ + }) product.variants = variants commit(types.PRODUCT_CURRENT_CTLGPRDCT_UPDATED, product) commit(types.PRODUCT_ADD_TO_CACHED_MULTIPLE, { products: [product, ...product.variants] }) diff --git a/src/views/catalog-product-details.vue b/src/views/catalog-product-details.vue index c8cb3f79..5b1ba853 100644 --- a/src/views/catalog-product-details.vue +++ b/src/views/catalog-product-details.vue @@ -21,13 +21,13 @@

{{ currentVariant.sku }}

-
+
- {{ featureType.charAt(0) + featureType.substring(1).toLowerCase() }} + {{ featureCategory.charAt(0) + featureCategory.substring(1).toLowerCase() }} - - {{ featureValue }} + + {{ featureOption }} @@ -480,65 +480,17 @@ export default defineComponent({ async getVariantDetails() { await this.store.dispatch('product/setCurrentCatalogProduct', { productId: this.productId}) if (this.product.variants) { - + await this.getVariantFeature() await this.getFeatures() - this.updateFeatures() } }, - applyFeature(featureValue: string, featureType: string) { - this.selectedFeature = featureType - this.selectedVariant[featureType] = featureValue + applyFeature(featureOption: string, featureCategory: string) { + this.selectedFeature = featureCategory + this.selectedVariant[featureCategory] = featureOption - this.updateFeatures() - }, - updateFeatures() { - Object.entries(this.selectedVariant).map((feature, featureIndex) => { - const nextFeature = Object.entries(this.selectedVariant).find((currentFeature, currentFeatureIndex) => currentFeatureIndex === featureIndex + 1) - - if(nextFeature){ - const nextFeatureType = nextFeature[0] - const availableVariants = this.product.variants.filter((variant: any) => { - let isVariantAvailable = true - Object.entries(this.selectedVariant).map((currentFeature, currentFeatureIndex) => { - if(currentFeatureIndex <= featureIndex && getFeature(variant.featureHierarchy, `1/${currentFeature[0]}`) != currentFeature[1]){ - isVariantAvailable = false - } - }) - return isVariantAvailable - }) - - const nextFeatureAvailableValues = [] as any - availableVariants.map((variant: any) => { - if(!nextFeatureAvailableValues.includes(getFeature(variant.featureHierarchy , `1/${nextFeatureType}`))){ - nextFeatureAvailableValues.push(getFeature(variant.featureHierarchy , `1/${nextFeatureType}`)) - } - }) - this.features[nextFeatureType] = nextFeatureType === 'SIZE' ? sortSizes(nextFeatureAvailableValues) : nextFeatureAvailableValues - } - }) - this.updateVariant() + this.getFeatures() }, - getFeatures() { - let features = {} as any - this.product.variants.map((variant: any) => { - variant.featureHierarchy.map((featureItem: any) => { - if(featureItem.startsWith('1/')){ - const featureType = featureItem.split('/')[1] - const featureValue = featureItem.split('/')[2] - - if (!features[featureType]) features[featureType] = [featureValue] - else if (!features[featureType].includes(featureValue)) features[featureType].push(featureValue) - } - }) - }) - - features = Object.keys(features).sort().reduce((result: any, key) => { - result[key] = features[key]; - return result; - }, {}); - - Object.keys(features).forEach((feature) => this.features[feature] = features[feature].sort()) - + getVariantFeature() { let selectedVariant = this.product.variants.find((variant: any) => variant.productId === this.variantId) let selectedVariantFeatures = {} as any @@ -555,7 +507,7 @@ export default defineComponent({ selectedVariantFeatures[featureItemSplitted[1]] = featureItemSplitted[2] } }) - + selectedVariantFeatures = Object.keys(selectedVariantFeatures).sort().reduce((result:any, key) => { result[key] = selectedVariantFeatures[key]; return result; @@ -563,6 +515,45 @@ export default defineComponent({ this.selectedVariant = selectedVariantFeatures } }, + async getFeatures() { + const selectedVariantFeatures = this.selectedVariant + const features = {} as any + Object.entries(selectedVariantFeatures).map((feature, featureIndex) => { + const featureCategory = feature[0] + if(featureIndex === 0){ + this.product.variants.map((variant: any) => { + const featureOption = getFeature(variant.featureHierarchy, `1/${featureCategory}`) + + if (!features[featureCategory]) features[featureCategory] = [featureOption] + else if (!features[featureCategory].includes(featureOption)) features[featureCategory].push(featureOption) + }) + } + const nextFeature = Object.entries(selectedVariantFeatures).find((currentFeature, currentFeatureIndex) => currentFeatureIndex === featureIndex + 1) + + if(nextFeature){ + const nextFeatureCategory = nextFeature[0] + const availableVariants = this.product.variants.filter((variant: any) => { + let isVariantAvailable = true + Object.entries(this.selectedVariant).map((currentFeature, currentFeatureIndex) => { + if(currentFeatureIndex <= featureIndex && getFeature(variant.featureHierarchy, `1/${currentFeature[0]}`) != currentFeature[1]){ + isVariantAvailable = false + } + }) + return isVariantAvailable + }) + + const nextFeatureAvailableValues = [] as any + availableVariants.map((variant: any) => { + if(!nextFeatureAvailableValues.includes(getFeature(variant.featureHierarchy , `1/${nextFeatureCategory}`))){ + nextFeatureAvailableValues.push(getFeature(variant.featureHierarchy , `1/${nextFeatureCategory}`)) + } + }) + features[nextFeatureCategory] = nextFeatureCategory === 'SIZE' ? sortSizes(nextFeatureAvailableValues) : nextFeatureAvailableValues + } + }) + this.features = features + await this.updateVariant() + }, async updateVariant() { let variant if (this.selectedFeature) {