forked from crowetic/commerce
Merge branch 'master' of github.com:okbel/e-comm-example
This commit is contained in:
commit
62f29fe766
@ -15,43 +15,87 @@ const cartApi: BigcommerceApiHandler = async (req, res, config) => {
|
||||
const { cookies } = req
|
||||
const cartId = cookies[config.cartCookie]
|
||||
|
||||
// Return current cart info
|
||||
if (req.method === 'GET') {
|
||||
let result: { data?: Cart } = {}
|
||||
try {
|
||||
// Return current cart info
|
||||
if (req.method === 'GET') {
|
||||
let result: { data?: Cart } = {}
|
||||
|
||||
try {
|
||||
result = await config.storeApiFetch(
|
||||
`/v3/carts/${cartId}?include=redirect_urls`
|
||||
)
|
||||
} catch (error) {
|
||||
if (error instanceof BigcommerceApiError && error.status === 404) {
|
||||
// Remove the cookie if it exists but the cart wasn't found
|
||||
res.setHeader('Set-Cookie', getCartCookie(name))
|
||||
} else {
|
||||
throw error
|
||||
try {
|
||||
result = await config.storeApiFetch(
|
||||
`/v3/carts/${cartId}?include=redirect_urls`
|
||||
)
|
||||
} catch (error) {
|
||||
if (error instanceof BigcommerceApiError && error.status === 404) {
|
||||
// Remove the cookie if it exists but the cart wasn't found
|
||||
res.setHeader('Set-Cookie', getCartCookie(name))
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).json({ cart: result.data ?? null })
|
||||
}
|
||||
|
||||
return res.status(200).json({ cart: result.data ?? null })
|
||||
// Create or add a product to the cart
|
||||
if (req.method === 'POST') {
|
||||
const { product } = req.body
|
||||
|
||||
if (!product) {
|
||||
return res.status(400).json({
|
||||
errors: [{ message: 'Missing product' }],
|
||||
})
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
line_items: [parseProduct(product)],
|
||||
}),
|
||||
}
|
||||
const { data } = cartId
|
||||
? await config.storeApiFetch(`/v3/carts/${cartId}/items`, options)
|
||||
: await config.storeApiFetch('/v3/carts', options)
|
||||
|
||||
// Create or update the cart cookie
|
||||
res.setHeader(
|
||||
'Set-Cookie',
|
||||
getCartCookie(name, data.id, config.cartCookieMaxAge)
|
||||
)
|
||||
|
||||
// There's no need to send any additional data here, the UI can use this response to display a
|
||||
// "success" for the operation and revalidate the GET request for this same endpoint right after.
|
||||
return res.status(200).json({ done: true })
|
||||
}
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof BigcommerceApiError
|
||||
? 'An unexpected error ocurred with the Bigcommerce API'
|
||||
: 'An unexpected error ocurred'
|
||||
|
||||
res.status(500).json({ errors: [{ message }] })
|
||||
}
|
||||
}
|
||||
|
||||
const ONE_DAY = 60 * 60 * 24
|
||||
const MAX_AGE = ONE_DAY * 30
|
||||
|
||||
function getCartCookie(name: string, cartId?: string) {
|
||||
const options: CookieSerializeOptions = cartId
|
||||
? {
|
||||
maxAge: MAX_AGE,
|
||||
expires: new Date(Date.now() + MAX_AGE * 1000),
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
path: '/',
|
||||
sameSite: 'lax',
|
||||
}
|
||||
: { maxAge: -1, path: '/' } // Removes the cookie
|
||||
function getCartCookie(name: string, cartId?: string, maxAge?: number) {
|
||||
const options: CookieSerializeOptions =
|
||||
cartId && maxAge
|
||||
? {
|
||||
maxAge,
|
||||
expires: new Date(Date.now() + maxAge * 1000),
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
path: '/',
|
||||
sameSite: 'lax',
|
||||
}
|
||||
: { maxAge: -1, path: '/' } // Removes the cookie
|
||||
|
||||
return serialize(name, cartId || '', options)
|
||||
}
|
||||
|
||||
const parseProduct = (product: any) => ({
|
||||
quantity: product.quantity,
|
||||
product_id: product.productId,
|
||||
variant_id: product.variantId,
|
||||
})
|
||||
|
||||
export default createApiHandler(cartApi)
|
||||
|
@ -103,10 +103,12 @@ export class Config {
|
||||
}
|
||||
}
|
||||
|
||||
const ONE_DAY = 60 * 60 * 24
|
||||
const config = new Config({
|
||||
commerceUrl: API_URL,
|
||||
apiToken: API_TOKEN,
|
||||
cartCookie: process.env.BIGCOMMERCE_CART_COOKIE ?? 'bc_cartId',
|
||||
cartCookieMaxAge: ONE_DAY * 30,
|
||||
fetch: fetchGraphqlApi,
|
||||
// REST API only
|
||||
storeApiUrl: STORE_API_URL,
|
||||
|
@ -1,16 +1,5 @@
|
||||
// Used for GraphQL errors
|
||||
export class BigcommerceError extends Error {
|
||||
status?: number
|
||||
|
||||
constructor(msg: string, res?: Response) {
|
||||
super(msg)
|
||||
this.name = 'BigcommerceError'
|
||||
|
||||
if (res) {
|
||||
this.status = res.status
|
||||
}
|
||||
}
|
||||
}
|
||||
export class BigcommerceGraphQLError extends Error {}
|
||||
|
||||
export class BigcommerceApiError extends Error {
|
||||
status: number
|
||||
|
@ -7,9 +7,14 @@ import {
|
||||
export type Cart = any
|
||||
|
||||
export const CartProvider: FC = ({ children }) => {
|
||||
return <CommerceCartProvider query="">{children}</CommerceCartProvider>
|
||||
return <CommerceCartProvider url="/api/cart">{children}</CommerceCartProvider>
|
||||
}
|
||||
|
||||
export function useCart() {
|
||||
return useCommerceCart<Cart>()
|
||||
const cart = useCommerceCart<Cart>()
|
||||
|
||||
// TODO: Do something to make this prop work
|
||||
cart.isEmpty = true
|
||||
|
||||
return cart
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ export interface CommerceAPIConfig {
|
||||
commerceUrl: string
|
||||
apiToken: string
|
||||
cartCookie: string
|
||||
cartCookieMaxAge: number
|
||||
fetch<Q, V = any>(
|
||||
query: string,
|
||||
queryData?: CommerceAPIFetchOptions<V>
|
||||
|
@ -21,11 +21,9 @@ const CartProvider: FC<CartProviderProps> = ({ children, query, url }) => {
|
||||
const { fetcher } = useCommerce()
|
||||
const cartId = getCartCookie()
|
||||
const response = useSWR(() => (cartId ? [url, query] : null), fetcher)
|
||||
// TODO: Do something to make this prop work
|
||||
const isEmpty = true
|
||||
|
||||
return (
|
||||
<CartContext.Provider value={{ ...response, isEmpty }}>
|
||||
<CartContext.Provider value={{ ...response, isEmpty: true }}>
|
||||
{children}
|
||||
</CartContext.Provider>
|
||||
)
|
||||
|
3
pages/api/bigcommerce/cart.ts
Normal file
3
pages/api/bigcommerce/cart.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import cartApi from '@lib/bigcommerce/api/cart'
|
||||
|
||||
export default cartApi()
|
Loading…
x
Reference in New Issue
Block a user