From 7021789621c4b82615cdd8f63929ac50a38bc586 Mon Sep 17 00:00:00 2001 From: Victor Gerbrands Date: Tue, 2 May 2023 15:41:48 +0200 Subject: [PATCH] feat: add medusa endpoints and reshapers --- lib/medusa/index.ts | 180 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 lib/medusa/index.ts diff --git a/lib/medusa/index.ts b/lib/medusa/index.ts new file mode 100644 index 000000000..cae2fc2f3 --- /dev/null +++ b/lib/medusa/index.ts @@ -0,0 +1,180 @@ +import { isShopifyError } from 'lib/type-guards'; +import { Cart, MedusaCart, MedusaProduct, Product, ProductCollection } from './types'; + +// const endpoint = `${process.env.MEDUSA_BACKEND_API!}`; +const endpoint = `http://localhost:9000/store`; + +export default async function medusaRequest( + method: string, + path = '', + payload?: Record | undefined +) { + const options: RequestInit = { + method, + headers: { + 'Content-Type': 'application/json' + } + }; + + if (payload) { + options.body = JSON.stringify(payload); + } + + try { + const result = await fetch(`${endpoint}/${path}`, options); + + const body = await result.json(); + + if (body.errors) { + throw body.errors[0]; + } + + return { + status: result.status, + body + }; + } catch (e) { + if (isShopifyError(e)) { + throw { + status: e.status || 500, + message: e.message + }; + } + + throw { + error: e + }; + } +} + +const reshapeCart = (cart: MedusaCart): Cart => { + const lines = cart.items; + const totalQuantity = cart.items.length || 0; + + return { + ...cart, + totalQuantity, + lines + }; +}; + +const reshapeProduct = (product: MedusaProduct): Product => { + const featuredImage = { + url: product.images?.[0]?.url ?? '' + }; + const priceRange = { + maxVariantPrice: { + amount: product.variants?.[0]?.prices?.[0]?.amount.toString() ?? '', + currencyCode: product.variants?.[0]?.prices?.[0]?.currency_code ?? '' + } + }; + + return { + ...product, + featuredImage, + priceRange + }; +}; + +export async function createCart(): Promise { + const res = await medusaRequest('POST', '/carts', {}); + console.log('Cart created!'); + console.log(res); + return reshapeCart(res.body.cart); +} + +export async function addToCart( + cartId: string, + lineItems: { variantId: string; quantity: number }[] +): Promise { + console.log(lineItems); + // TODO: transform lines into Medusa line items + const res = await medusaRequest('POST', `/carts/${cartId}/line-items`, { + lineItems + }); + + return res.body.data.cart; +} + +export async function removeFromCart(cartId: string, lineIds: string[]): Promise { + // TODO: We only allow you to pass a single line item to delete + const res = await medusaRequest('DELETE', `/carts/${cartId}/line-items/${lineIds[0]}`); + + return res.body.data.cart; +} + +export async function updateCart( + cartId: string, + lines: { id: string; merchandiseId: string; quantity: number }[] +): Promise { + console.log(lines); + // TODO: transform lines into Medusa line items + const res = await medusaRequest('POST', `/carts/${cartId}`, {}); + return res.body.data.cart; +} + +export async function getCart(cartId: string): Promise { + const res = await medusaRequest('GET', `/carts/${cartId}`); + + if (!res.body.cart) { + return null; + } + + return res.body.cart; +} + +export async function getCollection(handle: string): Promise { + const res = await medusaRequest('GET', `/collections?handle[]=${handle}&limit=1`); + return res.body.collections[0]; +} + +export async function getCollectionProducts(handle: string): Promise { + const collection = await getCollection(handle); + + if (!collection) { + return []; + } + + const res = await medusaRequest('GET', `/products?collection_id[]=${collection.id}`); + + if (!res.body?.products) { + return []; + } + + return res.body.products.map((product: Product) => reshapeProduct(product)); +} + +export async function getCollections(): Promise { + const collections = [ + { + handle: '', + title: 'All', + description: 'All products', + seo: { + title: 'All', + description: 'All products' + }, + path: '/search', + updatedAt: new Date().toISOString() + } + ]; + + // return collections; + return []; +} + +export async function getProduct(handle: string): Promise { + const res = await medusaRequest('get', `/products?handle=${handle}&limit=1`); + return res.body.product; +} + +export async function getProducts({ + query +}: { + query?: string; + reverse?: boolean; + sortKey?: string; +}): Promise { + const res = await medusaRequest('get', `/products?q=${query}&limit=20`); + return res.body.products; +}