diff --git a/blocks/product-details/product-details.css b/blocks/product-details/product-details.css index 3d8a3f1b50..730a3bdc70 100644 --- a/blocks/product-details/product-details.css +++ b/blocks/product-details/product-details.css @@ -1 +1,7 @@ -/* stylelint-disable no-empty-source */ \ No newline at end of file +.pdp-product__buttons { /* stylelint-disable-line selector-class-pattern */ + display: flex; +} + +.pdp-product__buttons > .dropin-button--primary { /* stylelint-disable-line selector-class-pattern */ + flex-grow: 1; +} diff --git a/blocks/product-details/product-details.js b/blocks/product-details/product-details.js index 075a2322d9..ba371641a2 100644 --- a/blocks/product-details/product-details.js +++ b/blocks/product-details/product-details.js @@ -247,6 +247,24 @@ export default async function decorate(block) { }, }; }); + + ctx.appendButton((next, state) => { + const adding = state.get('adding'); + return ({ + disabled: adding, + icon: 'Heart', + variant: 'secondary', + onClick: async () => { + try { + state.set('adding', true); + const { addToWishlist } = await import('../../scripts/wishlist/api.js'); + await addToWishlist(next.values.sku); + } finally { + state.set('adding', false); + } + }, + }); + }); }, }, useACDL: true, diff --git a/scripts/wishlist/api.js b/scripts/wishlist/api.js new file mode 100644 index 0000000000..1a75eed08b --- /dev/null +++ b/scripts/wishlist/api.js @@ -0,0 +1,103 @@ +import { getSignInToken, performMonolithGraphQLQuery } from '../commerce.js'; + +const redirectToSignin = () => { + window.location = '/customer/login'; +}; + +const getWishlistsQuery = ` + query GetWishlists { + customer { + wishlists { + id + name + items_count + items_v2 { + items { + id + product { + uid + name + sku + } + } + } + } + } +} +`; + +const addProductToWishlistMutation = ` +mutation( + $wishlistId: ID!, + $sku: String! +) { + addProductsToWishlist( + wishlistId: $wishlistId, + wishlistItems: [ + { + sku: $sku + quantity: 1 + } + ] + ) { + user_errors { + code + message + } + wishlist { + name + } + } +} +`; + +export async function getWishlists() { + const token = getSignInToken(); + if (!token) { + redirectToSignin(); + } + + const wishlists = await performMonolithGraphQLQuery( + getWishlistsQuery, + {}, + true, + token, + ); + + if (wishlists.errors?.find((error) => error.message === "The current customer isn't authorized.")) { + redirectToSignin(); + } + + return wishlists.data?.customer?.wishlists; +} + +/** + * Adds a product to the specified wishlist + * @param product SKU of the product to add + * @param wishlistId Optionally pass a wishlist. If no option, the first wishlist will be used. + * @returns {Promise} + */ +export async function addToWishlist(product, wishlistId) { + const token = getSignInToken(); + if (!token) { + redirectToSignin(); + } + + const toWishlist = wishlistId ?? (await getWishlists())[0].id; + + const response = await performMonolithGraphQLQuery( + addProductToWishlistMutation, + { + wishlistId: toWishlist, + sku: product, + }, + false, + token, + ); + + if (response.user_errors) { + console.error(response.user_errors); + } else { + window.location = `/customer/wishlist?wishlist_id=${toWishlist}`; + } +}