diff --git a/packages/sylius/src/cart/use-cart.tsx b/packages/sylius/src/cart/use-cart.tsx index 8f92de3c9..adc6e90be 100644 --- a/packages/sylius/src/cart/use-cart.tsx +++ b/packages/sylius/src/cart/use-cart.tsx @@ -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 export const handler: SWRHook = { 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( - {}, - { - isEmpty: { - get() { - return true - }, - enumerable: true, + Object.create(response, { + isEmpty: { + get() { + return (response.data?.lineItems.length ?? 0) <= 0 }, - } - ), - [] + enumerable: true, + }, + }), + [response] ) }, } diff --git a/packages/sylius/src/const.ts b/packages/sylius/src/const.ts index 83e9dd2a7..bd970319d 100644 --- a/packages/sylius/src/const.ts +++ b/packages/sylius/src/const.ts @@ -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' diff --git a/packages/sylius/src/next.config.cjs b/packages/sylius/src/next.config.cjs index 7d1ebf26c..a750259bd 100644 --- a/packages/sylius/src/next.config.cjs +++ b/packages/sylius/src/next.config.cjs @@ -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, }, } diff --git a/packages/sylius/src/types/cart.ts b/packages/sylius/src/types/cart.ts new file mode 100644 index 000000000..c4a65f182 --- /dev/null +++ b/packages/sylius/src/types/cart.ts @@ -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 +} diff --git a/packages/sylius/src/types/products.ts b/packages/sylius/src/types/products.ts index 6eb456c91..114138b76 100644 --- a/packages/sylius/src/types/products.ts +++ b/packages/sylius/src/types/products.ts @@ -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 diff --git a/packages/sylius/src/utils/normalize/normalize-cart.ts b/packages/sylius/src/utils/normalize/normalize-cart.ts new file mode 100644 index 000000000..1e5a519ab --- /dev/null +++ b/packages/sylius/src/utils/normalize/normalize-cart.ts @@ -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, + } +} diff --git a/packages/sylius/src/utils/token/cart-token.ts b/packages/sylius/src/utils/token/cart-token.ts new file mode 100644 index 000000000..0390c3cb6 --- /dev/null +++ b/packages/sylius/src/utils/token/cart-token.ts @@ -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) + } +}