create use-cart hook

This commit is contained in:
DuvCharles 2023-01-17 17:48:08 +01:00 committed by Hadrien Lucas
parent daba93efbe
commit 8adaa98c8d
7 changed files with 146 additions and 25 deletions

View File

@ -1,42 +1,43 @@
import { useMemo } from 'react'
import { SWRHook } from '@vercel/commerce/utils/types'
import useCart, { UseCart } from '@vercel/commerce/cart/use-cart'
import { getCartToken } from '../utils/token/cart-token'
import { normalizeCart } from '../utils/normalize/normalize-cart'
export default useCart as UseCart<typeof handler>
export const handler: SWRHook<any> = {
fetchOptions: {
query: '',
url: `/api/v2/shop/orders`,
method: 'GET',
},
async fetcher() {
return {
id: '',
createdAt: '',
currency: { code: '' },
taxesIncluded: '',
lineItems: [],
lineItemsSubtotalPrice: '',
subtotalPrice: 0,
totalPrice: 0,
fetcher: async ({ options, fetch }) => {
if (getCartToken()) {
const syliusCart = await fetch({
url: `${options.url}/${getCartToken()}`,
method: options.method,
})
return normalizeCart(syliusCart)
}
return null
},
useHook:
({ useData }) =>
(input) => {
const response = useData({
swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
})
return useMemo(
() =>
Object.create(
{},
{
Object.create(response, {
isEmpty: {
get() {
return true
return (response.data?.lineItems.length ?? 0) <= 0
},
enumerable: true,
},
}
),
[]
}),
[response]
)
},
}

View File

@ -2,3 +2,4 @@ export const API_URL = process.env.NEXT_PUBLIC_SYLIUS_API_URL
export const SYLIUS_CUSTOMER_TOKEN = 'sylius_customerToken'
export const SYLIUS_CUSTOMER_ROUTE = 'sylius_customerRoute'
export const SYLIUS_CART_TOKEN = 'sylius_cartToken'

View File

@ -8,5 +8,6 @@ module.exports = {
env: {
COMMERCE_SEARCH_ENABLED: process.env.COMMERCE_SEARCH_ENABLED,
COMMERCE_CUSTOMERAUTH_ENABLED: process.env.COMMERCE_CUSTOMERAUTH_ENABLED,
COMMERCE_CART_ENABLED: process.env.COMMERCE_CART_ENABLED,
},
}

View File

@ -0,0 +1,25 @@
import {
SyliusProduct,
SyliusProductOptionValue,
SyliusProductVariant,
} from './products'
export interface SyliusOrder {
id: number
currencyCode: string
taxTotal: number
itemsTotal: number
total: number
items: SyliusOrderItem[]
}
export interface SyliusOrderItem {
id: number
productName: string
quantity: number
unitPrice: number
discountedUnitPrice: number
variant: SyliusProductVariant
optionValues: SyliusProductOptionValue[]
product: SyliusProduct
}

View File

@ -21,7 +21,7 @@ export interface SyliusProductImage {
export interface SyliusProductVariant {
id: number
code: string
optionValues: SyliusProductOptionValues[]
optionValues: SyliusProductOptionValue[]
name: string
price: number
originalPrice: number
@ -32,13 +32,13 @@ export interface SyliusProductOption {
id: number
code: string
option: string
values: SyliusProductOptionValues[]
values: SyliusProductOptionValue[]
createdAt: Date
updatedAt: Date
name: string
}
export interface SyliusProductOptionValues {
export interface SyliusProductOptionValue {
id: number
code: string
value: string

View File

@ -0,0 +1,82 @@
import {
Cart,
ProductVariant,
SelectedOption,
} from '@vercel/commerce/types/cart'
import { LineItem } from '@vercel/commerce/types/cart'
import { SyliusOrder, SyliusOrderItem } from 'types/cart'
import {
SyliusProduct,
SyliusProductOption,
SyliusProductOptionValue,
SyliusProductVariant,
} from 'types/products'
import { normalizeProductImage } from './normalize-product'
export const normalizeCart = (syliusOrder: SyliusOrder): Cart => {
return {
id: syliusOrder.id.toString(),
createdAt: '',
currency: { code: syliusOrder.currencyCode },
taxesIncluded: syliusOrder.taxTotal > 0,
lineItems: syliusOrder.items.map((item) => normalizeOrderItem(item)),
lineItemsSubtotalPrice: syliusOrder.itemsTotal / 100,
subtotalPrice: syliusOrder.itemsTotal / 100,
totalPrice: syliusOrder.total / 100,
}
}
const normalizeOrderItem = (syliusOrderItem: SyliusOrderItem): LineItem => {
return {
id: syliusOrderItem.id.toString(),
variantId: syliusOrderItem.variant.id.toString(),
productId: syliusOrderItem.product.id.toString(),
name: syliusOrderItem.productName,
quantity: syliusOrderItem.quantity,
discounts: [],
path: syliusOrderItem.product.slug,
variant: normalizeOrderItemVariant(
syliusOrderItem.variant,
syliusOrderItem.product
),
options: syliusOrderItem.variant.optionValues.map((optionValue) =>
normalizeOrderItemOptionValue(
optionValue,
syliusOrderItem.product.options
)
),
}
}
const normalizeOrderItemVariant = (
syliusVariant: SyliusProductVariant,
syliusProduct: SyliusProduct
): ProductVariant => {
return {
id: syliusVariant.id.toString(),
sku: '',
name: syliusVariant.name,
requiresShipping: false,
price: syliusVariant.price / 100,
listPrice: syliusVariant.originalPrice / 100,
isInStock: syliusVariant.inStock,
image:
syliusProduct.images.length > 0
? normalizeProductImage(syliusProduct.images[0])
: undefined,
}
}
const normalizeOrderItemOptionValue = (
optionValue: SyliusProductOptionValue,
options: SyliusProductOption[]
): SelectedOption => {
const rightOption = options.filter((option) =>
option.values.some((value) => value.code === optionValue.code)
)[0]
return {
id: rightOption.id.toString(),
name: rightOption.name,
value: optionValue.value,
}
}

View File

@ -0,0 +1,11 @@
import { SYLIUS_CART_TOKEN } from '../../const'
export const getCartToken = () => localStorage.getItem(SYLIUS_CART_TOKEN)
export const setCartToken = (token: string | null) => {
if (!token) {
localStorage.removeItem(SYLIUS_CART_TOKEN)
} else {
localStorage.setItem(SYLIUS_CART_TOKEN, token)
}
}