forked from crowetic/commerce
Added add to cart method
This commit is contained in:
parent
ec1377850e
commit
ca959f6491
@ -15,43 +15,87 @@ const cartApi: BigcommerceApiHandler = async (req, res, config) => {
|
|||||||
const { cookies } = req
|
const { cookies } = req
|
||||||
const cartId = cookies[config.cartCookie]
|
const cartId = cookies[config.cartCookie]
|
||||||
|
|
||||||
// Return current cart info
|
try {
|
||||||
if (req.method === 'GET') {
|
// Return current cart info
|
||||||
let result: { data?: Cart } = {}
|
if (req.method === 'GET') {
|
||||||
|
let result: { data?: Cart } = {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = await config.storeApiFetch(
|
result = await config.storeApiFetch(
|
||||||
`/v3/carts/${cartId}?include=redirect_urls`
|
`/v3/carts/${cartId}?include=redirect_urls`
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof BigcommerceApiError && error.status === 404) {
|
if (error instanceof BigcommerceApiError && error.status === 404) {
|
||||||
// Remove the cookie if it exists but the cart wasn't found
|
// Remove the cookie if it exists but the cart wasn't found
|
||||||
res.setHeader('Set-Cookie', getCartCookie(name))
|
res.setHeader('Set-Cookie', getCartCookie(name))
|
||||||
} else {
|
} else {
|
||||||
throw error
|
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
|
function getCartCookie(name: string, cartId?: string, maxAge?: number) {
|
||||||
const MAX_AGE = ONE_DAY * 30
|
const options: CookieSerializeOptions =
|
||||||
|
cartId && maxAge
|
||||||
function getCartCookie(name: string, cartId?: string) {
|
? {
|
||||||
const options: CookieSerializeOptions = cartId
|
maxAge,
|
||||||
? {
|
expires: new Date(Date.now() + maxAge * 1000),
|
||||||
maxAge: MAX_AGE,
|
httpOnly: true,
|
||||||
expires: new Date(Date.now() + MAX_AGE * 1000),
|
secure: process.env.NODE_ENV === 'production',
|
||||||
httpOnly: true,
|
path: '/',
|
||||||
secure: process.env.NODE_ENV === 'production',
|
sameSite: 'lax',
|
||||||
path: '/',
|
}
|
||||||
sameSite: 'lax',
|
: { maxAge: -1, path: '/' } // Removes the cookie
|
||||||
}
|
|
||||||
: { maxAge: -1, path: '/' } // Removes the cookie
|
|
||||||
|
|
||||||
return serialize(name, cartId || '', options)
|
return serialize(name, cartId || '', options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parseProduct = (product: any) => ({
|
||||||
|
quantity: product.quantity,
|
||||||
|
product_id: product.productId,
|
||||||
|
variant_id: product.variantId,
|
||||||
|
})
|
||||||
|
|
||||||
export default createApiHandler(cartApi)
|
export default createApiHandler(cartApi)
|
||||||
|
@ -103,10 +103,12 @@ export class Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ONE_DAY = 60 * 60 * 24
|
||||||
const config = new Config({
|
const config = new Config({
|
||||||
commerceUrl: API_URL,
|
commerceUrl: API_URL,
|
||||||
apiToken: API_TOKEN,
|
apiToken: API_TOKEN,
|
||||||
cartCookie: process.env.BIGCOMMERCE_CART_COOKIE ?? 'bc_cartId',
|
cartCookie: process.env.BIGCOMMERCE_CART_COOKIE ?? 'bc_cartId',
|
||||||
|
cartCookieMaxAge: ONE_DAY * 30,
|
||||||
fetch: fetchGraphqlApi,
|
fetch: fetchGraphqlApi,
|
||||||
// REST API only
|
// REST API only
|
||||||
storeApiUrl: STORE_API_URL,
|
storeApiUrl: STORE_API_URL,
|
||||||
|
@ -1,16 +1,5 @@
|
|||||||
// Used for GraphQL errors
|
// Used for GraphQL errors
|
||||||
export class BigcommerceError extends Error {
|
export class BigcommerceGraphQLError extends Error {}
|
||||||
status?: number
|
|
||||||
|
|
||||||
constructor(msg: string, res?: Response) {
|
|
||||||
super(msg)
|
|
||||||
this.name = 'BigcommerceError'
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
this.status = res.status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BigcommerceApiError extends Error {
|
export class BigcommerceApiError extends Error {
|
||||||
status: number
|
status: number
|
||||||
|
@ -2,6 +2,7 @@ export interface CommerceAPIConfig {
|
|||||||
commerceUrl: string
|
commerceUrl: string
|
||||||
apiToken: string
|
apiToken: string
|
||||||
cartCookie: string
|
cartCookie: string
|
||||||
|
cartCookieMaxAge: number
|
||||||
fetch<Q, V = any>(
|
fetch<Q, V = any>(
|
||||||
query: string,
|
query: string,
|
||||||
queryData?: CommerceAPIFetchOptions<V>
|
queryData?: CommerceAPIFetchOptions<V>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user