feat: Update hooks

This commit is contained in:
Alessandro Casazza 2022-05-10 18:57:21 +02:00
parent a9e2d75f14
commit f11ff29e3b
No known key found for this signature in database
GPG Key ID: 3AF41B06C6495D3D
10 changed files with 239 additions and 167 deletions

View File

@ -1,54 +1,52 @@
import useAddItem, { UseAddItem } from '@vercel/commerce/cart/use-add-item'
import { MutationHook } from '@vercel/commerce/utils/types'
import { LineItem, Order } from '@commercelayer/js-sdk'
import getCredentials from '../api/utils/getCredentials'
import CLSdk from '@commercelayer/sdk'
import getCredentials, {
getOrganizationSlug,
} from '../api/utils/getCredentials'
import useCart from '../cart/use-cart'
import { useCallback } from 'react'
import getContentData from '../api/utils/getContentData'
export default useAddItem as UseAddItem<typeof handler>
export const handler: MutationHook<any> = {
fetchOptions: {
query: '',
},
async fetcher({ input, options, fetch }) {
async fetcher({ input }) {
const localOrderId = localStorage.getItem('CL_ORDER_ID')
const credentials = getCredentials()
const { accessToken, endpoint } = getCredentials()
const organization = getOrganizationSlug(endpoint).organization
const sdk = CLSdk({
accessToken,
organization,
})
const orderId =
localOrderId ||
(credentials.accessToken &&
(await Order.withCredentials(credentials).create({})).id)
localOrderId || (accessToken && (await sdk.orders.create({})).id)
if (orderId && input.variantId) {
!localOrderId && localStorage.setItem('CL_ORDER_ID', orderId)
const lineItem = await LineItem.withCredentials(credentials).create(
{
skuCode: input.variantId,
order: Order.build({ id: orderId }),
const [product] = await getContentData(input.productId)
const [image] = product.images
const lineItem = await sdk.line_items.create({
sku_code: input.variantId,
order: sdk.orders.relationship(orderId),
quantity: 1,
reference: input.productId,
_update_quantity: 1,
},
// @ts-ignore
{ rawResponse: true }
)
const attributes = lineItem.data.attributes
_update_quantity: true,
})
return {
id: lineItem.data.id,
name: attributes.name,
id: lineItem.id,
name: lineItem.name,
productId: input.productId,
variantId: input.variantId,
quantity: attributes.quantity,
price: attributes.unit_amount_float,
quantity: lineItem.quantity,
price: lineItem.unit_amount_float,
variant: {
id: lineItem.data.id,
name: attributes.name,
id: lineItem.id,
name: lineItem.name,
sku: input.variantId,
price: attributes.unit_amount_float,
image: {
url: `https://data.commercelayer.app/vercel-provider/${input.productId}_FLAT.png`,
altText: attributes.name,
width: 1000,
height: 1000,
},
price: lineItem.unit_amount_float,
image,
},
}
}
@ -57,6 +55,7 @@ export const handler: MutationHook<any> = {
({ fetch }) =>
() => {
const { mutate } = useCart()
return useCallback(
async function addItem(input) {
const data = await fetch({ input })

View File

@ -1,8 +1,10 @@
import { useMemo } from 'react'
import { SWRHook } from '@vercel/commerce/utils/types'
import useCart, { UseCart } from '@vercel/commerce/cart/use-cart'
import { Order } from '@commercelayer/js-sdk'
import getCredentials from '../api/utils/getCredentials'
import CLSdk from '@commercelayer/sdk'
import getCredentials, {
getOrganizationSlug,
} from '../api/utils/getCredentials'
import normalizeLineItems from '../api/utils/normalizeLineItems'
export default useCart as UseCart<typeof handler>
@ -14,25 +16,27 @@ export const handler: SWRHook<any> = {
async fetcher() {
const id = localStorage.getItem('CL_ORDER_ID') || ''
const credentials = getCredentials()
const organization = getOrganizationSlug(credentials.endpoint).organization
const sdk = CLSdk({
accessToken: credentials.accessToken,
organization,
})
if (id && credentials.accessToken) {
const clOrder = await Order.withCredentials(credentials)
.includes('lineItems')
.find(id, { rawResponse: true })
const attributes = clOrder.data.attributes
const orderStatus = attributes.status
if (['pending', 'draft'].includes(orderStatus)) {
const lineItems = clOrder?.included
? normalizeLineItems(clOrder?.included)
const order = await sdk.orders.retrieve(id, { include: ['line_items'] })
const orderStatus = order.status
if (orderStatus && ['pending', 'draft'].includes(orderStatus)) {
const lineItems = order.line_items
? normalizeLineItems(order.line_items)
: []
return {
id,
createdAt: attributes.created_at,
currency: { code: attributes.currency_code },
createdAt: order.created_at,
currency: { code: order.currency_code },
taxesIncluded: '',
lineItems,
lineItemsSubtotalPrice: '',
subtotalPrice: attributes.subtotal_amount_float,
totalPrice: attributes.total_amount_float,
subtotalPrice: order.subtotal_amount_float,
totalPrice: order.total_amount_float,
}
} else if (id) {
localStorage.removeItem('CL_ORDER_ID')
@ -53,6 +57,7 @@ export const handler: SWRHook<any> = {
({ useData }) =>
() => {
const response = useData()
console.log('response', response)
return useMemo(
() =>
Object.create(response, {

View File

@ -1,7 +1,11 @@
import { MutationHook } from '@vercel/commerce/utils/types'
import useRemoveItem, { UseRemoveItem } from '@vercel/commerce/cart/use-remove-item'
import getCredentials from '../api/utils/getCredentials'
import { LineItem } from '@commercelayer/js-sdk'
import useRemoveItem, {
UseRemoveItem,
} from '@vercel/commerce/cart/use-remove-item'
import getCredentials, {
getOrganizationSlug,
} from '../api/utils/getCredentials'
import CLSdk from '@commercelayer/sdk'
import useCart from './use-cart'
export default useRemoveItem as UseRemoveItem<typeof handler>
@ -13,8 +17,13 @@ export const handler: MutationHook<any> = {
async fetcher({ input: { id } }) {
const credentials = getCredentials()
const orderId = localStorage.getItem('CL_ORDER_ID')
const organization = getOrganizationSlug(credentials.endpoint).organization
const sdk = CLSdk({
accessToken: credentials.accessToken,
organization,
})
if (orderId && id) {
await LineItem.build({ id }).withCredentials(credentials).destroy()
await sdk.line_items.delete(id)
return {}
}
},

View File

@ -1,8 +1,13 @@
import { MutationHook } from '@vercel/commerce/utils/types'
import useUpdateItem, { UseUpdateItem } from '@vercel/commerce/cart/use-update-item'
import useUpdateItem, {
UseUpdateItem,
} from '@vercel/commerce/cart/use-update-item'
import useCart from '../cart/use-cart'
import getCredentials from '../api/utils/getCredentials'
import { LineItem } from '@commercelayer/js-sdk'
import getCredentials, {
getOrganizationSlug,
} from '../api/utils/getCredentials'
import CLSdk from '@commercelayer/sdk'
import getContentData from '../api/utils/getContentData'
export default useUpdateItem as UseUpdateItem<any>
@ -12,33 +17,29 @@ export const handler: MutationHook<any> = {
},
async fetcher({ input: { item, quantity } }) {
const credentials = getCredentials()
const organization = getOrganizationSlug(credentials.endpoint).organization
const sdk = CLSdk({
accessToken: credentials.accessToken,
organization,
})
const orderId = localStorage.getItem('CL_ORDER_ID')
if (orderId && item.id) {
const lineItem = (await LineItem.build({
id: item.id,
})
.withCredentials(credentials)
// @ts-ignore
.update({ quantity }, null, { rawResponse: true })) as any
const attributes = lineItem.data.attributes
const lineItem = await sdk.line_items.update({ id: item.id, quantity })
const [product] = await getContentData(item.productId)
const [image] = product.images
return {
id: lineItem.data.id,
name: attributes.name,
id: lineItem.id,
name: lineItem.name,
productId: item.productId,
variantId: item.variantId,
quantity: attributes.quantity,
price: attributes.unit_amount_float,
quantity: lineItem.quantity,
price: lineItem.unit_amount_float,
variant: {
id: lineItem.data.id,
name: attributes.name,
sku: lineItem.data.sku_code,
price: attributes.unit_amount_float,
image: {
url: `https://data.commercelayer.app/vercel-provider/${item.variantId}_FLAT.png`,
altText: 'Black Women Long Sleeve Shirt',
width: 1000,
height: 1000,
},
id: lineItem.id,
name: lineItem.name,
sku: lineItem.sku_code,
price: lineItem.unit_amount_float,
image,
},
}
}

View File

@ -1,4 +1,3 @@
import * as React from 'react'
import { ReactNode } from 'react'
import { CommercelayerProvider } from './provider'
import {

View File

@ -1,19 +1,20 @@
import { SWRHook } from '@vercel/commerce/utils/types'
import useSearch, { UseSearch } from '@vercel/commerce/product/use-search'
import data from '../data.json'
import getContentData from '../api/utils/getContentData'
import type { Products } from '../api/utils/getContentData'
export default useSearch as UseSearch<typeof handler>
const productsFinder = (s: string, c?: string, b?: string) => {
const { products } = data
const productsFinder = (
products: Products,
s: string,
c?: string,
b?: string
) => {
let p = products
if (s)
p = p.filter((p) => p.name.toLowerCase().search(s.toLowerCase()) !== -1)
if (s) p = p.filter((p) => p.name.toLowerCase().includes(s.toLowerCase()))
if (c)
p = p.filter(
(p) => p.categoryId.toLowerCase().search(c.toLowerCase()) !== -1
)
if (b)
p = p.filter((p) => p.brandId.toLowerCase().search(b.toLowerCase()) !== -1)
p = p.filter((p) => p.categoryId.toLowerCase().includes(c.toLowerCase()))
if (b) p = p.filter((p) => p.brandId.toLowerCase().includes(b.toLowerCase()))
return p
}
@ -21,19 +22,33 @@ export const handler: SWRHook<any> = {
fetchOptions: {
query: '',
},
async fetcher({ input, options, fetch }) {},
useHook:
({ useData }) =>
({ search, categoryId, brandId }) => {
const products = productsFinder(search, categoryId, brandId)
return {
data:
products.length > 0
async fetcher({ input }) {
const { search, categoryId, brandId } = input
const contentData = await getContentData()
const products = productsFinder(contentData, search, categoryId, brandId)
return products.length > 0
? {
products,
found: true,
}
: data,
: {
products: contentData,
}
},
useHook:
({ useData }) =>
(input = {}) => {
return useData({
input: [
['search', input.search],
['categoryId', input.categoryId],
['brandId', input.brandId],
['sort', input.sort],
],
swrOptions: {
revalidateOnFocus: false,
...input.swrOptions,
},
})
},
}

View File

@ -8,6 +8,9 @@ import { handler as useSearch } from './product/use-search'
import { handler as useLogin } from './auth/use-login'
import { handler as useLogout } from './auth/use-logout'
import { handler as useSignup } from './auth/use-signup'
import { handler as useWishlist } from './wishlist/use-wishlist'
import { handler as useWishlistAddItem } from './wishlist/use-add-item'
import { handler as useWishlistRemoveItem } from './wishlist/use-remove-item'
export const CommercelayerProvider = {
locale: 'en-US',
@ -18,6 +21,11 @@ export const CommercelayerProvider = {
customer: { useCustomer },
products: { useSearch },
auth: { useLogin, useLogout, useSignup },
wishlist: {
useWishlist,
useAddItem: useWishlistAddItem,
useRemoveItem: useWishlistRemoveItem,
},
}
export type Provider = typeof CommercelayerProvider

View File

@ -1,22 +1,48 @@
import { useCallback, useMemo } from 'react'
import useAddItem, { UseAddItem } from '@vercel/commerce/wishlist/use-add-item'
import useCustomer from '../customer/use-customer'
import { useCallback } from 'react'
import { MutationHook } from '@vercel/commerce/utils/types'
import useWishlist from './use-wishlist'
import { CommerceError } from '@vercel/commerce/utils/errors'
export default useAddItem as UseAddItem<typeof handler>
export function emptyHook() {
const useEmptyHook = async (options: any = {}) => {
export const handler: MutationHook<any> = {
fetchOptions: {
query: '',
},
async fetcher({ input }) {
const { variantId } = input
let wishlist = []
const localWishlist = localStorage.getItem('wishlist')
if (localWishlist) {
wishlist = JSON.parse(localWishlist)
if (!wishlist.includes(options.variantId)) {
wishlist.push(options.variantId)
if (!wishlist.includes(variantId)) {
wishlist.push(variantId)
}
} else {
wishlist.push(options.variantId)
wishlist.push(variantId)
}
localStorage.setItem('wishlist', JSON.stringify(wishlist))
return wishlist
},
useHook:
({ fetch }) =>
() => {
const { mutate } = useWishlist()
const { data: customer } = useCustomer()
return useCallback(
async function addItem(input) {
if (!customer) {
// A signed customer is required in order to have a wishlist
throw new CommerceError({
message: 'Signed customer not found',
})
}
return useEmptyHook
const data = await fetch({ input })
await mutate()
return data
},
[fetch]
)
},
}
export default emptyHook

View File

@ -1,20 +1,46 @@
type Options = {
includeProducts?: boolean
}
import useRemoveItem, {
UseRemoveItem,
} from '@vercel/commerce/wishlist/use-remove-item'
import useCustomer from '../customer/use-customer'
import { useCallback } from 'react'
import { MutationHook } from '@vercel/commerce/utils/types'
import useWishlist from './use-wishlist'
import { CommerceError } from '@vercel/commerce/utils/errors'
export default useRemoveItem as UseRemoveItem<typeof handler>
export function emptyHook(options?: Options) {
const useEmptyHook = async ({ id }: { id: string | number }) => {
export const handler: MutationHook<any> = {
fetchOptions: {
query: '',
},
async fetcher({ input }) {
const { id } = input
let wishlist = []
const localWishlist = localStorage.getItem('wishlist')
if (localWishlist) {
wishlist = JSON.parse(localWishlist)
wishlist = wishlist.filter((p: string) => p !== id)
wishlist = wishlist.filter((_p: string, key: number) => key !== id)
}
localStorage.setItem('wishlist', JSON.stringify(wishlist))
return wishlist
},
useHook:
({ fetch }) =>
() => {
const { mutate } = useWishlist()
const { data: customer } = useCustomer()
return useCallback(
async function addItem(input) {
if (!customer) {
// A signed customer is required in order to have a wishlist
throw new CommerceError({
message: 'Signed customer not found',
})
}
return useEmptyHook
const data = await fetch({ input })
await mutate()
return data
},
[fetch]
)
},
}
export default emptyHook

View File

@ -1,46 +1,24 @@
import { HookFetcher } from '@vercel/commerce/utils/types'
import type { Product } from '@vercel/commerce/types/product'
import data from '../data.json'
import { useCustomer } from '../customer'
import { SWRHook } from '@vercel/commerce/utils/types'
import useWishlist, {
UseWishlist,
} from '@vercel/commerce/wishlist/use-wishlist'
import useCustomer from '../customer/use-customer'
import getContentData from '../api/utils/getContentData'
export default useWishlist as UseWishlist<typeof handler>
const defaultOpts = {}
export type Wishlist = {
items: [
{
variant_id: number
product_id: number
id: number
product: Product
}
]
}
export interface UseWishlistOptions {
includeProducts?: boolean
}
export interface UseWishlistInput extends UseWishlistOptions {
customerId?: number
}
export const fetcher: HookFetcher<Wishlist | null, UseWishlistInput> = () => {
return null
}
export function extendHook(
customFetcher: typeof fetcher,
// swrOptions?: SwrOptions<Wishlist | null, UseWishlistInput>
swrOptions?: any
) {
const useWishlist = ({ includeProducts }: UseWishlistOptions = {}) => {
const { data: customer } = useCustomer()
export const handler: SWRHook<any> = {
fetchOptions: {
query: '',
},
async fetcher({ input }) {
const { customerEmail } = input
const getWishlist =
typeof localStorage !== 'undefined' && localStorage.getItem('wishlist')
if (getWishlist && customer?.email && data.products.length > 0) {
const products = await getContentData()
if (getWishlist && customerEmail && products.length > 0) {
const wishlist = JSON.parse(getWishlist)
const items = wishlist.map((wishlist: string, id: number) => {
const [product] = data.products.filter((p) =>
const [product] = products.filter((p) =>
wishlist.startsWith(p.id)
) as any
const [variant] = product?.variants
@ -51,14 +29,20 @@ export function extendHook(
product,
}
})
return { data: { items } }
return { items }
}
return { data: null }
return { items: [] }
},
useHook:
({ useData }) =>
(input = {}) => {
const { data: customer } = useCustomer()
return useData({
input: [['customerEmail', customer?.email]],
swrOptions: {
revalidateOnFocus: true,
...input.swrOptions,
},
})
},
}
useWishlist.extend = extendHook
return useWishlist
}
export default extendHook(fetcher)