Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add to Wishlist from PDP #3048

Merged
merged 44 commits into from
Mar 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
1549954
initial work to add CE wishlist functionality on pdp
sirugh Mar 9, 2021
4584c4f
Use 0 as wishlist id for CE
sirugh Mar 10, 2021
ee374fc
Adding configurableproduct via selected_options array
sirugh Mar 10, 2021
022152b
Fixing logic for temporary item added
sirugh Mar 10, 2021
520fd87
migrate logic to wishlist talons with compatible extension
sirugh Mar 10, 2021
d7ad759
Added to favorites ux is favorable over a technically challenging rem…
sirugh Mar 11, 2021
a01978f
bool name
sirugh Mar 11, 2021
13563a0
EE workflow
sirugh Mar 12, 2021
688bd0d
Feedback
sirugh Mar 12, 2021
2d43447
styles
sirugh Mar 12, 2021
95c1c87
fix gql warnings
sirugh Mar 12, 2021
94c5fbf
Merge branch 'develop' into rugh/pwa-1267-add-to-wishlist-pdp
sirugh Mar 12, 2021
bb6bbbd
Add messages and some cleanup
sirugh Mar 12, 2021
c24cfb7
capitalization
sirugh Mar 12, 2021
8f6cc19
id for i18n
sirugh Mar 12, 2021
92984f1
Only close new list form when cancel is clicked
sirugh Mar 12, 2021
f3ae3ac
Update icon styles for wishlist button
sirugh Mar 12, 2021
e552a97
Add underline to mimic link
sirugh Mar 12, 2021
9350eb1
wrap button in suspense to lazy load
sirugh Mar 15, 2021
cb5245e
Merge branch 'develop' into rugh/pwa-1267-add-to-wishlist-pdp
sirugh Mar 15, 2021
5fd6431
Address feedback.
sirugh Mar 15, 2021
d4fea5a
id is required on customer
sirugh Mar 15, 2021
4fe06c4
Remove unnecessary fragment
sirugh Mar 15, 2021
286f051
Rename to createWishlistForm
sirugh Mar 16, 2021
58ca5a8
Merge branch 'develop' into rugh/pwa-1267-add-to-wishlist-pdp
sirugh Mar 18, 2021
9b03aa0
Fix a bug for simple items where configurable_options was null
sirugh Mar 18, 2021
cca24a7
Minimal fixes to existing tests to get passing.
sirugh Mar 18, 2021
917aec1
Remove unused prop
sirugh Mar 18, 2021
a278ed1
Test changes to pfd talon
sirugh Mar 18, 2021
064f68a
Move and test wishlistLineItem
sirugh Mar 18, 2021
ee14ca4
Test useWishlistButton.ce.js
sirugh Mar 18, 2021
a9d06c3
Test useWishlistButton.ee.js
sirugh Mar 18, 2021
f9f883f
Test useCreateWishlistForm
sirugh Mar 19, 2021
c95cbeb
test useWishlistDialog
sirugh Mar 22, 2021
e7b3ee0
Test productFullDetail
sirugh Mar 22, 2021
f53e537
Test wishlistButton.ce
sirugh Mar 22, 2021
e0e1c25
Test wishlistButton.ee
sirugh Mar 22, 2021
128e742
Test CreateWishlistForm
sirugh Mar 23, 2021
4a68c9c
Test WishlistDialog
sirugh Mar 23, 2021
861bb7a
Merge remote-tracking branch 'origin/develop' into rugh/pwa-1267-add-…
sirugh Mar 23, 2021
de93f85
Merge branch 'develop' into rugh/pwa-1267-add-to-wishlist-pdp
dpatil-magento Mar 26, 2021
2e5ee88
Add enclosing root div to button components and pack content around c…
sirugh Mar 29, 2021
4d14627
fix snaps
sirugh Mar 29, 2021
5620add
Use a single child of button to contain items
sirugh Mar 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
import React from 'react';
import { useMutation } from '@apollo/client';
import { act } from 'react-test-renderer';
import { useMutation, useQuery } from '@apollo/client';

