mirror of
https://github.com/vercel/commerce.git
synced 2025-05-17 23:16:59 +00:00
Add dynamic API endpoints
This commit is contained in:
parent
11609a9e71
commit
17788b1eb0
@ -9,12 +9,6 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
|
|||||||
body: { cartId, item },
|
body: { cartId, item },
|
||||||
config,
|
config,
|
||||||
}) => {
|
}) => {
|
||||||
if (!item) {
|
|
||||||
return res.status(400).json({
|
|
||||||
data: null,
|
|
||||||
errors: [{ message: 'Missing item' }],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (!item.quantity) item.quantity = 1
|
if (!item.quantity) item.quantity = 1
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
@ -41,7 +35,7 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
|
|||||||
'Set-Cookie',
|
'Set-Cookie',
|
||||||
getCartCookie(config.cartCookie, data.id, config.cartCookieMaxAge)
|
getCartCookie(config.cartCookie, data.id, config.cartCookieMaxAge)
|
||||||
)
|
)
|
||||||
res.status(200).json({ data: normalizeCart(data) })
|
res.status(200).json({ data: data ? normalizeCart(data) : null })
|
||||||
}
|
}
|
||||||
|
|
||||||
export default addItem
|
export default addItem
|
||||||
|
@ -19,6 +19,7 @@ export const handlers: CartEndpoint['handlers'] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cartApi = createEndpoint<CartAPI>({
|
const cartApi = createEndpoint<CartAPI>({
|
||||||
|
/* @ts-ignore */
|
||||||
handler: cartEndpoint,
|
handler: cartEndpoint,
|
||||||
handlers,
|
handlers,
|
||||||
})
|
})
|
||||||
|
@ -7,13 +7,6 @@ const removeItem: CartEndpoint['handlers']['removeItem'] = async ({
|
|||||||
body: { cartId, itemId },
|
body: { cartId, itemId },
|
||||||
config,
|
config,
|
||||||
}) => {
|
}) => {
|
||||||
if (!cartId || !itemId) {
|
|
||||||
return res.status(400).json({
|
|
||||||
data: null,
|
|
||||||
errors: [{ message: 'Invalid request' }],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await config.storeApiFetch<{ data: any } | null>(
|
const result = await config.storeApiFetch<{ data: any } | null>(
|
||||||
`/v3/carts/${cartId}/items/${itemId}?include=line_items.physical_items.options`,
|
`/v3/carts/${cartId}/items/${itemId}?include=line_items.physical_items.options`,
|
||||||
{ method: 'DELETE' }
|
{ method: 'DELETE' }
|
||||||
@ -28,7 +21,8 @@ const removeItem: CartEndpoint['handlers']['removeItem'] = async ({
|
|||||||
: // Remove the cart cookie if the cart was removed (empty items)
|
: // Remove the cart cookie if the cart was removed (empty items)
|
||||||
getCartCookie(config.cartCookie)
|
getCartCookie(config.cartCookie)
|
||||||
)
|
)
|
||||||
res.status(200).json({ data: data && normalizeCart(data) })
|
|
||||||
|
res.status(200).json({ data: data ? normalizeCart(data) : null })
|
||||||
}
|
}
|
||||||
|
|
||||||
export default removeItem
|
export default removeItem
|
||||||
|
@ -8,14 +8,7 @@ const updateItem: CartEndpoint['handlers']['updateItem'] = async ({
|
|||||||
body: { cartId, itemId, item },
|
body: { cartId, itemId, item },
|
||||||
config,
|
config,
|
||||||
}) => {
|
}) => {
|
||||||
if (!cartId || !itemId || !item) {
|
const { data } = await config.storeApiFetch<{ data?: any }>(
|
||||||
return res.status(400).json({
|
|
||||||
data: null,
|
|
||||||
errors: [{ message: 'Invalid request' }],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data } = await config.storeApiFetch(
|
|
||||||
`/v3/carts/${cartId}/items/${itemId}?include=line_items.physical_items.options`,
|
`/v3/carts/${cartId}/items/${itemId}?include=line_items.physical_items.options`,
|
||||||
{
|
{
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
27
packages/bigcommerce/src/api/endpoints/index.ts
Normal file
27
packages/bigcommerce/src/api/endpoints/index.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type { BigcommerceAPI, Provider } from '..'
|
||||||
|
|
||||||
|
import createEndpoints from '@vercel/commerce/api/endpoints'
|
||||||
|
|
||||||
|
import cart from './cart'
|
||||||
|
import login from './login'
|
||||||
|
import logout from './logout'
|
||||||
|
import signup from './signup'
|
||||||
|
import checkout from './checkout'
|
||||||
|
import customer from './customer'
|
||||||
|
import wishlist from './wishlist'
|
||||||
|
import products from './catalog/products'
|
||||||
|
|
||||||
|
const endpoints = {
|
||||||
|
cart,
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
signup,
|
||||||
|
checkout,
|
||||||
|
wishlist,
|
||||||
|
customer,
|
||||||
|
'catalog/products': products,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function bigcommerceAPI(commerce: BigcommerceAPI) {
|
||||||
|
return createEndpoints<Provider>(commerce, endpoints)
|
||||||
|
}
|
@ -9,7 +9,7 @@ export default useLogin as UseLogin<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<LoginHook> = {
|
export const handler: MutationHook<LoginHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/login',
|
url: '/api/commerce/login',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({ input: { email, password }, options, fetch }) {
|
async fetcher({ input: { email, password }, options, fetch }) {
|
||||||
|
@ -8,7 +8,7 @@ export default useLogout as UseLogout<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<LogoutHook> = {
|
export const handler: MutationHook<LogoutHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/logout',
|
url: '/api/commerce/logout',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
useHook:
|
useHook:
|
||||||
|
@ -9,7 +9,7 @@ export default useSignup as UseSignup<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<SignupHook> = {
|
export const handler: MutationHook<SignupHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/signup',
|
url: '/api/commerce/signup',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
|
@ -9,7 +9,7 @@ export default useAddItem as UseAddItem<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<AddItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({ input: item, options, fetch }) {
|
async fetcher({ input: item, options, fetch }) {
|
||||||
|
@ -7,7 +7,7 @@ export default useCart as UseCart<typeof handler>
|
|||||||
|
|
||||||
export const handler: SWRHook<GetCartHook> = {
|
export const handler: SWRHook<GetCartHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
useHook:
|
useHook:
|
||||||
|
@ -4,8 +4,14 @@ 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 useRemoveItem, { UseRemoveItem } from '@vercel/commerce/cart/use-remove-item'
|
import useRemoveItem, {
|
||||||
import type { Cart, LineItem, RemoveItemHook } from '@vercel/commerce/types/cart'
|
UseRemoveItem,
|
||||||
|
} from '@vercel/commerce/cart/use-remove-item'
|
||||||
|
import type {
|
||||||
|
Cart,
|
||||||
|
LineItem,
|
||||||
|
RemoveItemHook,
|
||||||
|
} from '@vercel/commerce/types/cart'
|
||||||
import useCart from './use-cart'
|
import useCart from './use-cart'
|
||||||
|
|
||||||
export type RemoveItemFn<T = any> = T extends LineItem
|
export type RemoveItemFn<T = any> = T extends LineItem
|
||||||
@ -20,7 +26,7 @@ export default useRemoveItem as UseRemoveItem<typeof handler>
|
|||||||
|
|
||||||
export const handler = {
|
export const handler = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
|
@ -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'
|
||||||
@ -18,7 +20,7 @@ export default useUpdateItem as UseUpdateItem<typeof handler>
|
|||||||
|
|
||||||
export const handler = {
|
export const handler = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
|
@ -6,7 +6,7 @@ export default useCustomer as UseCustomer<typeof handler>
|
|||||||
|
|
||||||
export const handler: SWRHook<CustomerHook> = {
|
export const handler: SWRHook<CustomerHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer',
|
url: '/api/commerce/customer',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
async fetcher({ options, fetch }) {
|
async fetcher({ options, fetch }) {
|
||||||
|
@ -14,7 +14,7 @@ export type SearchProductsInput = {
|
|||||||
|
|
||||||
export const handler: SWRHook<SearchProductsHook> = {
|
export const handler: SWRHook<SearchProductsHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/catalog/products',
|
url: '/api/commerce/catalog/products',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) {
|
fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) {
|
||||||
|
@ -10,7 +10,7 @@ export default useAddItem as UseAddItem<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<AddItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/wishlist',
|
url: '/api/commerce/wishlist',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
useHook:
|
useHook:
|
||||||
|
@ -12,7 +12,7 @@ export default useRemoveItem as UseRemoveItem<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<RemoveItemHook> = {
|
export const handler: MutationHook<RemoveItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/wishlist',
|
url: '/api/commerce/wishlist',
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
},
|
},
|
||||||
useHook:
|
useHook:
|
||||||
|
@ -10,7 +10,7 @@ import type { GetWishlistHook } from '../types/wishlist'
|
|||||||
export default useWishlist as UseWishlist<typeof handler>
|
export default useWishlist as UseWishlist<typeof handler>
|
||||||
export const handler: SWRHook<GetWishlistHook> = {
|
export const handler: SWRHook<GetWishlistHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/wishlist',
|
url: '/api/commerce/wishlist',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
async fetcher({ input: { customerId, includeProducts }, options, fetch }) {
|
async fetcher({ input: { customerId, includeProducts }, options, fetch }) {
|
||||||
|
@ -69,7 +69,10 @@ Then, open [/site/.env.template](/site/.env.template) and add the provider name
|
|||||||
Using BigCommerce as an example. The first thing to do is export a `CommerceProvider` component that includes a `provider` object with all the handlers that can be used for hooks:
|
Using BigCommerce as an example. The first thing to do is export a `CommerceProvider` component that includes a `provider` object with all the handlers that can be used for hooks:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import { getCommerceProvider, useCommerce as useCoreCommerce } from '@vercel/commerce'
|
import {
|
||||||
|
getCommerceProvider,
|
||||||
|
useCommerce as useCoreCommerce,
|
||||||
|
} from '@vercel/commerce'
|
||||||
import { bigcommerceProvider, BigcommerceProvider } from './provider'
|
import { bigcommerceProvider, BigcommerceProvider } from './provider'
|
||||||
|
|
||||||
export { bigcommerceProvider }
|
export { bigcommerceProvider }
|
||||||
@ -135,7 +138,7 @@ export default useCart as UseCart<typeof handler>
|
|||||||
|
|
||||||
export const handler: SWRHook<GetCartHook> = {
|
export const handler: SWRHook<GetCartHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
useHook:
|
useHook:
|
||||||
@ -175,7 +178,7 @@ export default useAddItem as UseAddItem<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<AddItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({ input: item, options, fetch }) {
|
async fetcher({ input: item, options, fetch }) {
|
||||||
@ -213,25 +216,26 @@ export const handler: MutationHook<AddItemHook> = {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Showing progress and features
|
## Showing progress and features
|
||||||
|
|
||||||
When creating a PR for a new provider, include this list in the PR description and mark the progress as you push so we can organize the code review. Not all points are required (but advised) so make sure to keep the list up to date.
|
When creating a PR for a new provider, include this list in the PR description and mark the progress as you push so we can organize the code review. Not all points are required (but advised) so make sure to keep the list up to date.
|
||||||
|
|
||||||
**Status**
|
**Status**
|
||||||
|
|
||||||
* [ ] CommerceProvider
|
- [ ] CommerceProvider
|
||||||
* [ ] Schema & TS types
|
- [ ] Schema & TS types
|
||||||
* [ ] API Operations - Get all collections
|
- [ ] API Operations - Get all collections
|
||||||
* [ ] API Operations - Get all pages
|
- [ ] API Operations - Get all pages
|
||||||
* [ ] API Operations - Get all products
|
- [ ] API Operations - Get all products
|
||||||
* [ ] API Operations - Get page
|
- [ ] API Operations - Get page
|
||||||
* [ ] API Operations - Get product
|
- [ ] API Operations - Get product
|
||||||
* [ ] API Operations - Get Shop Info (categories and vendors working — `vendors` query still a WIP PR on Reaction)
|
- [ ] API Operations - Get Shop Info (categories and vendors working — `vendors` query still a WIP PR on Reaction)
|
||||||
* [ ] Hook - Add Item
|
- [ ] Hook - Add Item
|
||||||
* [ ] Hook - Remove Item
|
- [ ] Hook - Remove Item
|
||||||
* [ ] Hook - Update Item
|
- [ ] Hook - Update Item
|
||||||
* [ ] Hook - Get Cart (account-tied carts working, anonymous carts working, cart reconciliation working)
|
- [ ] Hook - Get Cart (account-tied carts working, anonymous carts working, cart reconciliation working)
|
||||||
* [ ] Auth (based on a WIP PR on Reaction - still need to implement refresh tokens)
|
- [ ] Auth (based on a WIP PR on Reaction - still need to implement refresh tokens)
|
||||||
* [ ] Customer information
|
- [ ] Customer information
|
||||||
* [ ] Product attributes - Size, Colors
|
- [ ] Product attributes - Size, Colors
|
||||||
* [ ] Custom checkout
|
- [ ] Custom checkout
|
||||||
* [ ] Typing (in progress)
|
- [ ] Typing (in progress)
|
||||||
* [ ] Tests
|
- [ ] Tests
|
||||||
|
@ -1,60 +1,54 @@
|
|||||||
import type { CartSchema } from '../../types/cart'
|
|
||||||
import { CommerceAPIError } from '../utils/errors'
|
|
||||||
import isAllowedOperation from '../utils/is-allowed-operation'
|
|
||||||
import type { GetAPISchema } from '..'
|
import type { GetAPISchema } from '..'
|
||||||
|
import type { CartSchema } from '../../types/cart'
|
||||||
|
|
||||||
const cartEndpoint: GetAPISchema<any, CartSchema<any>>['endpoint']['handler'] =
|
import validateHandlers from '../utils/validate-handlers'
|
||||||
async (ctx) => {
|
|
||||||
const { req, res, handlers, config } = ctx
|
|
||||||
|
|
||||||
if (
|
import {
|
||||||
!isAllowedOperation(req, res, {
|
getCartBodySchema,
|
||||||
GET: handlers['getCart'],
|
addItemBodySchema,
|
||||||
POST: handlers['addItem'],
|
updateItemBodySchema,
|
||||||
PUT: handlers['updateItem'],
|
removeItemBodySchema,
|
||||||
DELETE: handlers['removeItem'],
|
} from '../../schemas/cart'
|
||||||
})
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { cookies } = req
|
const cartEndpoint: GetAPISchema<
|
||||||
const cartId = cookies[config.cartCookie]
|
any,
|
||||||
|
CartSchema
|
||||||
|
>['endpoint']['handler'] = async (ctx) => {
|
||||||
|
const { req, res, handlers, config } = ctx
|
||||||
|
|
||||||
try {
|
validateHandlers(req, res, {
|
||||||
// Return current cart info
|
GET: handlers['getCart'],
|
||||||
if (req.method === 'GET') {
|
POST: handlers['addItem'],
|
||||||
const body = { cartId }
|
PUT: handlers['updateItem'],
|
||||||
return await handlers['getCart']({ ...ctx, body })
|
DELETE: handlers['removeItem'],
|
||||||
}
|
})
|
||||||
|
|
||||||
// Create or add an item to the cart
|
const { cookies } = req
|
||||||
if (req.method === 'POST') {
|
const cartId = cookies[config.cartCookie]
|
||||||
const body = { ...req.body, cartId }
|
|
||||||
return await handlers['addItem']({ ...ctx, body })
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update item in cart
|
// Return current cart info
|
||||||
if (req.method === 'PUT') {
|
if (req.method === 'GET') {
|
||||||
const body = { ...req.body, cartId }
|
const body = getCartBodySchema.parse({ cartId })
|
||||||
return await handlers['updateItem']({ ...ctx, body })
|
return handlers['getCart']({ ...ctx, body })
|
||||||
}
|
|
||||||
|
|
||||||
// Remove an item from the cart
|
|
||||||
if (req.method === 'DELETE') {
|
|
||||||
const body = { ...req.body, cartId }
|
|
||||||
return await handlers['removeItem']({ ...ctx, body })
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
const message =
|
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create or add an item to the cart
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
const body = addItemBodySchema.parse({ ...req.body, cartId })
|
||||||
|
return handlers['addItem']({ ...ctx, body })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update item in cart
|
||||||
|
if (req.method === 'PUT') {
|
||||||
|
const body = updateItemBodySchema.parse({ ...req.body, cartId })
|
||||||
|
return handlers['updateItem']({ ...ctx, body })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove an item from the cart
|
||||||
|
if (req.method === 'DELETE') {
|
||||||
|
const body = removeItemBodySchema.parse({ ...req.body, cartId })
|
||||||
|
return handlers['removeItem']({ ...ctx, body })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default cartEndpoint
|
export default cartEndpoint
|
||||||
|
@ -1,31 +1,26 @@
|
|||||||
import type { ProductsSchema } from '../../../types/product'
|
import { searchProductBodySchema } from '../../../schemas/product'
|
||||||
import { CommerceAPIError } from '../../utils/errors'
|
|
||||||
import isAllowedOperation from '../../utils/is-allowed-operation'
|
|
||||||
import type { GetAPISchema } from '../..'
|
import type { GetAPISchema } from '../..'
|
||||||
|
import type { ProductsSchema } from '../../../types/product'
|
||||||
|
|
||||||
|
import validateHandlers from '../../utils/validate-handlers'
|
||||||
|
|
||||||
const productsEndpoint: GetAPISchema<
|
const productsEndpoint: GetAPISchema<
|
||||||
any,
|
any,
|
||||||
ProductsSchema
|
ProductsSchema
|
||||||
>['endpoint']['handler'] = async (ctx) => {
|
>['endpoint']['handler'] = (ctx) => {
|
||||||
const { req, res, handlers } = ctx
|
const { req, res, handlers } = ctx
|
||||||
|
|
||||||
if (!isAllowedOperation(req, res, { GET: handlers['getProducts'] })) {
|
validateHandlers(req, res, { GET: handlers['getProducts'] })
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
const body = searchProductBodySchema.parse({
|
||||||
const body = req.query
|
search: req.query.search,
|
||||||
return await handlers['getProducts']({ ...ctx, body })
|
categoryId: req.query.categoryId,
|
||||||
} catch (error) {
|
brandId: req.query.brandId,
|
||||||
console.error(error)
|
sort: req.query.sort,
|
||||||
|
locale: req.query.locale,
|
||||||
|
})
|
||||||
|
|
||||||
const message =
|
return handlers['getProducts']({ ...ctx, body })
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default productsEndpoint
|
export default productsEndpoint
|
||||||
|
@ -1,48 +1,32 @@
|
|||||||
import type { CheckoutSchema } from '../../types/checkout'
|
|
||||||
import type { GetAPISchema } from '..'
|
import type { GetAPISchema } from '..'
|
||||||
|
import type { CheckoutSchema } from '../../types/checkout'
|
||||||
|
|
||||||
import { CommerceAPIError } from '../utils/errors'
|
import validateHandlers from '../utils/validate-handlers'
|
||||||
import isAllowedOperation from '../utils/is-allowed-operation'
|
|
||||||
|
|
||||||
const checkoutEndpoint: GetAPISchema<
|
const checkoutEndpoint: GetAPISchema<
|
||||||
any,
|
any,
|
||||||
CheckoutSchema
|
CheckoutSchema
|
||||||
>['endpoint']['handler'] = async (ctx) => {
|
>['endpoint']['handler'] = (ctx) => {
|
||||||
const { req, res, handlers, config } = ctx
|
const { req, res, handlers, config } = ctx
|
||||||
|
|
||||||
if (
|
validateHandlers(req, res, {
|
||||||
!isAllowedOperation(req, res, {
|
GET: handlers['getCheckout'],
|
||||||
GET: handlers['getCheckout'],
|
POST: handlers['submitCheckout'],
|
||||||
POST: handlers['submitCheckout'],
|
})
|
||||||
})
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { cookies } = req
|
const { cookies } = req
|
||||||
const cartId = cookies[config.cartCookie]
|
const cartId = cookies[config.cartCookie]
|
||||||
|
|
||||||
try {
|
// Create checkout
|
||||||
// Create checkout
|
if (req.method === 'GET') {
|
||||||
if (req.method === 'GET') {
|
const body = { ...req.body, cartId }
|
||||||
const body = { ...req.body, cartId }
|
return handlers['getCheckout']({ ...ctx, body })
|
||||||
return await handlers['getCheckout']({ ...ctx, body })
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Create checkout
|
// Create checkout
|
||||||
if (req.method === 'POST' && handlers['submitCheckout']) {
|
if (req.method === 'POST' && handlers['submitCheckout']) {
|
||||||
const body = { ...req.body, cartId }
|
const body = { ...req.body, cartId }
|
||||||
return await handlers['submitCheckout']({ ...ctx, body })
|
return handlers['submitCheckout']({ ...ctx, body })
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
const message =
|
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,64 +1,47 @@
|
|||||||
import type { CustomerAddressSchema } from '../../../types/customer/address'
|
import type { CustomerAddressSchema } from '../../../types/customer/address'
|
||||||
import type { GetAPISchema } from '../..'
|
import type { GetAPISchema } from '../..'
|
||||||
|
|
||||||
import { CommerceAPIError } from '../../utils/errors'
|
import validateHandlers from '../../utils/validate-handlers'
|
||||||
import isAllowedOperation from '../../utils/is-allowed-operation'
|
|
||||||
|
|
||||||
const customerShippingEndpoint: GetAPISchema<
|
const customerShippingEndpoint: GetAPISchema<
|
||||||
any,
|
any,
|
||||||
CustomerAddressSchema
|
CustomerAddressSchema
|
||||||
>['endpoint']['handler'] = async (ctx) => {
|
>['endpoint']['handler'] = (ctx) => {
|
||||||
const { req, res, handlers, config } = ctx
|
const { req, res, handlers, config } = ctx
|
||||||
|
|
||||||
if (
|
validateHandlers(req, res, {
|
||||||
!isAllowedOperation(req, res, {
|
GET: handlers['getAddresses'],
|
||||||
GET: handlers['getAddresses'],
|
POST: handlers['addItem'],
|
||||||
POST: handlers['addItem'],
|
PUT: handlers['updateItem'],
|
||||||
PUT: handlers['updateItem'],
|
DELETE: handlers['removeItem'],
|
||||||
DELETE: handlers['removeItem'],
|
})
|
||||||
})
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { cookies } = req
|
const { cookies } = req
|
||||||
|
|
||||||
// Cart id might be usefull for anonymous shopping
|
// Cart id might be usefull for anonymous shopping
|
||||||
const cartId = cookies[config.cartCookie]
|
const cartId = cookies[config.cartCookie]
|
||||||
|
|
||||||
try {
|
// Return customer addresses
|
||||||
// Return customer addresses
|
if (req.method === 'GET') {
|
||||||
if (req.method === 'GET') {
|
const body = { cartId }
|
||||||
const body = { cartId }
|
return handlers['getAddresses']({ ...ctx, body })
|
||||||
return await handlers['getAddresses']({ ...ctx, body })
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Create or add an item to customer addresses list
|
// Create or add an item to customer addresses list
|
||||||
if (req.method === 'POST') {
|
if (req.method === 'POST') {
|
||||||
const body = { ...req.body, cartId }
|
const body = { ...req.body, cartId }
|
||||||
return await handlers['addItem']({ ...ctx, body })
|
return handlers['addItem']({ ...ctx, body })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update item in customer addresses list
|
// Update item in customer addresses list
|
||||||
if (req.method === 'PUT') {
|
if (req.method === 'PUT') {
|
||||||
const body = { ...req.body, cartId }
|
const body = { ...req.body, cartId }
|
||||||
return await handlers['updateItem']({ ...ctx, body })
|
return handlers['updateItem']({ ...ctx, body })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove an item from customer addresses list
|
// Remove an item from customer addresses list
|
||||||
if (req.method === 'DELETE') {
|
if (req.method === 'DELETE') {
|
||||||
const body = { ...req.body, cartId }
|
const body = { ...req.body, cartId }
|
||||||
return await handlers['removeItem']({ ...ctx, body })
|
return handlers['removeItem']({ ...ctx, body })
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
const message =
|
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,64 +1,47 @@
|
|||||||
import type { CustomerCardSchema } from '../../../types/customer/card'
|
import type { CustomerCardSchema } from '../../../types/customer/card'
|
||||||
import type { GetAPISchema } from '../..'
|
import type { GetAPISchema } from '../..'
|
||||||
|
|
||||||
import { CommerceAPIError } from '../../utils/errors'
|
import validateHandlers from '../../utils/validate-handlers'
|
||||||
import isAllowedOperation from '../../utils/is-allowed-operation'
|
|
||||||
|
|
||||||
const customerCardEndpoint: GetAPISchema<
|
const customerCardEndpoint: GetAPISchema<
|
||||||
any,
|
any,
|
||||||
CustomerCardSchema
|
CustomerCardSchema
|
||||||
>['endpoint']['handler'] = async (ctx) => {
|
>['endpoint']['handler'] = (ctx) => {
|
||||||
const { req, res, handlers, config } = ctx
|
const { req, res, handlers, config } = ctx
|
||||||
|
|
||||||
if (
|
validateHandlers(req, res, {
|
||||||
!isAllowedOperation(req, res, {
|
GET: handlers['getCards'],
|
||||||
GET: handlers['getCards'],
|
POST: handlers['addItem'],
|
||||||
POST: handlers['addItem'],
|
PUT: handlers['updateItem'],
|
||||||
PUT: handlers['updateItem'],
|
DELETE: handlers['removeItem'],
|
||||||
DELETE: handlers['removeItem'],
|
})
|
||||||
})
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { cookies } = req
|
const { cookies } = req
|
||||||
|
|
||||||
// Cart id might be usefull for anonymous shopping
|
// Cart id might be usefull for anonymous shopping
|
||||||
const cartId = cookies[config.cartCookie]
|
const cartId = cookies[config.cartCookie]
|
||||||
|
|
||||||
try {
|
// Create or add a card
|
||||||
// Create or add a card
|
if (req.method === 'GET') {
|
||||||
if (req.method === 'GET') {
|
const body = { ...req.body }
|
||||||
const body = { ...req.body }
|
return handlers['getCards']({ ...ctx, body })
|
||||||
return await handlers['getCards']({ ...ctx, body })
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Create or add an item to customer cards
|
// Create or add an item to customer cards
|
||||||
if (req.method === 'POST') {
|
if (req.method === 'POST') {
|
||||||
const body = { ...req.body, cartId }
|
const body = { ...req.body, cartId }
|
||||||
return await handlers['addItem']({ ...ctx, body })
|
return handlers['addItem']({ ...ctx, body })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update item in customer cards
|
// Update item in customer cards
|
||||||
if (req.method === 'PUT') {
|
if (req.method === 'PUT') {
|
||||||
const body = { ...req.body, cartId }
|
const body = { ...req.body, cartId }
|
||||||
return await handlers['updateItem']({ ...ctx, body })
|
return handlers['updateItem']({ ...ctx, body })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove an item from customer cards
|
// Remove an item from customer cards
|
||||||
if (req.method === 'DELETE') {
|
if (req.method === 'DELETE') {
|
||||||
const body = { ...req.body, cartId }
|
const body = { ...req.body, cartId }
|
||||||
return await handlers['removeItem']({ ...ctx, body })
|
return handlers['removeItem']({ ...ctx, body })
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
const message =
|
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,36 +1,20 @@
|
|||||||
import type { CustomerSchema } from '../../../types/customer'
|
import type { CustomerSchema } from '../../../types/customer'
|
||||||
import type { GetAPISchema } from '../..'
|
import type { GetAPISchema } from '../..'
|
||||||
|
|
||||||
import { CommerceAPIError } from '../../utils/errors'
|
import validateHandlers from '../../utils/validate-handlers'
|
||||||
import isAllowedOperation from '../../utils/is-allowed-operation'
|
|
||||||
|
|
||||||
const customerEndpoint: GetAPISchema<
|
const customerEndpoint: GetAPISchema<
|
||||||
any,
|
any,
|
||||||
CustomerSchema<any>
|
CustomerSchema
|
||||||
>['endpoint']['handler'] = async (ctx) => {
|
>['endpoint']['handler'] = (ctx) => {
|
||||||
const { req, res, handlers } = ctx
|
const { req, res, handlers } = ctx
|
||||||
|
|
||||||
if (
|
validateHandlers(req, res, {
|
||||||
!isAllowedOperation(req, res, {
|
GET: handlers['getLoggedInCustomer'],
|
||||||
GET: handlers['getLoggedInCustomer'],
|
})
|
||||||
})
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
const body = null
|
||||||
const body = null
|
return handlers['getLoggedInCustomer']({ ...ctx, body })
|
||||||
return await handlers['getLoggedInCustomer']({ ...ctx, body })
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
const message =
|
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default customerEndpoint
|
export default customerEndpoint
|
||||||
|
72
packages/commerce/src/api/endpoints/index.ts
Normal file
72
packages/commerce/src/api/endpoints/index.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
|
||||||
|
import type { APIProvider, CommerceAPI } from '..'
|
||||||
|
|
||||||
|
import { getErrorResponse } from '../utils/errors'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the catch-all api endpoint for the Commerce API.
|
||||||
|
* @param {CommerceAPI} commerce The Commerce API instance.
|
||||||
|
* @param endpoints An object containing the handlers for each endpoint.
|
||||||
|
*/
|
||||||
|
export default function createEndpoints<P extends APIProvider>(
|
||||||
|
commerce: CommerceAPI<P>,
|
||||||
|
endpoints: {
|
||||||
|
[key: string]: (commerce: CommerceAPI<P>) => NextApiHandler
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
const paths = Object.keys(endpoints)
|
||||||
|
|
||||||
|
const handlers = paths.reduce<Record<string, NextApiHandler>>(
|
||||||
|
(acc, path) =>
|
||||||
|
Object.assign(acc, {
|
||||||
|
[path]: endpoints[path](commerce),
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
return async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
|
try {
|
||||||
|
if (!req.query.commerce) {
|
||||||
|
throw new Error(
|
||||||
|
'Invalid configuration. Please make sure that the /pages/api/commerce/[[...commerce]].ts route is configured correctly, and it passes the commerce instance.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the url path
|
||||||
|
*/
|
||||||
|
const path = Array.isArray(req.query.commerce)
|
||||||
|
? req.query.commerce.join('/')
|
||||||
|
: req.query.commerce
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the handler for this path exists and return a 404 if it doesn't
|
||||||
|
*/
|
||||||
|
if (!paths.includes(path)) {
|
||||||
|
throw new Error(
|
||||||
|
`Endpoint handler not implemented. Please use one of the available api endpoints: ${paths.join(
|
||||||
|
', '
|
||||||
|
)}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await handlers[path](req, res)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the handler returns a value but the response hasn't been sent yet, send it
|
||||||
|
*/
|
||||||
|
if (!res.headersSent) {
|
||||||
|
res.status(200).json({
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
const { status, data, errors } = getErrorResponse(error)
|
||||||
|
res.status(status).json({
|
||||||
|
data,
|
||||||
|
errors,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,36 +1,20 @@
|
|||||||
import type { LoginSchema } from '../../types/login'
|
|
||||||
import { CommerceAPIError } from '../utils/errors'
|
|
||||||
import isAllowedOperation from '../utils/is-allowed-operation'
|
|
||||||
import type { GetAPISchema } from '..'
|
import type { GetAPISchema } from '..'
|
||||||
|
import type { LoginSchema } from '../../types/login'
|
||||||
|
|
||||||
const loginEndpoint: GetAPISchema<
|
import validateHandlers from '../utils/validate-handlers'
|
||||||
any,
|
|
||||||
LoginSchema<any>
|
const loginEndpoint: GetAPISchema<any, LoginSchema>['endpoint']['handler'] = (
|
||||||
>['endpoint']['handler'] = async (ctx) => {
|
ctx
|
||||||
|
) => {
|
||||||
const { req, res, handlers } = ctx
|
const { req, res, handlers } = ctx
|
||||||
|
|
||||||
if (
|
validateHandlers(req, res, {
|
||||||
!isAllowedOperation(req, res, {
|
POST: handlers['login'],
|
||||||
POST: handlers['login'],
|
GET: handlers['login'],
|
||||||
GET: handlers['login'],
|
})
|
||||||
})
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
const body = req.body ?? {}
|
||||||
const body = req.body ?? {}
|
return handlers['login']({ ...ctx, body })
|
||||||
return await handlers['login']({ ...ctx, body })
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
const message =
|
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default loginEndpoint
|
export default loginEndpoint
|
||||||
|
@ -1,35 +1,20 @@
|
|||||||
import type { LogoutSchema } from '../../types/logout'
|
|
||||||
import { CommerceAPIError } from '../utils/errors'
|
|
||||||
import isAllowedOperation from '../utils/is-allowed-operation'
|
|
||||||
import type { GetAPISchema } from '..'
|
import type { GetAPISchema } from '..'
|
||||||
|
import type { LogoutSchema } from '../../types/logout'
|
||||||
|
|
||||||
const logoutEndpoint: GetAPISchema<any, LogoutSchema>['endpoint']['handler'] =
|
import validateHandlers from '../utils/validate-handlers'
|
||||||
async (ctx) => {
|
|
||||||
const { req, res, handlers } = ctx
|
|
||||||
|
|
||||||
if (
|
const logoutEndpoint: GetAPISchema<any, LogoutSchema>['endpoint']['handler'] = (
|
||||||
!isAllowedOperation(req, res, {
|
ctx
|
||||||
GET: handlers['logout'],
|
) => {
|
||||||
})
|
const { req, res, handlers } = ctx
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
validateHandlers(req, res, {
|
||||||
const redirectTo = req.query.redirect_to
|
GET: handlers['logout'],
|
||||||
const body = typeof redirectTo === 'string' ? { redirectTo } : {}
|
})
|
||||||
|
const redirectTo = req.query.redirect_to
|
||||||
|
const body = typeof redirectTo === 'string' ? { redirectTo } : {}
|
||||||
|
|
||||||
return await handlers['logout']({ ...ctx, body })
|
return handlers['logout']({ ...ctx, body })
|
||||||
} catch (error) {
|
}
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
const message =
|
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default logoutEndpoint
|
export default logoutEndpoint
|
||||||
|
@ -1,36 +1,21 @@
|
|||||||
import type { SignupSchema } from '../../types/signup'
|
|
||||||
import { CommerceAPIError } from '../utils/errors'
|
|
||||||
import isAllowedOperation from '../utils/is-allowed-operation'
|
|
||||||
import type { GetAPISchema } from '..'
|
import type { GetAPISchema } from '..'
|
||||||
|
import type { SignupSchema } from '../../types/signup'
|
||||||
|
|
||||||
const signupEndpoint: GetAPISchema<any, SignupSchema>['endpoint']['handler'] =
|
import validateHandlers from '../utils/validate-handlers'
|
||||||
async (ctx) => {
|
|
||||||
const { req, res, handlers, config } = ctx
|
|
||||||
|
|
||||||
if (
|
const signupEndpoint: GetAPISchema<any, SignupSchema>['endpoint']['handler'] = (
|
||||||
!isAllowedOperation(req, res, {
|
ctx
|
||||||
POST: handlers['signup'],
|
) => {
|
||||||
})
|
const { req, res, handlers, config } = ctx
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { cookies } = req
|
validateHandlers(req, res, {
|
||||||
const cartId = cookies[config.cartCookie]
|
POST: handlers['signup'],
|
||||||
|
})
|
||||||
|
const { cookies } = req
|
||||||
|
const cartId = cookies[config.cartCookie]
|
||||||
|
|
||||||
try {
|
const body = { ...req.body, cartId }
|
||||||
const body = { ...req.body, cartId }
|
return handlers['signup']({ ...ctx, body })
|
||||||
return await handlers['signup']({ ...ctx, body })
|
}
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
const message =
|
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default signupEndpoint
|
export default signupEndpoint
|
||||||
|
@ -1,57 +1,42 @@
|
|||||||
import type { WishlistSchema } from '../../types/wishlist'
|
|
||||||
import { CommerceAPIError } from '../utils/errors'
|
|
||||||
import isAllowedOperation from '../utils/is-allowed-operation'
|
|
||||||
import type { GetAPISchema } from '..'
|
import type { GetAPISchema } from '..'
|
||||||
|
import type { WishlistSchema } from '../../types/wishlist'
|
||||||
|
|
||||||
|
import validateHandlers from '../utils/validate-handlers'
|
||||||
|
|
||||||
const wishlistEndpoint: GetAPISchema<
|
const wishlistEndpoint: GetAPISchema<
|
||||||
any,
|
any,
|
||||||
WishlistSchema<any>
|
WishlistSchema
|
||||||
>['endpoint']['handler'] = async (ctx) => {
|
>['endpoint']['handler'] = (ctx) => {
|
||||||
const { req, res, handlers, config } = ctx
|
const { req, res, handlers, config } = ctx
|
||||||
|
|
||||||
if (
|
validateHandlers(req, res, {
|
||||||
!isAllowedOperation(req, res, {
|
GET: handlers['getWishlist'],
|
||||||
GET: handlers['getWishlist'],
|
POST: handlers['addItem'],
|
||||||
POST: handlers['addItem'],
|
DELETE: handlers['removeItem'],
|
||||||
DELETE: handlers['removeItem'],
|
})
|
||||||
})
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { cookies } = req
|
const { cookies } = req
|
||||||
const customerToken = cookies[config.customerCookie]
|
const customerToken = cookies[config.customerCookie]
|
||||||
|
|
||||||
try {
|
// Return current wishlist info
|
||||||
// Return current wishlist info
|
if (req.method === 'GET') {
|
||||||
if (req.method === 'GET') {
|
const body = {
|
||||||
const body = {
|
customerToken,
|
||||||
customerToken,
|
includeProducts: !!req.query.products,
|
||||||
includeProducts: req.query.products === '1',
|
|
||||||
}
|
|
||||||
return await handlers['getWishlist']({ ...ctx, body })
|
|
||||||
}
|
}
|
||||||
|
return handlers['getWishlist']({ ...ctx, body })
|
||||||
|
}
|
||||||
|
|
||||||
// Add an item to the wishlist
|
// Add an item to the wishlist
|
||||||
if (req.method === 'POST') {
|
if (req.method === 'POST') {
|
||||||
const body = { ...req.body, customerToken }
|
const body = { ...req.body, customerToken }
|
||||||
return await handlers['addItem']({ ...ctx, body })
|
return handlers['addItem']({ ...ctx, body })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove an item from the wishlist
|
// Remove an item from the wishlist
|
||||||
if (req.method === 'DELETE') {
|
if (req.method === 'DELETE') {
|
||||||
const body = { ...req.body, customerToken }
|
const body = { ...req.body, customerToken }
|
||||||
return await handlers['removeItem']({ ...ctx, body })
|
return handlers['removeItem']({ ...ctx, body })
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
const message =
|
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
import { ZodError } from 'zod'
|
||||||
|
|
||||||
import type { Response } from '@vercel/fetch'
|
import type { Response } from '@vercel/fetch'
|
||||||
|
import { CommerceError } from '../../utils/errors'
|
||||||
|
|
||||||
export class CommerceAPIError extends Error {
|
export class CommerceAPIError extends Error {
|
||||||
status: number
|
status: number
|
||||||
@ -20,3 +23,51 @@ export class CommerceNetworkError extends Error {
|
|||||||
this.name = 'CommerceNetworkError'
|
this.name = 'CommerceNetworkError'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getErrorResponse = (error: unknown) => {
|
||||||
|
if (error instanceof CommerceAPIError) {
|
||||||
|
return {
|
||||||
|
status: error.status || 500,
|
||||||
|
data: error.data || null,
|
||||||
|
errors: [
|
||||||
|
{ message: 'An unexpected error ocurred with the Commerce API' },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error instanceof ZodError) {
|
||||||
|
return {
|
||||||
|
status: 400,
|
||||||
|
data: null,
|
||||||
|
errors: error.issues,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 500,
|
||||||
|
data: null,
|
||||||
|
errors: [{ message: 'An unexpected error ocurred' }],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getOperationError = (operation: string, error: unknown) => {
|
||||||
|
if (error instanceof ZodError) {
|
||||||
|
return new CommerceError({
|
||||||
|
code: 'SCHEMA_VALIDATION_ERROR',
|
||||||
|
message:
|
||||||
|
`The ${operation} operation returned invalid data and has ${
|
||||||
|
error.issues.length
|
||||||
|
} parse ${error.issues.length === 1 ? 'error' : 'errors'}: \n` +
|
||||||
|
error.issues
|
||||||
|
.map(
|
||||||
|
(e, index) =>
|
||||||
|
`Error #${index + 1} ${
|
||||||
|
e.path.length > 0 ? `Path: ${e.path.join('.')}, ` : ''
|
||||||
|
}Code: ${e.code}, Message: ${e.message}`
|
||||||
|
)
|
||||||
|
.join('\n'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
@ -2,7 +2,11 @@ import type { NextApiRequest, NextApiResponse } from 'next'
|
|||||||
import isAllowedMethod, { HTTP_METHODS } from './is-allowed-method'
|
import isAllowedMethod, { HTTP_METHODS } from './is-allowed-method'
|
||||||
import { APIHandler } from './types'
|
import { APIHandler } from './types'
|
||||||
|
|
||||||
export default function isAllowedOperation(
|
/**
|
||||||
|
* Checks if the request method is allowed
|
||||||
|
* @throws Error if the method is not allowed
|
||||||
|
*/
|
||||||
|
export default function validateHandlers(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse,
|
res: NextApiResponse,
|
||||||
allowedOperations: { [k in HTTP_METHODS]?: APIHandler<any, any> }
|
allowedOperations: { [k in HTTP_METHODS]?: APIHandler<any, any> }
|
||||||
@ -15,5 +19,7 @@ export default function isAllowedOperation(
|
|||||||
return arr
|
return arr
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return isAllowedMethod(req, res, allowedMethods)
|
if (!isAllowedMethod(req, res, allowedMethods)) {
|
||||||
|
throw new Error(`Method ${req.method} Not Allowed for this url: ${req.url}`)
|
||||||
|
}
|
||||||
}
|
}
|
27
packages/commerce/src/schemas/cart.ts
Normal file
27
packages/commerce/src/schemas/cart.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
export const getCartBodySchema = z.object({
|
||||||
|
cartId: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const cartItemBodySchema = z.object({
|
||||||
|
variantId: z.string(),
|
||||||
|
productId: z.string().optional(),
|
||||||
|
quantity: z.number().min(1).optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const addItemBodySchema = z.object({
|
||||||
|
cartId: z.string().optional(),
|
||||||
|
item: cartItemBodySchema,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const updateItemBodySchema = z.object({
|
||||||
|
cartId: z.string(),
|
||||||
|
itemId: z.string(),
|
||||||
|
item: cartItemBodySchema,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const removeItemBodySchema = z.object({
|
||||||
|
cartId: z.string(),
|
||||||
|
itemId: z.string(),
|
||||||
|
})
|
18
packages/commerce/src/schemas/page.ts
Normal file
18
packages/commerce/src/schemas/page.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
export const pageSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
url: z.string().startsWith('/').optional(),
|
||||||
|
body: z.string(),
|
||||||
|
is_visible: z.boolean().optional(),
|
||||||
|
sort_order: z.number().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const pagesPathsSchema = z.array(
|
||||||
|
z.object({
|
||||||
|
page: z.object({
|
||||||
|
path: z.string().startsWith('/'),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
60
packages/commerce/src/schemas/product.ts
Normal file
60
packages/commerce/src/schemas/product.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
export const productPriceSchema = z.object({
|
||||||
|
value: z.number(),
|
||||||
|
currencyCode: z.string().max(3).optional(),
|
||||||
|
retailPrice: z.number().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const productOptionSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
displayName: z.string(),
|
||||||
|
values: z.array(
|
||||||
|
z.object({
|
||||||
|
label: z.string(),
|
||||||
|
hexColors: z.array(z.string()).optional(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const productImageSchema = z.object({
|
||||||
|
url: z.string().url().or(z.string().startsWith('/')),
|
||||||
|
alt: z.string().optional(),
|
||||||
|
width: z.number().optional(),
|
||||||
|
height: z.number().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const productVariantSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
sku: z.string().nullish(),
|
||||||
|
name: z.string().optional(),
|
||||||
|
options: z.array(productOptionSchema),
|
||||||
|
image: productImageSchema.optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const productSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
descriptionHtml: z.string().optional(),
|
||||||
|
sku: z.string().nullish(),
|
||||||
|
slug: z.string(),
|
||||||
|
path: z.string().startsWith('/'),
|
||||||
|
images: z.array(productImageSchema),
|
||||||
|
variants: z.array(productVariantSchema),
|
||||||
|
price: productPriceSchema,
|
||||||
|
options: z.array(productOptionSchema),
|
||||||
|
vendor: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const productsPathsSchema = z.array(
|
||||||
|
z.object({ path: z.string().startsWith('/') })
|
||||||
|
)
|
||||||
|
|
||||||
|
export const searchProductBodySchema = z.object({
|
||||||
|
search: z.string().optional(),
|
||||||
|
categoryId: z.string().optional(),
|
||||||
|
brandId: z.string().optional(),
|
||||||
|
sort: z.string().optional(),
|
||||||
|
locale: z.string().optional(),
|
||||||
|
})
|
18
packages/commerce/src/schemas/site.ts
Normal file
18
packages/commerce/src/schemas/site.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
export const siteInfoSchema = z.object({
|
||||||
|
categories: z.array(
|
||||||
|
z.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
path: z.string().startsWith('/'),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
brands: z.array(
|
||||||
|
z.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
path: z.string().startsWith('/'),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
@ -158,11 +158,11 @@ export type CartHandlers<T extends CartTypes = CartTypes> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type GetCartHandler<T extends CartTypes = CartTypes> = GetCartHook<T> & {
|
export type GetCartHandler<T extends CartTypes = CartTypes> = GetCartHook<T> & {
|
||||||
body: { cartId?: string }
|
body: { cartId: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AddItemHandler<T extends CartTypes = CartTypes> = AddItemHook<T> & {
|
export type AddItemHandler<T extends CartTypes = CartTypes> = AddItemHook<T> & {
|
||||||
body: { cartId: string }
|
body: { cartId?: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UpdateItemHandler<T extends CartTypes = CartTypes> =
|
export type UpdateItemHandler<T extends CartTypes = CartTypes> =
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
16
packages/commercejs/src/api/endpoints/index.ts
Normal file
16
packages/commercejs/src/api/endpoints/index.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import type { CommercejsAPI } from '..'
|
||||||
|
|
||||||
|
import handleEndpoints from '@vercel/commerce/api/endpoints'
|
||||||
|
|
||||||
|
import login from './login'
|
||||||
|
import checkout from './checkout'
|
||||||
|
|
||||||
|
const endpoints = {
|
||||||
|
login,
|
||||||
|
checkout,
|
||||||
|
}
|
||||||
|
|
||||||
|
const handler = (commerce: CommercejsAPI) =>
|
||||||
|
handleEndpoints(commerce, endpoints)
|
||||||
|
|
||||||
|
export default handler
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -11,7 +11,7 @@ export default useSubmitCheckout as UseSubmitCheckout<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<SubmitCheckoutHook> = {
|
export const handler: MutationHook<SubmitCheckoutHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/checkout',
|
url: '/api/commerce/checkout',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({ input: item, options, fetch }) {
|
async fetcher({ input: item, options, fetch }) {
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
26
packages/kibocommerce/src/api/endpoints/index.ts
Normal file
26
packages/kibocommerce/src/api/endpoints/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import type { KiboCommerceAPI } from '..'
|
||||||
|
|
||||||
|
import handleEndpoints from '@vercel/commerce/api/endpoints'
|
||||||
|
|
||||||
|
import cart from './cart'
|
||||||
|
import login from './login'
|
||||||
|
import logout from './logout'
|
||||||
|
import signup from './signup'
|
||||||
|
import customer from './customer'
|
||||||
|
import wishlist from './wishlist'
|
||||||
|
import products from './catalog/products'
|
||||||
|
|
||||||
|
const endpoints = {
|
||||||
|
cart,
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
signup,
|
||||||
|
wishlist,
|
||||||
|
customer,
|
||||||
|
'catalog/products': products,
|
||||||
|
}
|
||||||
|
|
||||||
|
const handler = (commerce: KiboCommerceAPI) =>
|
||||||
|
handleEndpoints(commerce, endpoints)
|
||||||
|
|
||||||
|
export default handler
|
@ -10,7 +10,7 @@ export default useLogin as UseLogin<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<LoginHook> = {
|
export const handler: MutationHook<LoginHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/login',
|
url: '/api/commerce/login',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({ input: { email, password }, options, fetch }) {
|
async fetcher({ input: { email, password }, options, fetch }) {
|
||||||
|
@ -9,7 +9,7 @@ export default useLogout as UseLogout<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<LogoutHook> = {
|
export const handler: MutationHook<LogoutHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/logout',
|
url: '/api/commerce/logout',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
useHook: ({ fetch }) => () => {
|
useHook: ({ fetch }) => () => {
|
||||||
|
@ -9,7 +9,7 @@ export default useSignup as UseSignup<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<SignupHook> = {
|
export const handler: MutationHook<SignupHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/signup',
|
url: '/api/commerce/signup',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
|
@ -9,7 +9,7 @@ export default useAddItem as UseAddItem<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<AddItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({ input: item, options, fetch }) {
|
async fetcher({ input: item, options, fetch }) {
|
||||||
@ -29,16 +29,18 @@ export const handler: MutationHook<AddItemHook> = {
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
useHook: ({ fetch }) => () => {
|
useHook:
|
||||||
const { mutate } = useCart()
|
({ fetch }) =>
|
||||||
|
() => {
|
||||||
|
const { mutate } = useCart()
|
||||||
|
|
||||||
return useCallback(
|
return useCallback(
|
||||||
async function addItem(input) {
|
async function addItem(input) {
|
||||||
const data = await fetch({ input })
|
const data = await fetch({ input })
|
||||||
await mutate(data, false)
|
await mutate(data, false)
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
[fetch, mutate]
|
[fetch, mutate]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -7,27 +7,29 @@ export default useCart as UseCart<typeof handler>
|
|||||||
export const handler: SWRHook<any> = {
|
export const handler: SWRHook<any> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
},
|
},
|
||||||
async fetcher({ options, fetch }) {
|
async fetcher({ options, fetch }) {
|
||||||
return await fetch({ ...options })
|
return await fetch({ ...options })
|
||||||
},
|
},
|
||||||
useHook: ({ useData }) => (input) => {
|
useHook:
|
||||||
const response = useData({
|
({ useData }) =>
|
||||||
swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
|
(input) => {
|
||||||
})
|
const response = useData({
|
||||||
|
swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
|
||||||
|
})
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() =>
|
() =>
|
||||||
Object.create(response, {
|
Object.create(response, {
|
||||||
isEmpty: {
|
isEmpty: {
|
||||||
get() {
|
get() {
|
||||||
return (response.data?.lineItems.length ?? 0) <= 0
|
return (response.data?.lineItems.length ?? 0) <= 0
|
||||||
|
},
|
||||||
|
enumerable: true,
|
||||||
},
|
},
|
||||||
enumerable: true,
|
}),
|
||||||
},
|
[response]
|
||||||
}),
|
)
|
||||||
[response]
|
},
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,14 @@ 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 useRemoveItem, { UseRemoveItem } from '@vercel/commerce/cart/use-remove-item'
|
import useRemoveItem, {
|
||||||
import type { Cart, LineItem, RemoveItemHook } from '@vercel/commerce/types/cart'
|
UseRemoveItem,
|
||||||
|
} from '@vercel/commerce/cart/use-remove-item'
|
||||||
|
import type {
|
||||||
|
Cart,
|
||||||
|
LineItem,
|
||||||
|
RemoveItemHook,
|
||||||
|
} from '@vercel/commerce/types/cart'
|
||||||
import useCart from './use-cart'
|
import useCart from './use-cart'
|
||||||
|
|
||||||
export type RemoveItemFn<T = any> = T extends LineItem
|
export type RemoveItemFn<T = any> = T extends LineItem
|
||||||
@ -20,7 +26,7 @@ export default useRemoveItem as UseRemoveItem<typeof handler>
|
|||||||
|
|
||||||
export const handler = {
|
export const handler = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
@ -30,27 +36,25 @@ export const handler = {
|
|||||||
}: HookFetcherContext<RemoveItemHook>) {
|
}: HookFetcherContext<RemoveItemHook>) {
|
||||||
return await fetch({ ...options, body: { itemId } })
|
return await fetch({ ...options, body: { itemId } })
|
||||||
},
|
},
|
||||||
useHook: ({ fetch }: MutationHookContext<RemoveItemHook>) => <
|
useHook:
|
||||||
T extends LineItem | undefined = undefined
|
({ fetch }: MutationHookContext<RemoveItemHook>) =>
|
||||||
>(
|
<T extends LineItem | undefined = undefined>(ctx: { item?: T } = {}) => {
|
||||||
ctx: { item?: T } = {}
|
const { item } = ctx
|
||||||
) => {
|
const { mutate } = useCart()
|
||||||
const { item } = ctx
|
const removeItem: RemoveItemFn<LineItem> = async (input) => {
|
||||||
const { mutate } = useCart()
|
const itemId = input?.id ?? item?.id
|
||||||
const removeItem: RemoveItemFn<LineItem> = async (input) => {
|
|
||||||
const itemId = input?.id ?? item?.id
|
|
||||||
|
|
||||||
if (!itemId) {
|
if (!itemId) {
|
||||||
throw new ValidationError({
|
throw new ValidationError({
|
||||||
message: 'Invalid input used for this operation',
|
message: 'Invalid input used for this operation',
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await fetch({ input: { itemId } })
|
||||||
|
await mutate(data, false)
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetch({ input: { itemId } })
|
return useCallback(removeItem as RemoveItemFn<T>, [fetch, mutate])
|
||||||
await mutate(data, false)
|
},
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
return useCallback(removeItem as RemoveItemFn<T>, [fetch, mutate])
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
@ -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'
|
||||||
@ -18,7 +20,7 @@ export default useUpdateItem as UseUpdateItem<typeof handler>
|
|||||||
|
|
||||||
export const handler = {
|
export const handler = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
@ -46,39 +48,39 @@ export const handler = {
|
|||||||
body: { itemId, item },
|
body: { itemId, item },
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
useHook: ({ fetch }: MutationHookContext<UpdateItemHook>) => <
|
useHook:
|
||||||
T extends LineItem | undefined = undefined
|
({ fetch }: MutationHookContext<UpdateItemHook>) =>
|
||||||
>(
|
<T extends LineItem | undefined = undefined>(
|
||||||
ctx: {
|
ctx: {
|
||||||
item?: T
|
item?: T
|
||||||
wait?: number
|
wait?: number
|
||||||
} = {}
|
} = {}
|
||||||
) => {
|
) => {
|
||||||
const { item } = ctx
|
const { item } = ctx
|
||||||
const { mutate } = useCart() as any
|
const { mutate } = useCart() as any
|
||||||
|
|
||||||
return useCallback(
|
return useCallback(
|
||||||
debounce(async (input: UpdateItemActionInput<T>) => {
|
debounce(async (input: UpdateItemActionInput<T>) => {
|
||||||
const itemId = input.id ?? item?.id
|
const itemId = input.id ?? item?.id
|
||||||
const productId = input.productId ?? item?.productId
|
const productId = input.productId ?? item?.productId
|
||||||
const variantId = input.productId ?? item?.variantId
|
const variantId = input.productId ?? item?.variantId
|
||||||
|
|
||||||
if (!itemId || !productId || !variantId) {
|
if (!itemId || !productId || !variantId) {
|
||||||
throw new ValidationError({
|
throw new ValidationError({
|
||||||
message: 'Invalid input used for this operation',
|
message: 'Invalid input used for this operation',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await fetch({
|
||||||
|
input: {
|
||||||
|
itemId,
|
||||||
|
item: { productId, variantId, quantity: input.quantity },
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
await mutate(data, false)
|
||||||
|
return data
|
||||||
const data = await fetch({
|
}, ctx.wait ?? 500),
|
||||||
input: {
|
[fetch, mutate]
|
||||||
itemId,
|
)
|
||||||
item: { productId, variantId, quantity: input.quantity },
|
},
|
||||||
},
|
|
||||||
})
|
|
||||||
await mutate(data, false)
|
|
||||||
return data
|
|
||||||
}, ctx.wait ?? 500),
|
|
||||||
[fetch, mutate]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ export default useCustomer as UseCustomer<typeof handler>
|
|||||||
|
|
||||||
export const handler: SWRHook<CustomerHook> = {
|
export const handler: SWRHook<CustomerHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer',
|
url: '/api/commerce/customer',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
async fetcher({ options, fetch }) {
|
async fetcher({ options, fetch }) {
|
||||||
|
@ -5,7 +5,7 @@ export default useSearch as UseSearch<typeof handler>
|
|||||||
export const handler: SWRHook<any> = {
|
export const handler: SWRHook<any> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/api/catalog/products',
|
url: '/api/commerce/catalog/products',
|
||||||
},
|
},
|
||||||
fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) {
|
fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) {
|
||||||
// Use a dummy base as we only care about the relative path
|
// Use a dummy base as we only care about the relative path
|
||||||
@ -23,15 +23,17 @@ export const handler: SWRHook<any> = {
|
|||||||
method: options.method,
|
method: options.method,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
useHook: ({ useData }) => (input) => {
|
useHook:
|
||||||
return useData({
|
({ useData }) =>
|
||||||
input: [
|
(input) => {
|
||||||
['search', input.search],
|
return useData({
|
||||||
['categoryId', input.categoryId],
|
input: [
|
||||||
['brandId', input.brandId],
|
['search', input.search],
|
||||||
['sort', input.sort],
|
['categoryId', input.categoryId],
|
||||||
],
|
['brandId', input.brandId],
|
||||||
swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
|
['sort', input.sort],
|
||||||
})
|
],
|
||||||
},
|
swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ export default useAddItem as UseAddItem<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<AddItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/wishlist',
|
url: '/api/commerce/wishlist',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
useHook:
|
useHook:
|
||||||
|
@ -12,7 +12,7 @@ export default useRemoveItem as UseRemoveItem<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<RemoveItemHook> = {
|
export const handler: MutationHook<RemoveItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/wishlist',
|
url: '/api/commerce/wishlist',
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
},
|
},
|
||||||
useHook:
|
useHook:
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { SWRHook } from '@vercel/commerce/utils/types'
|
import { SWRHook } from '@vercel/commerce/utils/types'
|
||||||
import useWishlist, { UseWishlist } from '@vercel/commerce/wishlist/use-wishlist'
|
import useWishlist, {
|
||||||
|
UseWishlist,
|
||||||
|
} from '@vercel/commerce/wishlist/use-wishlist'
|
||||||
import type { GetWishlistHook } from '@vercel/commerce/types/wishlist'
|
import type { GetWishlistHook } from '@vercel/commerce/types/wishlist'
|
||||||
import useCustomer from '../customer/use-customer'
|
import useCustomer from '../customer/use-customer'
|
||||||
|
|
||||||
@ -8,45 +10,47 @@ export default useWishlist as UseWishlist<typeof handler>
|
|||||||
|
|
||||||
export const handler: SWRHook<any> = {
|
export const handler: SWRHook<any> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/wishlist',
|
url: '/api/commerce/wishlist',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
fetcher({ input: { customerId, includeProducts}, options, fetch }) {
|
fetcher({ input: { customerId, includeProducts }, options, fetch }) {
|
||||||
if (!customerId) return null
|
if (!customerId) return null
|
||||||
// Use a dummy base as we only care about the relative path
|
// Use a dummy base as we only care about the relative path
|
||||||
const url = new URL(options.url!, 'http://a')
|
const url = new URL(options.url!, 'http://a')
|
||||||
|
|
||||||
if (includeProducts) url.searchParams.set('products', '1')
|
if (includeProducts) url.searchParams.set('products', '1')
|
||||||
if(customerId) url.searchParams.set('customerId', customerId)
|
if (customerId) url.searchParams.set('customerId', customerId)
|
||||||
|
|
||||||
return fetch({
|
return fetch({
|
||||||
url: url.pathname + url.search,
|
url: url.pathname + url.search,
|
||||||
method: options.method,
|
method: options.method,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
useHook: ({ useData }) => (input) => {
|
useHook:
|
||||||
const { data: customer } = useCustomer()
|
({ useData }) =>
|
||||||
const response = useData({
|
(input) => {
|
||||||
input: [
|
const { data: customer } = useCustomer()
|
||||||
['customerId', customer?.id],
|
const response = useData({
|
||||||
['includeProducts', input?.includeProducts],
|
input: [
|
||||||
],
|
['customerId', customer?.id],
|
||||||
swrOptions: {
|
['includeProducts', input?.includeProducts],
|
||||||
revalidateOnFocus: false,
|
],
|
||||||
...input?.swrOptions,
|
swrOptions: {
|
||||||
},
|
revalidateOnFocus: false,
|
||||||
})
|
...input?.swrOptions,
|
||||||
return useMemo(
|
},
|
||||||
() =>
|
})
|
||||||
Object.create(response, {
|
return useMemo(
|
||||||
isEmpty: {
|
() =>
|
||||||
get() {
|
Object.create(response, {
|
||||||
return (response.data?.items?.length || 0) <= 0
|
isEmpty: {
|
||||||
|
get() {
|
||||||
|
return (response.data?.items?.length || 0) <= 0
|
||||||
|
},
|
||||||
|
enumerable: true,
|
||||||
},
|
},
|
||||||
enumerable: true,
|
}),
|
||||||
},
|
[response]
|
||||||
}),
|
)
|
||||||
[response]
|
},
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -11,14 +11,6 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
|
|||||||
body: { cartId, item },
|
body: { cartId, item },
|
||||||
config: { restBuyerFetch, cartCookie, tokenCookie },
|
config: { restBuyerFetch, cartCookie, tokenCookie },
|
||||||
}) => {
|
}) => {
|
||||||
// Return an error if no item is present
|
|
||||||
if (!item) {
|
|
||||||
return res.status(400).json({
|
|
||||||
data: null,
|
|
||||||
errors: [{ message: 'Missing item' }],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store token
|
// Store token
|
||||||
let token
|
let token
|
||||||
|
|
||||||
@ -46,7 +38,7 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
|
|||||||
path: '/',
|
path: '/',
|
||||||
sameSite: 'lax',
|
sameSite: 'lax',
|
||||||
}),
|
}),
|
||||||
serialize(cartCookie, cartId, {
|
serialize(cartCookie, cartId!, {
|
||||||
maxAge: 60 * 60 * 24 * 30,
|
maxAge: 60 * 60 * 24 * 30,
|
||||||
expires: new Date(Date.now() + 60 * 60 * 24 * 30 * 1000),
|
expires: new Date(Date.now() + 60 * 60 * 24 * 30 * 1000),
|
||||||
secure: process.env.NODE_ENV === 'production',
|
secure: process.env.NODE_ENV === 'production',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { CartSchema } from '../../../types/cart'
|
|
||||||
import type { OrdercloudAPI } from '../..'
|
import type { OrdercloudAPI } from '../..'
|
||||||
|
import type { CartSchema } from '@vercel/commerce/types/cart'
|
||||||
|
|
||||||
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
|
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
|
||||||
import cartEndpoint from '@vercel/commerce/api/endpoints/cart'
|
import cartEndpoint from '@vercel/commerce/api/endpoints/cart'
|
||||||
@ -9,9 +9,8 @@ import addItem from './add-item'
|
|||||||
import updateItem from './update-item'
|
import updateItem from './update-item'
|
||||||
import removeItem from './remove-item'
|
import removeItem from './remove-item'
|
||||||
|
|
||||||
export type CartAPI = GetAPISchema<OrdercloudAPI, CartSchema>
|
|
||||||
|
|
||||||
export type CartEndpoint = CartAPI['endpoint']
|
export type CartEndpoint = CartAPI['endpoint']
|
||||||
|
export type CartAPI = GetAPISchema<OrdercloudAPI, CartSchema>
|
||||||
|
|
||||||
export const handlers: CartEndpoint['handlers'] = {
|
export const handlers: CartEndpoint['handlers'] = {
|
||||||
getCart,
|
getCart,
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
22
packages/ordercloud/src/api/endpoints/index.ts
Normal file
22
packages/ordercloud/src/api/endpoints/index.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import type { OrdercloudAPI } from '..'
|
||||||
|
|
||||||
|
import handleEndpoints from '@vercel/commerce/api/endpoints'
|
||||||
|
|
||||||
|
import cart from './cart'
|
||||||
|
import checkout from './checkout'
|
||||||
|
import products from './catalog/products'
|
||||||
|
import customerCard from './customer/card'
|
||||||
|
import customerAddress from './customer/address'
|
||||||
|
|
||||||
|
const endpoints = {
|
||||||
|
cart,
|
||||||
|
checkout,
|
||||||
|
'customer/card': customerCard,
|
||||||
|
'customer/address': customerAddress,
|
||||||
|
'catalog/products': products,
|
||||||
|
}
|
||||||
|
|
||||||
|
const handler = (commerce: OrdercloudAPI) =>
|
||||||
|
handleEndpoints(commerce, endpoints)
|
||||||
|
|
||||||
|
export default handler
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function noopApi(...args: any[]): void {}
|
|
@ -10,7 +10,7 @@ export default useAddItem as UseAddItem<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<AddItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({ input: item, options, fetch }) {
|
async fetcher({ input: item, options, fetch }) {
|
||||||
|
@ -8,7 +8,7 @@ export default useCart as UseCart<typeof handler>
|
|||||||
|
|
||||||
export const handler: SWRHook<GetCartHook> = {
|
export const handler: SWRHook<GetCartHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
useHook: ({ useData }) =>
|
useHook: ({ useData }) =>
|
||||||
|
@ -2,12 +2,18 @@ import type {
|
|||||||
MutationHookContext,
|
MutationHookContext,
|
||||||
HookFetcherContext,
|
HookFetcherContext,
|
||||||
} from '@vercel/commerce/utils/types'
|
} from '@vercel/commerce/utils/types'
|
||||||
import type { Cart, LineItem, RemoveItemHook } from '@vercel/commerce/types/cart'
|
import type {
|
||||||
|
Cart,
|
||||||
|
LineItem,
|
||||||
|
RemoveItemHook,
|
||||||
|
} from '@vercel/commerce/types/cart'
|
||||||
|
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
import { ValidationError } from '@vercel/commerce/utils/errors'
|
import { ValidationError } from '@vercel/commerce/utils/errors'
|
||||||
import useRemoveItem, { UseRemoveItem } from '@vercel/commerce/cart/use-remove-item'
|
import useRemoveItem, {
|
||||||
|
UseRemoveItem,
|
||||||
|
} from '@vercel/commerce/cart/use-remove-item'
|
||||||
|
|
||||||
import useCart from './use-cart'
|
import useCart from './use-cart'
|
||||||
|
|
||||||
@ -23,7 +29,7 @@ export default useRemoveItem as UseRemoveItem<typeof handler>
|
|||||||
|
|
||||||
export const handler = {
|
export const handler = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
|
@ -9,7 +9,9 @@ import debounce from 'lodash.debounce'
|
|||||||
|
|
||||||
import { MutationHook } from '@vercel/commerce/utils/types'
|
import { MutationHook } 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 { 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'
|
||||||
@ -22,7 +24,7 @@ export default useUpdateItem as UseUpdateItem<any>
|
|||||||
|
|
||||||
export const handler: MutationHook<any> = {
|
export const handler: MutationHook<any> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/commerce/cart',
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
|
@ -9,7 +9,7 @@ export default useCheckout as UseCheckout<typeof handler>
|
|||||||
|
|
||||||
export const handler: SWRHook<GetCheckoutHook> = {
|
export const handler: SWRHook<GetCheckoutHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/checkout',
|
url: '/api/commerce/checkout',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
useHook: ({ useData }) =>
|
useHook: ({ useData }) =>
|
||||||
|
@ -10,7 +10,7 @@ export default useSubmitCheckout as UseSubmitCheckout<typeof handler>
|
|||||||
|
|
||||||
export const handler: MutationHook<SubmitCheckoutHook> = {
|
export const handler: MutationHook<SubmitCheckoutHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/checkout',
|
url: '/api/commerce/checkout',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({ input: item, options, fetch }) {
|
async fetcher({ input: item, options, fetch }) {
|
||||||
|
@ -2,14 +2,16 @@ import type { AddItemHook } from '@vercel/commerce/types/customer/address'
|
|||||||
import type { MutationHook } from '@vercel/commerce/utils/types'
|
import type { MutationHook } from '@vercel/commerce/utils/types'
|
||||||
|
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/address/use-add-item'
|
import useAddItem, {
|
||||||
|
UseAddItem,
|
||||||
|
} from '@vercel/commerce/customer/address/use-add-item'
|
||||||
import useAddresses from './use-addresses'
|
import useAddresses from './use-addresses'
|
||||||
|
|
||||||
export default useAddItem as UseAddItem<typeof handler>
|
export default useAddItem as UseAddItem<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<AddItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer/address',
|
url: '/api/commerce/customer/address',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({ input: item, options, fetch }) {
|
async fetcher({ input: item, options, fetch }) {
|
||||||
|
@ -10,7 +10,7 @@ export default useAddresses as UseAddresses<typeof handler>
|
|||||||
|
|
||||||
export const handler: SWRHook<GetAddressesHook> = {
|
export const handler: SWRHook<GetAddressesHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer/address',
|
url: '/api/commerce/customer/address',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
useHook: ({ useData }) =>
|
useHook: ({ useData }) =>
|
||||||
|
@ -2,7 +2,10 @@ import type {
|
|||||||
MutationHookContext,
|
MutationHookContext,
|
||||||
HookFetcherContext,
|
HookFetcherContext,
|
||||||
} from '@vercel/commerce/utils/types'
|
} from '@vercel/commerce/utils/types'
|
||||||
import type { Address, RemoveItemHook } from '@vercel/commerce/types/customer/address'
|
import type {
|
||||||
|
Address,
|
||||||
|
RemoveItemHook,
|
||||||
|
} from '@vercel/commerce/types/customer/address'
|
||||||
|
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
@ -25,7 +28,7 @@ export default useRemoveItem as UseRemoveItem<typeof handler>
|
|||||||
|
|
||||||
export const handler = {
|
export const handler = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer/address',
|
url: '/api/commerce/customer/address',
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
|
@ -2,7 +2,10 @@ import type {
|
|||||||
HookFetcherContext,
|
HookFetcherContext,
|
||||||
MutationHookContext,
|
MutationHookContext,
|
||||||
} from '@vercel/commerce/utils/types'
|
} from '@vercel/commerce/utils/types'
|
||||||
import type { UpdateItemHook, Address } from '@vercel/commerce/types/customer/address'
|
import type {
|
||||||
|
UpdateItemHook,
|
||||||
|
Address,
|
||||||
|
} from '@vercel/commerce/types/customer/address'
|
||||||
|
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
@ -21,7 +24,7 @@ export default useUpdateItem as UseUpdateItem<any>
|
|||||||
|
|
||||||
export const handler: MutationHook<any> = {
|
export const handler: MutationHook<any> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer/address',
|
url: '/api/commerce/customer/address',
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
|
@ -2,14 +2,16 @@ import type { AddItemHook } from '@vercel/commerce/types/customer/card'
|
|||||||
import type { MutationHook } from '@vercel/commerce/utils/types'
|
import type { MutationHook } from '@vercel/commerce/utils/types'
|
||||||
|
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/card/use-add-item'
|
import useAddItem, {
|
||||||
|
UseAddItem,
|
||||||
|
} from '@vercel/commerce/customer/card/use-add-item'
|
||||||
import useCards from './use-cards'
|
import useCards from './use-cards'
|
||||||
|
|
||||||
export default useAddItem as UseAddItem<typeof handler>
|
export default useAddItem as UseAddItem<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<AddItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer/card',
|
url: '/api/commerce/customer/card',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
},
|
},
|
||||||
async fetcher({ input: item, options, fetch }) {
|
async fetcher({ input: item, options, fetch }) {
|
||||||
|
@ -8,7 +8,7 @@ export default useCard as UseCards<typeof handler>
|
|||||||
|
|
||||||
export const handler: SWRHook<GetCardsHook> = {
|
export const handler: SWRHook<GetCardsHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer/card',
|
url: '/api/commerce/customer/card',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
useHook: ({ useData }) =>
|
useHook: ({ useData }) =>
|
||||||
|
@ -25,7 +25,7 @@ export default useRemoveItem as UseRemoveItem<typeof handler>
|
|||||||
|
|
||||||
export const handler = {
|
export const handler = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer/card',
|
url: '/api/commerce/customer/card',
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
|
@ -21,7 +21,7 @@ export default useUpdateItem as UseUpdateItem<any>
|
|||||||
|
|
||||||
export const handler: MutationHook<any> = {
|
export const handler: MutationHook<any> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer/card',
|
url: '/api/commerce/customer/card',
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
},
|
},
|
||||||
async fetcher({
|
async fetcher({
|
||||||
|
@ -5,7 +5,7 @@ export default useSearch as UseSearch<typeof handler>
|
|||||||
|
|
||||||
export const handler: SWRHook<SearchProductsHook> = {
|
export const handler: SWRHook<SearchProductsHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/catalog/products',
|
url: '/api/commerce/catalog/products',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) {
|
fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) {
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export default function (_commerce: any) {}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user