Fix typescript errors & normalize cart

Signed-off-by: Chloe <pinkcloudvnn@gmail.com>
This commit is contained in:
Chloe 2022-04-28 19:09:35 +07:00
parent 7d1b542b6f
commit 2a32beb5cd
14 changed files with 59 additions and 39 deletions

View File

@ -5,7 +5,9 @@ import type {
HookFetcherContext, HookFetcherContext,
} from '@vercel/commerce/utils/types' } from '@vercel/commerce/utils/types'
import { ValidationError } from '@vercel/commerce/utils/errors' import { ValidationError } from '@vercel/commerce/utils/errors'
import useUpdateItem, { UseUpdateItem } from '@vercel/commerce/cart/use-update-item' import useUpdateItem, {
UseUpdateItem,
} from '@vercel/commerce/cart/use-update-item'
import type { LineItem, UpdateItemHook } from '@vercel/commerce/types/cart' import type { LineItem, UpdateItemHook } from '@vercel/commerce/types/cart'
import { handler as removeItemHandler } from './use-remove-item' import { handler as removeItemHandler } from './use-remove-item'
import useCart from './use-cart' import useCart from './use-cart'

View File

@ -4,7 +4,6 @@ import addCartItemsMutation from '../../mutations/add-cart-item'
import createCartMutation from '../../mutations/create-cart' import createCartMutation from '../../mutations/create-cart'
import type { CartEndpoint } from '.' import type { CartEndpoint } from '.'
import { CreateCartPayload } from '../../../../schema'
const addItem: CartEndpoint['handlers']['addItem'] = async ({ const addItem: CartEndpoint['handlers']['addItem'] = async ({
res, res,
@ -37,20 +36,28 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
} }
if (!cartId) { if (!cartId) {
const { data } = await config.fetch(createCartMutation, { variables }) const {
data: { createCart },
} = await config.fetch(createCartMutation, { variables })
res.setHeader('Set-Cookie', [ res.setHeader('Set-Cookie', [
getCartCookie(config.cartCookie, data.cart._id, config.cartCookieMaxAge), getCartCookie(
config.cartCookie,
createCart.cart._id,
config.cartCookieMaxAge
),
getCartCookie( getCartCookie(
config.anonymousCartTokenCookie, config.anonymousCartTokenCookie,
data.token, createCart.token,
config.cartCookieMaxAge config.cartCookieMaxAge
), ),
]) ])
return res.status(200).json({ data: normalizeCart(data.cart) }) return res.status(200).json({ data: normalizeCart(createCart.cart) })
} }
const { data } = await config.fetch(addCartItemsMutation, { const {
data: { addCartItems },
} = await config.fetch(addCartItemsMutation, {
variables: { variables: {
input: { input: {
items: variables.input.items, items: variables.input.items,
@ -60,7 +67,7 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
}, },
}) })
return res.status(200).json({ data: normalizeCart(data.cart) }) return res.status(200).json({ data: normalizeCart(addCartItems.cart) })
} }
export default addItem export default addItem

View File

@ -1,6 +1,5 @@
import { normalizeCart } from '../../../utils/normalize' import { normalizeCart } from '../../../utils/normalize'
import getCartCookie from '../../utils/get-cart-cookie' import getAnonymousCartQuery from '../../queries/get-anonymous-cart'
import getAnonymousCart from '../../queries/get-anonymous-cart'
import type { CartEndpoint } from '.' import type { CartEndpoint } from '.'
// Return current cart info // Return current cart info
@ -11,7 +10,9 @@ const getCart: CartEndpoint['handlers']['getCart'] = async ({
config, config,
}) => { }) => {
if (cartId && cookies[config.anonymousCartTokenCookie]) { if (cartId && cookies[config.anonymousCartTokenCookie]) {
const { data } = await config.fetch(getAnonymousCart, { const {
data: { cart: rawAnonymousCart },
} = await config.fetch(getAnonymousCartQuery, {
variables: { variables: {
cartId, cartId,
cartToken: cookies[config.anonymousCartTokenCookie], cartToken: cookies[config.anonymousCartTokenCookie],
@ -19,7 +20,7 @@ const getCart: CartEndpoint['handlers']['getCart'] = async ({
}) })
return res.status(200).json({ return res.status(200).json({
data: normalizeCart(data), data: normalizeCart(rawAnonymousCart),
}) })
} }

View File

@ -16,7 +16,9 @@ const removeItem: CartEndpoint['handlers']['removeItem'] = async ({
}) })
} }
const { data } = await config.fetch(removeCartItemsMutation, { const {
data: { removeCartItems },
} = await config.fetch(removeCartItemsMutation, {
variables: { variables: {
input: { input: {
cartId, cartId,
@ -31,7 +33,7 @@ const removeItem: CartEndpoint['handlers']['removeItem'] = async ({
getCartCookie(config.cartCookie, cartId, config.cartCookieMaxAge) getCartCookie(config.cartCookie, cartId, config.cartCookieMaxAge)
) )
res.status(200).json({ data: normalizeCart(data.cart) }) res.status(200).json({ data: normalizeCart(removeCartItems.cart) })
} }
export default removeItem export default removeItem

View File

@ -2,6 +2,7 @@ import { normalizeCart } from '../../../utils/normalize'
import getCartCookie from '../../utils/get-cart-cookie' import getCartCookie from '../../utils/get-cart-cookie'
import updateCartItemsQuantityMutation from '../../mutations/update-cart-item-quantity' import updateCartItemsQuantityMutation from '../../mutations/update-cart-item-quantity'
import type { CartEndpoint } from '.' import type { CartEndpoint } from '.'
import { UpdateCartItemsQuantityPayload } from '../../../../schema'
const updateItem: CartEndpoint['handlers']['updateItem'] = async ({ const updateItem: CartEndpoint['handlers']['updateItem'] = async ({
res, res,
@ -16,9 +17,11 @@ const updateItem: CartEndpoint['handlers']['updateItem'] = async ({
}) })
} }
const { data } = await config.fetch(updateCartItemsQuantityMutation, { const {
data: { updateCartItemsQuantity },
} = await config.fetch(updateCartItemsQuantityMutation, {
variables: { variables: {
input: { updateCartItemsQuantityInput: {
cartId, cartId,
cartToken: cookies[config.anonymousCartTokenCookie], cartToken: cookies[config.anonymousCartTokenCookie],
items: [{ cartItemId: itemId, quantity: item.quantity }], items: [{ cartItemId: itemId, quantity: item.quantity }],
@ -31,7 +34,7 @@ const updateItem: CartEndpoint['handlers']['updateItem'] = async ({
'Set-Cookie', 'Set-Cookie',
getCartCookie(config.cartCookie, cartId, config.cartCookieMaxAge) getCartCookie(config.cartCookie, cartId, config.cartCookieMaxAge)
) )
res.status(200).json({ data: normalizeCart(data.cart) }) res.status(200).json({ data: normalizeCart(updateCartItemsQuantity.cart) })
} }
export default updateItem export default updateItem

View File

@ -1,6 +1,6 @@
import { cartPayloadFragment } from '../queries/get-cart-query' import { cartPayloadFragment } from '../queries/get-cart-query'
const updateCartItemsQuantityMutation = ` const updateCartItemsQuantityMutation = /* GraphQL */ `
mutation updateCartItemsQuantity($updateCartItemsQuantityInput: UpdateCartItemsQuantityInput!) { mutation updateCartItemsQuantity($updateCartItemsQuantityInput: UpdateCartItemsQuantityInput!) {
updateCartItemsQuantity(input: $updateCartItemsQuantityInput) { updateCartItemsQuantity(input: $updateCartItemsQuantityInput) {
cart { cart {

View File

@ -1,7 +1,7 @@
import { cartQueryFragment } from './get-cart-query' import { cartQueryFragment } from './get-cart-query'
export const getAnonymousCart = /* GraphQL */ ` export const getAnonymousCart = `
query anonymousCartByCartIdQuery($cartId: ID!, $cartToken: String!) { query anonymousCartByCartIdQuery($cartId: ID!, $cartToken: String!, $itemsAfterCursor: ConnectionCursor) {
cart: anonymousCartByCartId(cartId: $cartId, cartToken: $cartToken) { cart: anonymousCartByCartId(cartId: $cartId, cartToken: $cartToken) {
${cartQueryFragment} ${cartQueryFragment}
} }

View File

@ -3,11 +3,12 @@ import useAddItem, { UseAddItem } from '@vercel/commerce/cart/use-add-item'
import type { AddItemHook } from '@vercel/commerce/types/cart' import type { AddItemHook } from '@vercel/commerce/types/cart'
import { CommerceError } from '@vercel/commerce/utils/errors' import { CommerceError } from '@vercel/commerce/utils/errors'
import { MutationHook } from '@vercel/commerce/utils/types' import { MutationHook } from '@vercel/commerce/utils/types'
import { CartTypes } from '../types/cart'
import useCart from './use-cart' import useCart from './use-cart'
export default useAddItem as UseAddItem<typeof handler> export default useAddItem as UseAddItem<typeof handler>
export const handler: MutationHook<AddItemHook> = { export const handler: MutationHook<AddItemHook<CartTypes>> = {
fetchOptions: { fetchOptions: {
url: '/api/cart', url: '/api/cart',
method: 'POST', method: 'POST',

View File

@ -1,6 +1,7 @@
import { useCallback } from 'react' import { useCallback } from 'react'
import { import {
HookFetcherContext, HookFetcherContext,
MutationHook,
MutationHookContext, MutationHookContext,
} from '@vercel/commerce/utils/types' } from '@vercel/commerce/utils/types'
import useRemoveItem, { import useRemoveItem, {
@ -24,16 +25,12 @@ export type RemoveItemFn<T = any> = T extends LineItem
export default useRemoveItem as UseRemoveItem<typeof handler> export default useRemoveItem as UseRemoveItem<typeof handler>
export const handler = { export const handler: MutationHook<RemoveItemHook> = {
fetchOptions: { fetchOptions: {
url: '/api/cart', url: '/api/cart',
method: 'DELETE', method: 'DELETE',
}, },
async fetcher({ async fetcher({ input: { itemId }, options, fetch }) {
input: { itemId },
options,
fetch,
}: HookFetcherContext<RemoveItemHook>) {
return await fetch({ ...options, body: { itemId } }) return await fetch({ ...options, body: { itemId } })
}, },
useHook: useHook:
@ -54,6 +51,6 @@ export const handler = {
return data return data
} }
return useCallback(removeItem, [fetch, mutate]) return useCallback(removeItem as RemoveItemFn<T>, [fetch, mutate])
}, },
} }

View File

@ -17,14 +17,14 @@ export default useUpdateItem as UseUpdateItem<typeof handler>
export const handler: MutationHook<UpdateItemHook> = { export const handler: MutationHook<UpdateItemHook> = {
fetchOptions: { fetchOptions: {
query: '/api/cart', url: '/api/cart',
method: 'PUT', method: 'PUT',
}, },
async fetcher({ input: { itemId, item }, options, fetch }) { async fetcher({ input: { itemId, item }, options, fetch }) {
if (Number.isInteger(item.quantity)) { if (Number.isInteger(item.quantity)) {
// Also allow the update hook to remove an item if the quantity is lower than 1 // Also allow the update hook to remove an item if the quantity is lower than 1
if (item.quantity! < 1) { if (item.quantity! < 1) {
return removeItemHandler.fetcher({ return removeItemHandler.fetcher!({
options: removeItemHandler.fetchOptions, options: removeItemHandler.fetchOptions,
input: { itemId }, input: { itemId },
fetch, fetch,

View File

@ -8,15 +8,13 @@ export type Cart = Core.Cart & {
} }
export type CartItemBody = Core.CartItemBody & { export type CartItemBody = Core.CartItemBody & {
price: { price?: {
amount: number amount: number
currency: string currencyCode: string
} }
} }
export type CartTypes = { export type CartTypes = Core.CartTypes & {
cart: Cart
item: Core.LineItem
itemBody: CartItemBody itemBody: CartItemBody
} }

View File

@ -273,6 +273,7 @@ function normalizeLineItem(cartItemEdge: CartItemEdge): LineItem {
optionTitle, optionTitle,
variantTitle, variantTitle,
quantity, quantity,
productSlug,
} = <CartItem>cartItem } = <CartItem>cartItem
return { return {
@ -292,7 +293,7 @@ function normalizeLineItem(cartItemEdge: CartItemEdge): LineItem {
price: priceWhenAdded?.amount, price: priceWhenAdded?.amount,
listPrice: compareAtPrice?.amount ?? 0, listPrice: compareAtPrice?.amount ?? 0,
}, },
path: '', path: productSlug ?? '',
discounts: [], discounts: [],
options: [ options: [
{ {

View File

@ -45,13 +45,17 @@ const CartItem = ({
target: { value }, target: { value },
}: ChangeEvent<HTMLInputElement>) => { }: ChangeEvent<HTMLInputElement>) => {
setQuantity(Number(value)) setQuantity(Number(value))
await updateItem({ quantity: Number(value) }) await updateItem({
quantity: Number(value),
variantId: item.variantId,
id: item.id,
})
} }
const increaseQuantity = async (n = 1) => { const increaseQuantity = async (n = 1) => {
const val = Number(quantity) + n const val = Number(quantity) + n
setQuantity(val) setQuantity(val)
await updateItem({ quantity: val }) await updateItem({ quantity: val, variantId: item.variantId, id: item.id })
} }
const handleRemove = async () => { const handleRemove = async () => {
@ -93,7 +97,7 @@ const CartItem = ({
width={150} width={150}
height={150} height={150}
src={item.variant.image?.url || placeholderImg} src={item.variant.image?.url || placeholderImg}
alt={item.variant.image?.altText || "Product Image"} alt={item.variant.image?.altText || 'Product Image'}
unoptimized unoptimized
/> />
</a> </a>

View File

@ -32,6 +32,10 @@ const ProductSidebar: FC<ProductSidebarProps> = ({ product, className }) => {
await addItem({ await addItem({
productId: String(product.id), productId: String(product.id),
variantId: String(variant ? variant.id : product.variants[0]?.id), variantId: String(variant ? variant.id : product.variants[0]?.id),
price: {
amount: product.price.value,
currencyCode: String(product.price.currencyCode),
},
}) })
openSidebar() openSidebar()
setLoading(false) setLoading(false)