import createTestInstance from '../../../util/createTestInstance';
import { useProductFullDetail } from '../useProductFullDetail';
import { useUserContext } from '../../../context/user';

jest.mock('@apollo/client', () => ({
useMutation: jest.fn().mockImplementation(() => [
jest.fn(),
{
error: null
}
])
]),
useQuery: jest.fn().mockImplementation(() => ({
data: {
storeConfig: {
magento_wishlist_general_is_enabled: true
}
},
loading: false,
error: false
}))
}));

jest.mock('@magento/peregrine/lib/context/user', () => {
const userState = { isSignedIn: false };
const userApi = {};
const useUserContext = jest.fn(() => [userState, userApi]);

return { useUserContext };
});

jest.mock('@magento/peregrine/lib/context/cart', () => {
const cartState = { cartId: 'ThisIsMyCart' };
const cartApi = {};
Expand All @@ -38,10 +57,123 @@ const defaultProps = {
value: 99
}
}
}
},
sku: 'MySimpleProductSku'
}
};

describe('shouldShowWishlistButton', () => {
test('is false if not signed in', () => {
useUserContext.mockReturnValueOnce([{ isSignedIn: false }]);
const tree = createTestInstance(<Component {...defaultProps} />);

const { root } = tree;
const { talonProps } = root.findByType('i').props;

expect(talonProps.shouldShowWishlistButton).toBeFalsy();
});

test('is false if wishlist is disabled in config', () => {
useUserContext.mockReturnValueOnce([{ isSignedIn: true }]);
useQuery.mockReturnValueOnce({
data: {
storeConfig: {
magento_wishlist_general_is_enabled: false
}
},
loading: false,
error: false
});
const tree = createTestInstance(<Component {...defaultProps} />);

const { root } = tree;
const { talonProps } = root.findByType('i').props;

expect(talonProps.shouldShowWishlistButton).toBeFalsy();
});

test('is true if signed in and wishlist is enabled', () => {
useUserContext.mockReturnValueOnce([{ isSignedIn: true }]);
useQuery.mockReturnValueOnce({
data: {
storeConfig: {
magento_wishlist_general_is_enabled: true
}
},
loading: false,
error: false
});
const tree = createTestInstance(<Component {...defaultProps} />);

const { root } = tree;
const { talonProps } = root.findByType('i').props;

expect(talonProps.shouldShowWishlistButton).toBeTruthy();
});
});

describe('wishlistItemOptions', () => {
test('returns quantity and sku for all products', () => {
const tree = createTestInstance(<Component {...defaultProps} />);

const { root } = tree;
const { talonProps } = root.findByType('i').props;

expect(talonProps.wishlistItemOptions).toMatchObject({
quantity: 1,
sku: defaultProps.product.sku
});
});

test('returns selected_options for ConfigurableProducts', () => {
const optionId = 1;
const selectionId = 2;
const uid = 'foo';

const props = {
...defaultProps,
product: {
...defaultProps.product,
sku: 'MyConfigurableProductSku',
__typename: 'ConfigurableProduct',
configurable_options: [
{
attribute_id: optionId,
values: [{ uid, value_index: selectionId }]
}
],
variants: []
}
};
const tree = createTestInstance(<Component {...props} />);

const { root } = tree;

expect(
root.findByType('i').props.talonProps.wishlistItemOptions
).toMatchObject({
quantity: 1,
sku: props.product.sku,
selected_options: []
});

act(() => {
root.findByType('i').props.talonProps.handleSelectionChange(
optionId,
selectionId
);
});

expect(
root.findByType('i').props.talonProps.wishlistItemOptions
).toMatchObject({
quantity: 1,
sku: props.product.sku,
selected_options: [uid]
});
});
});

