From b39feaa2104245a878d7b9df9e61e8b8744be404 Mon Sep 17 00:00:00 2001 From: Chandradeepta Date: Thu, 2 Jun 2022 11:11:59 +0530 Subject: [PATCH 1/2] fix: color selection error --- .../src/api/configureProduct/index.ts | 14 +- .../composables/src/getters/productGetters.ts | 147 +++++++++++------- packages/theme/pages/Product.vue | 11 +- 3 files changed, 110 insertions(+), 62 deletions(-) diff --git a/packages/api-client/src/api/configureProduct/index.ts b/packages/api-client/src/api/configureProduct/index.ts index fc33617..1b51ddb 100644 --- a/packages/api-client/src/api/configureProduct/index.ts +++ b/packages/api-client/src/api/configureProduct/index.ts @@ -1,11 +1,17 @@ import { Context } from '@vue-storefront/core'; import defaultMutation from './defaultMutation'; -import { ConfigureProductResponse, InternalConfigureProductParams } from '../../types/Api'; +import { + ConfigureProductResponse, + InternalConfigureProductParams +} from '../../types/Api'; // eslint-disable-next-line @typescript-eslint/no-unused-vars -export default async function configureProduct(context: Context, params: InternalConfigureProductParams): Promise { - const attributes = Object.keys(params.attributes).map(a => ({ - attributeFQN: `tenant~${a}`, +export default async function configureProduct( + context: Context, + params: InternalConfigureProductParams +): Promise { + const attributes = Object.keys(params.attributes).map((a) => ({ + attributeFQN: a, value: params.attributes[a] })); const product = params.product; diff --git a/packages/composables/src/getters/productGetters.ts b/packages/composables/src/getters/productGetters.ts index 35ddf3e..3dd118c 100644 --- a/packages/composables/src/getters/productGetters.ts +++ b/packages/composables/src/getters/productGetters.ts @@ -8,16 +8,18 @@ import { import type { Product } from '@vue-storefront/kibocommerce-api'; import { buildBreadcrumbs } from '../helpers/buildBreadcrumbs'; -import {ProductFiltersParams, ProductAttributesParams } from '../types'; +import { ProductFiltersParams, ProductAttributesParams } from '../types'; // TODO: Add interfaces for some of the methods in core // Product // eslint-disable-next-line @typescript-eslint/no-unused-vars -export const getProductName = (product: Product): string => product?.content?.productName || ''; +export const getProductName = (product: Product): string => + product?.content?.productName || ''; // eslint-disable-next-line @typescript-eslint/no-unused-vars -export const getProductSlug = (product: Product): string => product?.content?.seoFriendlyUrl || ''; +export const getProductSlug = (product: Product): string => + product?.content?.seoFriendlyUrl || ''; // eslint-disable-next-line @typescript-eslint/no-unused-vars export const getProductPrice = (product: Product): AgnosticPrice => { @@ -28,25 +30,35 @@ export const getProductPrice = (product: Product): AgnosticPrice => { }; // eslint-disable-next-line @typescript-eslint/no-unused-vars -export const getProductGallery = (product: Product): AgnosticMediaGalleryItem[] => { - return product?.content?.productImages.map(pi => ({ - small: pi.imageUrl, - normal: pi.imageUrl, - big: pi.imageUrl - })) || []; +export const getProductGallery = ( + product: Product +): AgnosticMediaGalleryItem[] => { + return ( + product?.content?.productImages.map((pi) => ({ + small: pi.imageUrl, + normal: pi.imageUrl, + big: pi.imageUrl + })) || [] + ); }; // eslint-disable-next-line @typescript-eslint/no-unused-vars -export const getProductCoverImage = (product: Product): string => product?.content?.productImages?.[0]?.imageUrl || ''; +export const getProductCoverImage = (product: Product): string => + product?.content?.productImages?.[0]?.imageUrl || ''; // eslint-disable-next-line @typescript-eslint/no-unused-vars -export const getProductFiltered = (products: Product[], filters: ProductFiltersParams): Product[] => { +export const getProductFiltered = ( + products: Product[], + filters: ProductFiltersParams +): Product[] => { if (!products) return []; return products; }; // eslint-disable-next-line @typescript-eslint/no-unused-vars -export const getProductAttributes = (products: Product[] | Product): Record => { +export const getProductAttributes = ( + products: Product[] | Product +): Record => { try { const isSingleProduct = !Array.isArray(products); const productList = (isSingleProduct ? [products] : products) as Product[]; @@ -57,22 +69,28 @@ export const getProductAttributes = (products: Product[] | Product): Record { const attributes = []; - product.properties.filter(p => p.isHidden !== true).forEach(p => { - attributes.push(...p.values.map(val => { - if (val.value !== null) - return { - name: p.attributeDetail?.name, - value: (val.value.toString() as string), - label: val.stringValue ?? (val.value.toString() as string) - }; - })); - }); + product.properties + .filter((p) => p.isHidden !== true) + .forEach((p) => { + attributes.push( + ...p.values.map((val) => { + if (val.value !== null) + return { + name: p.attributeDetail?.name, + value: val.value.toString() as string, + label: val.stringValue ?? (val.value.toString() as string) + }; + }) + ); + }); return attributes; }; const reduceToUniques = (prev, curr) => { try { - const isAttributeExist = prev.some(el => el.name === curr.name && el.value === curr.value); + const isAttributeExist = prev.some( + (el) => el.name === curr.name && el.value === curr.value + ); if (!isAttributeExist) { prev.push(curr); } @@ -85,13 +103,11 @@ export const getProductAttributes = (products: Product[] | Product): Record ({ ...prev, - [curr.name]: [ - ...(prev[curr.name] || []), - curr.value - ] + [curr.name]: [...(prev[curr.name] || []), curr.value] }); - const list = productList.map(formatAttributes) + const list = productList + .map(formatAttributes) .reduce((prev, curr) => { prev.push(...curr); return prev; @@ -106,7 +122,10 @@ export const getProductAttributes = (products: Product[] | Product): Record => { +export const getProductOptions = ( + products: Product[] | Product, + filterByAttributeName?: string[] +): Record => { try { const isSingleProduct = !Array.isArray(products); const productList = (isSingleProduct ? [products] : products) as Product[]; @@ -118,25 +137,34 @@ export const getProductOptions = (products: Product[] | Product, filterByAttribu const formatAttributes = (product: Product): AgnosticAttribute[] => { const attributes = []; const options = filterByAttributeName - ? product.options?.filter(p => filterByAttributeName.includes(p.attributeDetail?.name.toLowerCase())) + ? product.options?.filter((p) => + filterByAttributeName.includes( + p.attributeDetail?.name.toLowerCase() + ) + ) : product.options; - options.forEach(p => { - attributes.push(...p.values.map(val => { - if (val.value !== null) - return { - name: p.attributeDetail?.name, - value: (val.value.toString() as string), - label: val.value ?? (val.value.toString() as string) - }; - })); + options.forEach((p) => { + attributes.push( + ...p.values.map((val) => { + if (val.value !== null) + return { + name: p.attributeDetail?.name, + value: val.value.toString() as string, + label: val.value ?? (val.value.toString() as string), + attributeFQN: p.attributeFQN + }; + }) + ); }); return attributes; }; const reduceToUniques = (prev, curr) => { try { - const isAttributeExist = prev.some(el => el.name === curr.name && el.value === curr.value); + const isAttributeExist = prev.some( + (el) => el.name === curr.name && el.value === curr.value + ); if (!isAttributeExist) { prev.push(curr); } @@ -152,10 +180,12 @@ export const getProductOptions = (products: Product[] | Product, filterByAttribu [curr.name.toLowerCase()]: [ ...(prev[curr.name.toLowerCase()] || []), curr.value - ] + ], + attributeFQN: curr.attributeFQN }); - const list = productList.map(formatAttributes) + const list = productList + .map(formatAttributes) .reduce((prev, curr) => { prev.push(...curr); return prev; @@ -169,11 +199,14 @@ export const getProductOptions = (products: Product[] | Product, filterByAttribu } }; -export const getProductDescription = (product: Product): string => product?.content?.productFullDescription || ''; +export const getProductDescription = (product: Product): string => + product?.content?.productFullDescription || ''; -export const getProductCategoryIds = (product: Product): string[] => product?.categories?.map(c => c.categoryId.toString()) || []; +export const getProductCategoryIds = (product: Product): string[] => + product?.categories?.map((c) => c.categoryId.toString()) || []; -export const getProductId = (product: Product): string => product?.variationProductCode || product?.productCode || ''; +export const getProductId = (product: Product): string => + product?.variationProductCode || product?.productCode || ''; export const getFormattedPrice = (price: number): string => String(price); @@ -183,13 +216,18 @@ export const getProductTotalReviews = (product: Product): number => 0; // eslint-disable-next-line @typescript-eslint/no-unused-vars export const getProductAverageRating = (product: Product): number => 0; -export const getProductBreadcrumbs = (product: Product): AgnosticBreadcrumb[] => { +export const getProductBreadcrumbs = ( + product: Product +): AgnosticBreadcrumb[] => { if (!product) { return []; } const bcs = [ - { text: 'Home', link: '/'}, - ...buildBreadcrumbs(product.categories[0]).map(b => ({...b, link: `/c/${b.link}` })) + { text: 'Home', link: '/' }, + ...buildBreadcrumbs(product.categories[0]).map((b) => ({ + ...b, + link: `/c/${b.link}` + })) ]; return bcs; }; @@ -198,16 +236,21 @@ export const getIsPurchasable = (product: Product): boolean => { return product?.purchasableState?.isPurchasable || false; }; -export const getProductConfiguration = (product: Product): ProductAttributesParams => { +export const getProductConfiguration = ( + product: Product +): ProductAttributesParams => { const ret = {}; - product?.options.forEach(o => { - ret[o.attributeDetail?.name.toLowerCase()] = o.values?.filter(v => v.isSelected)?.[0]?.value; + product?.options.forEach((o) => { + ret[o.attributeDetail?.name.toLowerCase()] = o.values?.filter( + (v) => v.isSelected + )?.[0]?.value; }); return ret; }; export const getProductInventory = (product: Product): number => { - if (product?.inventoryInfo?.manageStock) return product.inventoryInfo.onlineStockAvailable; + if (product?.inventoryInfo?.manageStock) + return product.inventoryInfo.onlineStockAvailable; return 100; }; diff --git a/packages/theme/pages/Product.vue b/packages/theme/pages/Product.vue index e776146..457aca6 100644 --- a/packages/theme/pages/Product.vue +++ b/packages/theme/pages/Product.vue @@ -44,7 +44,7 @@ :regular="$n(productGetters.getPrice(product).regular, 'currency')" :special=" productGetters.getPrice(product).special && - $n(productGetters.getPrice(product).special, 'currency') + $n(productGetters.getPrice(product).special, 'currency') " />
@@ -95,7 +95,7 @@ :key="i" :color="color" class="product__color" - @click="updateFilter({ color })" + @click="updateFilter({ [options.attributeFQN]: color })" />
products.value); From b36541928c047967698c53ec1fe1ec02d8c760b5 Mon Sep 17 00:00:00 2001 From: Chandradeepta Date: Tue, 7 Jun 2022 20:02:04 +0530 Subject: [PATCH 2/2] fix: test cases and login mutation --- .../__tests__/api/configureProduct.spec.ts | 5 ++- .../__tests__/api/logInUser.spec.ts | 40 +++++++++++++++---- .../api-client/src/api/logInUser/index.ts | 38 ++++++++++++++++-- packages/composables/package.json | 2 +- 4 files changed, 71 insertions(+), 14 deletions(-) diff --git a/packages/api-client/__tests__/api/configureProduct.spec.ts b/packages/api-client/__tests__/api/configureProduct.spec.ts index 1bb1b79..e84b128 100644 --- a/packages/api-client/__tests__/api/configureProduct.spec.ts +++ b/packages/api-client/__tests__/api/configureProduct.spec.ts @@ -33,7 +33,10 @@ describe('[kibo-api-client] configureProduct', () => { const product = { productCode: 'ACC1' } as any; - const productResponse = await configureProduct(context, { product, attributes: { color: 'Green' } }); + const productResponse = await configureProduct(context, { + product, + attributes: { 'tenant~color': 'Green' } + }); expect(productResponse.data).toEqual('config response'); }); diff --git a/packages/api-client/__tests__/api/logInUser.spec.ts b/packages/api-client/__tests__/api/logInUser.spec.ts index 79868a6..dc112ae 100644 --- a/packages/api-client/__tests__/api/logInUser.spec.ts +++ b/packages/api-client/__tests__/api/logInUser.spec.ts @@ -1,4 +1,13 @@ import logInUser from '../../src/api/logInUser'; +import defaultMutation from '../../src/api/logInUser/defaultMutation'; + +const loginResponse = { + accessToken: 'access token', + accessTokenExpiration: 'access token expiration', + refreshToken: 'refresh token', + userId: 'userId', + refreshTokenExpiration: 'refresh token expiration' +}; describe('[kibo-api-client] logInUser', () => { beforeEach(() => { @@ -6,10 +15,11 @@ describe('[kibo-api-client] logInUser', () => { }); it('creates user session', async () => { - const givenVariables = { - username: 'kevin.watts@kibocommerce.com', - password: '12345' + loginInput: { + username: 'kevin.watts@kibocommerce.com', + password: '12345' + } }; const context = { config: { @@ -18,14 +28,28 @@ describe('[kibo-api-client] logInUser', () => { currency: 'USD' }, client: { - loginCustomerAndSetAuthTicket: (params) =>{ - expect(params).toEqual(givenVariables); - return { data: 'user response' }; + mutate: ({ variables, mutation }) => { + expect(variables).toStrictEqual(givenVariables); + expect(mutation).toEqual(defaultMutation); + + return { + data: { + account: loginResponse + } + }; + }, + shopperAuthManager: { + setTicket: (data) => { + expect(data).toStrictEqual(loginResponse); + } } } }; - const { data } = await logInUser(context, givenVariables) as any; - expect(data).toBe('user response'); + const { data } = (await logInUser( + context, + givenVariables.loginInput + )) as any; + expect(data).toStrictEqual({ account: loginResponse }); }); }); diff --git a/packages/api-client/src/api/logInUser/index.ts b/packages/api-client/src/api/logInUser/index.ts index 0b950d7..59b1d93 100644 --- a/packages/api-client/src/api/logInUser/index.ts +++ b/packages/api-client/src/api/logInUser/index.ts @@ -1,12 +1,42 @@ /* eslint camelcase: "warn"*/ import { Context } from '@vue-storefront/core'; -import { KiboApolloClient } from '@kibocommerce/graphql-client'; +import loginMutation from './defaultMutation'; import { LogInUserParams, LogInUserResponse } from '../../types/Api'; +import { KiboApolloClient } from '@kibocommerce/graphql-client'; -const loginUser = async (context:Context, params:LogInUserParams): Promise => { - const client = context.client as KiboApolloClient; +const loginUser = async ( + context: Context, + params: LogInUserParams +): Promise => { const { username, password } = params; - const loginResponse = await client.loginCustomerAndSetAuthTicket({ username, password }) as any; + const client = context.client as KiboApolloClient; + const loginResponse = await context.client.mutate({ + mutation: loginMutation, + variables: { + loginInput: { + username, + password + } + }, + fetchPolicy: 'no-cache' + }); + + const { + accessToken, + accessTokenExpiration, + refreshToken, + userId, + refreshTokenExpiration + } = loginResponse.data.account; + + client.shopperAuthManager.setTicket({ + accessToken, + accessTokenExpiration, + refreshToken, + userId, + refreshTokenExpiration + }); + return loginResponse; }; diff --git a/packages/composables/package.json b/packages/composables/package.json index 9964edd..5603d19 100644 --- a/packages/composables/package.json +++ b/packages/composables/package.json @@ -17,7 +17,7 @@ }, "dependencies": { "@vue-storefront/core": "~2.5.0", - "@vue-storefront/kibocommerce-api": "^1.0.0-beta.4", + "@vue-storefront/kibocommerce-api": "^1.0.3-beta.7", "vue": "^2.6.12", "@vue/composition-api": "^1.3.3", "vue-demi": "^0.12.1",