Skip to content

Commit

Permalink
[PWA-1101] Add support for Configurable Product Image Setting (#2958)
Browse files Browse the repository at this point in the history
* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

* PWA-1101: Add support for Configurable Product Image Setting

Co-authored-by: Devagouda <40405790+dpatil-magento@users.noreply.github.com>
  • Loading branch information
eug123 and dpatil-magento authored Jan 21, 2021
1 parent 006c26b commit 9e54fc7
Show file tree
Hide file tree
Showing 34 changed files with 907 additions and 140 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`it returns the proper shape 1`] = `
<i
talonProps={
Object {
"errorMessage": "",
"handleEditItem": [Function],
"handleRemoveFromCart": [Function],
"handleToggleFavorites": [Function],
"handleUpdateItemQuantity": [Function],
"isEditable": false,
"isFavorite": false,
"product": Object {
"currency": "USD",
"image": "test.webp",
"name": "unit test",
"options": Array [],
"quantity": 7,
"stockStatus": undefined,
"unitPrice": 99,
"urlKey": undefined,
"urlSuffix": undefined,
},
}
}
/>
`;

exports[`it returns the proper shape when use variant image is configured 1`] = `
<i
talonProps={
Object {
"errorMessage": "",
"handleEditItem": [Function],
"handleRemoveFromCart": [Function],
"handleToggleFavorites": [Function],
"handleUpdateItemQuantity": [Function],
"isEditable": true,
"isFavorite": false,
"product": Object {
"currency": "USD",
"image": "variant1.webp",
"name": "unit test",
"options": Array [
Object {
"id": 22,
"option_label": "Color",
"value_id": 2,
"value_label": "red",
},
],
"quantity": 7,
"stockStatus": undefined,
"unitPrice": 99,
"urlKey": undefined,
"urlSuffix": undefined,
},
}
}
/>
`;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';

import { createTestInstance } from '@magento/peregrine';
import { useMutation } from '@apollo/client';
import { useMutation, useQuery } from '@apollo/client';
import { useAppContext } from '@magento/peregrine/lib/context/app';

import { useProduct } from '../useProduct';
Expand Down Expand Up @@ -31,7 +31,18 @@ jest.mock('@apollo/client', () => {
]);

return {
ApolloClient,
...ApolloClient,
useQuery: jest.fn().mockReturnValue({
called: false,
error: null,
loading: false,
data: {
storeConfig: {
id: 1,
configurable_thumbnail_source: 'parent'
}
}
}),
useMutation: spy
};
});
Expand Down Expand Up @@ -97,20 +108,70 @@ test('it returns the proper shape', () => {
useMutation.mockReturnValueOnce([jest.fn(), {}]);
useMutation.mockReturnValueOnce([jest.fn(), {}]);

// Act.
createTestInstance(<Component {...props} />);
const tree = createTestInstance(<Component {...props} />);
expect(tree.toJSON()).toMatchSnapshot();
});

