From 28ee2eb0644d05111a9248e6da1d2062e2e3c027 Mon Sep 17 00:00:00 2001 From: tniezg Date: Tue, 17 Aug 2021 18:16:51 +0200 Subject: [PATCH] Allow updating line item quantity --- framework/spree/cart/use-update-item.tsx | 99 +++++++++++++++++-- .../spree/utils/createCreateFetchFetcher.ts | 5 +- 2 files changed, 94 insertions(+), 10 deletions(-) diff --git a/framework/spree/cart/use-update-item.tsx b/framework/spree/cart/use-update-item.tsx index 06d703f70..239cc6c98 100644 --- a/framework/spree/cart/use-update-item.tsx +++ b/framework/spree/cart/use-update-item.tsx @@ -1,18 +1,103 @@ -import { MutationHook } from '@commerce/utils/types' +import type { MutationHook } from '@commerce/utils/types' import useUpdateItem, { UseUpdateItem } from '@commerce/cart/use-update-item' +import type { UpdateItemHook } from '@commerce/types/cart' +import useCart from './use-cart' +import { useCallback } from 'react' +import { ValidationError } from '@commerce/utils/errors' +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token' +import type { SetQuantity } from '@spree/storefront-api-v2-sdk/types/interfaces/endpoints/CartClass' +import getCartToken from '@framework/utils/getCartToken' +import type { GraphQLFetcherResult } from '@commerce/api' +import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order' +import normalizeCart from '@framework/utils/normalizeCart' +import debounce from 'lodash.debounce' export default useUpdateItem as UseUpdateItem -export const handler: MutationHook = { +export const handler: MutationHook = { fetchOptions: { + url: '__UNUSED__', query: '', }, - async fetcher({ input, options, fetch }) {}, + async fetcher({ input, options, fetch }) { + console.info( + 'useRemoveItem fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ) + + const { itemId, item } = input + + if (!item.quantity) { + throw new ValidationError({ + message: 'Line item quantity needs to be provided.', + }) + } + + const token: IToken = { orderToken: getCartToken() } + const setQuantityParameters: SetQuantity = { + line_item_id: itemId, + quantity: item.quantity, + include: [ + 'line_items', + 'line_items.variant', + 'line_items.variant.product', + 'line_items.variant.product.images', + 'line_items.variant.images', + 'line_items.variant.option_values', + 'line_items.variant.product.option_types', + ].join(','), + } + + const { + data: { data: spreeSuccessResponse }, + } = await fetch>({ + variables: { + methodPath: 'cart.setQuantity', + arguments: [token, setQuantityParameters], + }, + }) + + return normalizeCart(spreeSuccessResponse, spreeSuccessResponse.data) + }, useHook: ({ fetch }) => - () => { - return async function addItem() { - return {} - } + (context) => { + console.log('useUpdateItem useHook called.') + + const { mutate } = useCart() + + return useCallback( + debounce(async (input: UpdateItemHook['actionInput']) => { + const itemId = context?.item?.id + const productId = input.productId ?? context?.item?.productId + const variantId = input.variantId ?? context?.item?.variantId + const quantity = input.quantity + + if (!itemId || !productId || !variantId) { + throw new ValidationError({ + message: 'Invalid input used for this operation', + }) + } + + const data = await fetch({ + input: { + item: { + productId, + variantId, + quantity, + }, + itemId, + }, + }) + + await mutate(data, false) + + return data + }, context?.wait ?? 500), + [] + ) }, } diff --git a/framework/spree/utils/createCreateFetchFetcher.ts b/framework/spree/utils/createCreateFetchFetcher.ts index 8c6e9e0cb..fec6ea61d 100644 --- a/framework/spree/utils/createCreateFetchFetcher.ts +++ b/framework/spree/utils/createCreateFetchFetcher.ts @@ -1,11 +1,10 @@ import * as qs from 'qs' import { errors } from '@spree/storefront-api-v2-sdk' import type { CreateFetcher } from '@spree/storefront-api-v2-sdk/types/interfaces/ClientConfig' -import { Request } from 'node-fetch' -// TODO: Fix rawFetch any type. const createCreateFetchFetcher = ({ fetch: rawFetch }): CreateFetcher => + // TODO: Fix rawFetch any type. (fetcherOptions) => { const { FetchError } = errors const sharedHeaders = { @@ -38,7 +37,7 @@ const createCreateFetchFetcher = try { const response = await rawFetch(absoluteUrl.toString(), { - method, + method: method.toUpperCase(), headers: { ...sharedHeaders, ...headers }, ...payload, })