From 0f7c1518059e4531aaf484357e2157e03964131c Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Mon, 25 Jan 2021 13:41:14 +0100 Subject: [PATCH] Implement useCart/useAddItem --- .../handlers/get-logged-in-customer.ts | 3 +- framework/vendure/api/index.ts | 2 +- framework/vendure/cart/use-add-item.tsx | 55 ++++++++---- framework/vendure/cart/use-cart.tsx | 89 +++++++++++++------ framework/vendure/customer/use-customer.tsx | 5 +- framework/vendure/index.tsx | 8 +- 6 files changed, 110 insertions(+), 52 deletions(-) diff --git a/framework/vendure/api/customers/handlers/get-logged-in-customer.ts b/framework/vendure/api/customers/handlers/get-logged-in-customer.ts index 698235dda..d2c689cd3 100644 --- a/framework/vendure/api/customers/handlers/get-logged-in-customer.ts +++ b/framework/vendure/api/customers/handlers/get-logged-in-customer.ts @@ -1,4 +1,3 @@ -import type { GetLoggedInCustomerQuery } from '../../../schema' import type { CustomersHandlers } from '..' export const getLoggedInCustomerQuery = /* GraphQL */ ` @@ -22,7 +21,7 @@ export const getLoggedInCustomerQuery = /* GraphQL */ ` } ` -export type Customer = NonNullable +export type Customer = NonNullable const getLoggedInCustomer: CustomersHandlers['getLoggedInCustomer'] = async ({ req, diff --git a/framework/vendure/api/index.ts b/framework/vendure/api/index.ts index 1760ff935..653fa379c 100644 --- a/framework/vendure/api/index.ts +++ b/framework/vendure/api/index.ts @@ -9,7 +9,7 @@ const API_URL = process.env.VENDURE_SHOP_API_URL if (!API_URL) { throw new Error( - `The environment variable BIGCOMMERCE_STOREFRONT_API_URL is missing and it's required to access your store` + `The environment variable VENDURE_SHOP_API_URL is missing and it's required to access your store` ) } diff --git a/framework/vendure/cart/use-add-item.tsx b/framework/vendure/cart/use-add-item.tsx index ab8e634a2..0f8bb5278 100644 --- a/framework/vendure/cart/use-add-item.tsx +++ b/framework/vendure/cart/use-add-item.tsx @@ -1,25 +1,43 @@ -import { useCallback } from 'react' -import type { HookFetcher } from '@commerce/utils/types' import { CommerceError } from '@commerce/utils/errors' +import { HookFetcher } from '@commerce/utils/types' +import fetchGraphqlApi from '@framework/api/utils/fetch-graphql-api' import useCartAddItem from '@commerce/cart/use-add-item' -import type { ItemBody, AddItemBody } from '../api/cart' -import useCart, { Cart } from './use-cart' +import useCart from './use-cart' +import { useCallback } from 'react' -const defaultOpts = { - url: '/api/bigcommerce/cart', - method: 'POST', -} +export const addItemToOrderMutation = /* GraphQL */ ` + mutation addItemToOrder($variantId: ID!, $quantity: Int!) { + addItemToOrder(productVariantId: $variantId, quantity: $quantity) { + ... on Order { + id + code + totalQuantity + total + totalWithTax + lines { + id + productVariant { + featuredAsset { + id + preview + } + } + } + } + } + } +` -export type AddItemInput = ItemBody +export type AddItemInput = { productId?: number; variantId: number; quantity?: number; }; -export const fetcher: HookFetcher = ( +export const fetcher: HookFetcher = ( options, - { item }, + { variantId, quantity }, fetch ) => { if ( - item.quantity && - (!Number.isInteger(item.quantity) || item.quantity! < 1) + quantity && + (!Number.isInteger(quantity) || quantity! < 1) ) { throw new CommerceError({ message: 'The item quantity has to be a valid integer greater than 0', @@ -27,20 +45,23 @@ export const fetcher: HookFetcher = ( } return fetch({ - ...defaultOpts, ...options, - body: { item }, + query: addItemToOrderMutation, + variables: { variantId, quantity: quantity || 1 }, + }).then(res => { + console.log({ res }); + return res; }) } export function extendHook(customFetcher: typeof fetcher) { const useAddItem = () => { const { mutate } = useCart() - const fn = useCartAddItem(defaultOpts, customFetcher) + const fn = useCartAddItem({}, customFetcher) return useCallback( async function addItem(input: AddItemInput) { - const data = await fn({ item: input }) + const data = await fn({ quantity: input.quantity, variantId: input.variantId }) await mutate(data, false) return data }, diff --git a/framework/vendure/cart/use-cart.tsx b/framework/vendure/cart/use-cart.tsx index c1a9bed7a..7219c2eb7 100644 --- a/framework/vendure/cart/use-cart.tsx +++ b/framework/vendure/cart/use-cart.tsx @@ -1,46 +1,83 @@ -import { normalizeCart } from '../lib/normalize' -import type { HookFetcher } from '@commerce/utils/types' -import type { SwrOptions } from '@commerce/utils/use-data' -import useResponse from '@commerce/utils/use-response' +import fetchGraphqlApi from '@framework/api/utils/fetch-graphql-api' +import { HookFetcher } from '@commerce/utils/types' +import useData, { SwrOptions } from '@commerce/utils/use-data' import useCommerceCart, { CartInput } from '@commerce/cart/use-cart' -import type { Cart as BigCommerceCart } from '../api/cart' +import useResponse from '@commerce/utils/use-response' +import useAction from '@commerce/utils/use-action' +import { useCallback } from 'react' +import { normalizeCart } from '../../bigcommerce/lib/normalize' -const defaultOpts = { - url: '/api/bigcommerce/cart', - method: 'GET', -} +export const getCartQuery = /* GraphQL */ ` + query activeOrder { + activeOrder { + id + code + totalQuantity + subTotal + subTotalWithTax + total + totalWithTax + currencyCode + lines { + id + quantity + featuredAsset { + id + preview + } + productVariant { + name + product { + slug + } + productId + } + } + } + } +` -type UseCartResponse = BigCommerceCart & Cart - -export const fetcher: HookFetcher = ( +export const fetcher: HookFetcher = ( options, - { cartId }, + input, fetch ) => { - return cartId ? fetch({ ...defaultOpts, ...options }) : null + return fetch({ ...options, query: getCartQuery }) } export function extendHook( customFetcher: typeof fetcher, - swrOptions?: SwrOptions + swrOptions?: SwrOptions ) { const useCart = () => { - const response = useCommerceCart(defaultOpts, [], customFetcher, { - revalidateOnFocus: false, - ...swrOptions, - }) + const response = useData({}, [], customFetcher, swrOptions) const res = useResponse(response, { - normalizer: normalizeCart, + normalizer: (data => { + const order = data?.activeOrder; + console.log({ order }); + return (order ? { + id: order.id, + currency: { code: order.currencyCode }, + subTotal: order.subTotalWithTax / 100, + total: order.totalWithTax / 100, + items: order.lines?.map(l => ({ + name: l.productVariant.name, + quantity: l.quantity, + url: l.productVariant.product.slug, + variantId: l.productVariant.id, + productId: l.productVariant.productId, + images: [{ url: l.featuredAsset?.preview }] + })) + } : null) + }), descriptors: { isEmpty: { get() { - return Object.values(response.data?.line_items ?? {}).every( - (items) => !items.length - ) + return response.data?.activeOrder?.totalQuantity === 0 }, - enumerable: true, - }, - }, + enumerable: true + } + } }) return res diff --git a/framework/vendure/customer/use-customer.tsx b/framework/vendure/customer/use-customer.tsx index f44f16c1f..e5643392d 100644 --- a/framework/vendure/customer/use-customer.tsx +++ b/framework/vendure/customer/use-customer.tsx @@ -15,8 +15,9 @@ export const fetcher: HookFetcher = async ( _, fetch ) => { - const data = await fetch({ ...defaultOpts, ...options }) - return data?.customer ?? null + // const data = await fetch({ ...defaultOpts, ...options }) + // return data?.customer ?? null + return null; } export function extendHook( diff --git a/framework/vendure/index.tsx b/framework/vendure/index.tsx index fd14f765e..eba7be772 100644 --- a/framework/vendure/index.tsx +++ b/framework/vendure/index.tsx @@ -26,13 +26,13 @@ async function getError(res: Response) { export const vendureConfig: CommerceConfig = { locale: 'en-us', cartCookie: 'bc_cartId', - async fetcher({ url, method = 'GET', variables, body: bodyObj }) { - const hasBody = Boolean(variables || bodyObj) + async fetcher({ url, method = 'POST', variables, query, body: bodyObj }) { + const hasBody = Boolean(variables || query) const body = hasBody - ? JSON.stringify(variables ? { variables } : bodyObj) + ? JSON.stringify({ query, variables }) : undefined const headers = hasBody ? { 'Content-Type': 'application/json' } : undefined - const res = await fetch(url!, { method, body, headers }) + const res = await fetch('http://localhost:3001/shop-api'!, { method, body, headers, credentials: 'include' }) if (res.ok) { const { data } = await res.json()