test('returns undefined category if there are no categories for the product', () => {
const props = {
...defaultProps,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useCallback, useState, useMemo } from 'react';
import { useMutation } from '@apollo/client';
import { useMutation, useQuery } from '@apollo/client';
import { useCartContext } from '@magento/peregrine/lib/context/cart';
import { useUserContext } from '@magento/peregrine/lib/context/user';

import { appendOptionsToPayload } from '@magento/peregrine/lib/util/appendOptionsToPayload';
import { findMatchingVariant } from '@magento/peregrine/lib/util/findMatchingProductVariant';
Expand Down Expand Up @@ -150,6 +151,7 @@ const SUPPORTED_PRODUCT_TYPES = ['SimpleProduct', 'ConfigurableProduct'];
/**
* @param {GraphQLQuery} props.addConfigurableProductToCartMutation - configurable product mutation
* @param {GraphQLQuery} props.addSimpleProductToCartMutation - configurable product mutation
* @param {GraphQLQuery} props.getWishlistConfig - queries for whether wishlists are enabled.
* @param {Object} props.product - the product, see RootComponents/Product
*
* @returns {{
Expand All @@ -169,6 +171,7 @@ export const useProductFullDetail = props => {
const {
addConfigurableProductToCartMutation,
addSimpleProductToCartMutation,
getWishlistConfig,
product
} = props;

Expand All @@ -179,6 +182,11 @@ export const useProductFullDetail = props => {
);

const [{ cartId }] = useCartContext();
const [{ isSignedIn }] = useUserContext();

const { data: storeConfigData } = useQuery(getWishlistConfig, {
fetchPolicy: 'cache-and-network'
});

const [
addConfigurableProductToCart,
Expand Down Expand Up @@ -222,6 +230,39 @@ export const useProductFullDetail = props => {
[product, optionCodes, optionSelections]
);

// The map of ids to values (and their uids)
// For example:
// { "179" => [{ uid: "abc", value_index: 1 }, { uid: "def", value_index: 2 }]}
const attributeIdToValuesMap = useMemo(() => {
const map = new Map();
// For simple items, this will be an empty map.
const options = product.configurable_options || [];
for (const { attribute_id, values } of options) {
map.set(attribute_id, values);
}
return map;
}, [product.configurable_options]);

// An array of selected option uids. Useful for passing to mutations.
// For example:
// ["abc", "def"]
const selectedOptionsArray = useMemo(() => {
const selectedOptions = [];

optionSelections.forEach((value, key) => {
const values = attributeIdToValuesMap.get(key);

const selectedValue = values.find(
item => item.value_index === value
);

if (selectedValue) {
selectedOptions.push(selectedValue.uid);
}
});
return selectedOptions;
}, [attributeIdToValuesMap, optionSelections]);

const handleAddToCart = useCallback(
async formValues => {
const { quantity } = formValues;
Expand Down Expand Up @@ -310,6 +351,19 @@ export const useProductFullDetail = props => {
[errorAddingConfigurableProduct, errorAddingSimpleProduct]
);

const wishlistItemOptions = useMemo(() => {
const options = {
quantity: 1,
supernova-at marked this conversation as resolved.
Show resolved Hide resolved
sku: product.sku
};

if (productType === 'ConfigurableProduct') {
options.selected_options = selectedOptionsArray;
}

return options;
}, [product, productType, selectedOptionsArray]);

return {
breadcrumbCategoryId,
errorMessage: derivedErrorMessage,
Expand All @@ -319,6 +373,11 @@ export const useProductFullDetail = props => {
isMissingOptions || isAddConfigurableLoading || isAddSimpleLoading,
isSupportedProductType,
mediaGalleryEntries,
productDetails
shouldShowWishlistButton:
isSignedIn &&
storeConfigData &&
!!storeConfigData.storeConfig.magento_wishlist_general_is_enabled,
productDetails,
wishlistItemOptions
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const ProductDetailsFragment = gql`
id
label
values {
uid
default_label
label
store_label
Expand Down
Loading