// Assert.
expect(log).toHaveBeenCalledWith({
errorMessage: '',
handleEditItem: expect.any(Function),
handleRemoveFromCart: expect.any(Function),
handleToggleFavorites: expect.any(Function),
handleUpdateItemQuantity: expect.any(Function),
isEditable: expect.any(Boolean),
isFavorite: expect.any(Boolean),
product: expect.any(Object)
test('it returns the proper shape when use variant image is configured', () => {
// Arrange.
useMutation.mockReturnValueOnce([jest.fn(), {}]);
useMutation.mockReturnValueOnce([jest.fn(), {}]);
useQuery.mockReturnValueOnce({
called: false,
error: null,
loading: false,
data: {
storeConfig: {
id: 1,
configurable_thumbnail_source: 'itself'
}
}
});
const configurableProps = {
item: {
...props.item,
product: {
...props.item.product,
variants: [
{
attributes: [
{
uid: 'Y29uZmlndXJhYmxlLzIyLzI='
}
],
product: {
small_image: {
url: 'variant1.webp'
}
}
},
{
attributes: [
{
uid: 'Y29uZmlndXJhYmxlLzIyLzM='
}
],
product: {
small_image: {
url: 'variant2.webp'
}
}
}
]
},
configurable_options: [
{
id: 22,
option_label: 'Color',
value_label: 'red',
value_id: 2
}
]
}
};

const tree = createTestInstance(<Component {...configurableProps} />);
expect(tree.toJSON()).toMatchSnapshot();
});

test('it returns the correct error message when the error is not graphql', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { gql } from '@apollo/client';

export const GET_CONFIGURABLE_THUMBNAIL_SOURCE = gql`
query getConfigurableThumbnailSource {
storeConfig {
id
configurable_thumbnail_source
}
}
`;

export default {
getConfigurableThumbnailSource: GET_CONFIGURABLE_THUMBNAIL_SOURCE
};
45 changes: 35 additions & 10 deletions packages/peregrine/lib/talons/CartPage/ProductListing/useProduct.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useMutation } from '@apollo/client';
import { useMutation, useQuery } from '@apollo/client';
import { useCartContext } from '@magento/peregrine/lib/context/cart';
import { deriveErrorMessage } from '../../../util/deriveErrorMessage';
import configuredVariant from '@magento/peregrine/lib/util/configuredVariant';
import mergeOperations from '../../../util/shallowMerge';
import DEFAULT_OPERATIONS from './product.gql';

/**
* This talon contains logic for a product component used in a product listing component.
Expand All @@ -15,7 +18,7 @@ import { deriveErrorMessage } from '../../../util/deriveErrorMessage';
*
* @param {Object} props
* @param {ProductItem} props.item Product item data
* @param {ProductMutations} props.mutations GraphQL mutations for a product in a cart
* @param {ProductMutations} props.operations GraphQL mutations for a product in a cart
* @param {function} props.setActiveEditItem Function for setting the actively editing item
* @param {function} props.setIsCartUpdating Function for setting the updating state of the cart
*
Expand All @@ -24,15 +27,32 @@ import { deriveErrorMessage } from '../../../util/deriveErrorMessage';
* @example <caption>Importing into your project</caption>
* import { useProduct } from '@magento/peregrine/lib/talons/CartPage/ProductListing/useProduct';
*/

export const useProduct = props => {
const { item, setActiveEditItem, setIsCartUpdating } = props;

const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
const {
item,
mutations: { removeItemMutation, updateItemQuantityMutation },
setActiveEditItem,
setIsCartUpdating
} = props;
removeItemMutation,
updateItemQuantityMutation,
getConfigurableThumbnailSource
} = operations;

const flatProduct = flattenProduct(item);
const { data: configurableThumbnailSourceData } = useQuery(
getConfigurableThumbnailSource,
{
fetchPolicy: 'cache-and-network'
}
);

const configurableThumbnailSource = useMemo(() => {
if (configurableThumbnailSourceData) {
return configurableThumbnailSourceData.storeConfig
.configurable_thumbnail_source;
}
}, [configurableThumbnailSourceData]);

const flatProduct = flattenProduct(item, configurableThumbnailSource);

const [
removeItem,
Expand Down Expand Up @@ -141,14 +161,16 @@ export const useProduct = props => {
};
};

const flattenProduct = item => {
const flattenProduct = (item, configurableThumbnailSource) => {
const {
configurable_options: options = [],
prices,
product,
quantity
} = item;

const configured_variant = configuredVariant(options, product);

const { price } = prices;
const { value: unitPrice, currency } = price;

Expand All @@ -159,7 +181,10 @@ const flattenProduct = item => {
url_key: urlKey,
url_suffix: urlSuffix
} = product;
const { url: image } = small_image;
const { url: image } =
configurableThumbnailSource === 'itself' && configured_variant
? configured_variant.small_image
: small_image;

return {
currency,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`returns correct shape 1`] = `
Object {
"configurableThumbnailSource": "parent",
"hasErrors": false,
"isLoading": true,
"items": Array [],
Expand All @@ -13,6 +14,7 @@ Object {

exports[`uses static data if provided 1`] = `
Object {
"configurableThumbnailSource": "parent",
"hasErrors": false,
"isLoading": true,
"items": Array [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import React from 'react';
import { useLazyQuery } from '@apollo/client';
import { useLazyQuery, useQuery } from '@apollo/client';

import createTestInstance from '../../../../../lib/util/createTestInstance';
import { useItemsReview } from '../useItemsReview';

import cartItems from '../__fixtures__/cartItems';

jest.mock('@apollo/client', () => ({
useLazyQuery: jest.fn().mockReturnValue([
() => {},
{
data: null,
error: null,
loading: true
}
])
}));
jest.mock('@apollo/client', () => {
const apolloClient = jest.requireActual('@apollo/client');

return {
...apolloClient,
useQuery: jest.fn(),
useLazyQuery: jest.fn()
};
});

jest.mock('../../../../context/cart', () => {
const state = {
Expand All @@ -27,6 +26,25 @@ jest.mock('../../../../context/cart', () => {
return { useCartContext };
});

beforeAll(() => {
useLazyQuery.mockReturnValue([
() => {},
{
data: null,
error: null,
loading: true
}
]);
useQuery.mockReturnValue({
data: {
storeConfig: {
id: 1,
configurable_thumbnail_source: 'parent'
}
}
});
});

const Component = props => {
const talonProps = useItemsReview(props);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { gql } from '@apollo/client';

export const GET_CONFIGURABLE_THUMBNAIL_SOURCE = gql`
query getConfigurableThumbnailSource {
storeConfig {
id
configurable_thumbnail_source
}
}
`;

export default {
getConfigurableThumbnailSource: GET_CONFIGURABLE_THUMBNAIL_SOURCE
};
Loading

0 comments on commit 9e54fc7

Please sign in to comment.