mirror of
https://github.com/vercel/commerce.git
synced 2025-05-19 07:56:59 +00:00
Move API to new Node architecture
Signed-off-by: Loan Laux <loan@outgrow.io>
This commit is contained in:
parent
8dc6881cd9
commit
23e0d57cf5
@ -1,60 +0,0 @@
|
|||||||
import isAllowedMethod from '../utils/is-allowed-method'
|
|
||||||
import createApiHandler, {
|
|
||||||
ReactionCommerceApiHandler,
|
|
||||||
ReactionCommerceHandler,
|
|
||||||
} from '../utils/create-api-handler'
|
|
||||||
import { ReactionCommerceApiError } from '../utils/errors'
|
|
||||||
import getCart from './handlers/get-cart'
|
|
||||||
import addItem from './handlers/add-item'
|
|
||||||
import type {
|
|
||||||
Cart,
|
|
||||||
GetCartHandlerBody,
|
|
||||||
AddCartItemHandlerBody,
|
|
||||||
} from '../../types'
|
|
||||||
|
|
||||||
export type CartHandlers = {
|
|
||||||
getCart: ReactionCommerceHandler<Cart, GetCartHandlerBody>
|
|
||||||
addItem: ReactionCommerceHandler<Cart, AddCartItemHandlerBody>
|
|
||||||
}
|
|
||||||
|
|
||||||
const METHODS = ['GET', 'POST']
|
|
||||||
|
|
||||||
// TODO: a complete implementation should have schema validation for `req.body`
|
|
||||||
const cartApi: ReactionCommerceApiHandler<Cart, CartHandlers> = async (
|
|
||||||
req,
|
|
||||||
res,
|
|
||||||
config,
|
|
||||||
handlers
|
|
||||||
) => {
|
|
||||||
if (!isAllowedMethod(req, res, METHODS)) return
|
|
||||||
|
|
||||||
const { cookies } = req
|
|
||||||
const cartId = cookies[config.anonymousCartTokenCookie]
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Return current cart info
|
|
||||||
if (req.method === 'GET') {
|
|
||||||
const body = { cartId }
|
|
||||||
return await handlers['getCart']({ req, res, config, body })
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or add an item to the cart
|
|
||||||
if (req.method === 'POST') {
|
|
||||||
const body = { ...req.body, cartId }
|
|
||||||
return await handlers['addItem']({ req, res, config, body })
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
const message =
|
|
||||||
error instanceof ReactionCommerceApiError
|
|
||||||
? 'An unexpected error occurred with the Reaction Commerce API'
|
|
||||||
: 'An unexpected error occurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const handlers = { getCart, addItem }
|
|
||||||
|
|
||||||
export default createApiHandler(cartApi, handlers, {})
|
|
@ -1 +0,0 @@
|
|||||||
export default function () {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function () {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function () {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function () {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function () {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function () {}
|
|
@ -1 +0,0 @@
|
|||||||
export default function () {}
|
|
@ -1,4 +1,3 @@
|
|||||||
import type { CartHandlers } from '..'
|
|
||||||
import {
|
import {
|
||||||
addCartItemsMutation,
|
addCartItemsMutation,
|
||||||
createCartMutation,
|
createCartMutation,
|
||||||
@ -10,8 +9,9 @@ import {
|
|||||||
REACTION_CART_ID_COOKIE,
|
REACTION_CART_ID_COOKIE,
|
||||||
REACTION_CUSTOMER_TOKEN_COOKIE,
|
REACTION_CUSTOMER_TOKEN_COOKIE,
|
||||||
} from '@framework/const'
|
} from '@framework/const'
|
||||||
|
import type { CartEndpoint } from '.'
|
||||||
|
|
||||||
const addItem: CartHandlers['addItem'] = async ({
|
const addItem: CartEndpoint['handlers']['addItem'] = async ({
|
||||||
req: { cookies },
|
req: { cookies },
|
||||||
res,
|
res,
|
||||||
body: { item },
|
body: { item },
|
@ -1,4 +1,3 @@
|
|||||||
import type { CartHandlers } from '../'
|
|
||||||
import getAnonymousCartQuery from '@framework/utils/queries/get-anonymous-cart'
|
import getAnonymousCartQuery from '@framework/utils/queries/get-anonymous-cart'
|
||||||
import accountCartByAccountIdQuery from '@framework/utils/queries/account-cart-by-account-id'
|
import accountCartByAccountIdQuery from '@framework/utils/queries/account-cart-by-account-id'
|
||||||
import getCartCookie from '@framework/api/utils/get-cart-cookie'
|
import getCartCookie from '@framework/api/utils/get-cart-cookie'
|
||||||
@ -10,9 +9,13 @@ import {
|
|||||||
REACTION_CUSTOMER_TOKEN_COOKIE,
|
REACTION_CUSTOMER_TOKEN_COOKIE,
|
||||||
} from '@framework/const'
|
} from '@framework/const'
|
||||||
import { normalizeCart } from '@framework/utils'
|
import { normalizeCart } from '@framework/utils'
|
||||||
|
import type { CartEndpoint } from '.'
|
||||||
|
|
||||||
// Return current cart info
|
const getCart: CartEndpoint['handlers']['getCart'] = async ({
|
||||||
const getCart: CartHandlers['getCart'] = async ({ req, res, config }) => {
|
req,
|
||||||
|
res,
|
||||||
|
config,
|
||||||
|
}) => {
|
||||||
const {
|
const {
|
||||||
cookies: {
|
cookies: {
|
||||||
[REACTION_ANONYMOUS_CART_TOKEN_COOKIE]: anonymousCartToken,
|
[REACTION_ANONYMOUS_CART_TOKEN_COOKIE]: anonymousCartToken,
|
21
framework/reactioncommerce/api/endpoints/cart/index.ts
Normal file
21
framework/reactioncommerce/api/endpoints/cart/index.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { CommerceAPI, createEndpoint, GetAPISchema } from '@commerce/api'
|
||||||
|
import cartEndpoint from '@commerce/api/endpoints/cart'
|
||||||
|
import type { CartSchema } from '@commerce/types/cart'
|
||||||
|
import getCart from './get-cart'
|
||||||
|
import addItem from './add-item'
|
||||||
|
|
||||||
|
export type CartAPI = GetAPISchema<CommerceAPI, CartSchema>
|
||||||
|
|
||||||
|
export type CartEndpoint = CartAPI['endpoint']
|
||||||
|
|
||||||
|
export const handlers: CartEndpoint['handlers'] = {
|
||||||
|
getCart,
|
||||||
|
addItem,
|
||||||
|
}
|
||||||
|
|
||||||
|
const cartApi = createEndpoint<CartAPI>({
|
||||||
|
handler: cartEndpoint,
|
||||||
|
handlers,
|
||||||
|
})
|
||||||
|
|
||||||
|
export default cartApi
|
@ -0,0 +1 @@
|
|||||||
|
export default function noopApi(...args: any[]): void {}
|
@ -0,0 +1 @@
|
|||||||
|
export default function noopApi(...args: any[]): void {}
|
@ -0,0 +1 @@
|
|||||||
|
export default function noopApi(...args: any[]): void {}
|
@ -0,0 +1 @@
|
|||||||
|
export default function noopApi(...args: any[]): void {}
|
@ -0,0 +1 @@
|
|||||||
|
export default function noopApi(...args: any[]): void {}
|
@ -0,0 +1 @@
|
|||||||
|
export default function noopApi(...args: any[]): void {}
|
@ -0,0 +1 @@
|
|||||||
|
export default function noopApi(...args: any[]): void {}
|
@ -1,5 +1,8 @@
|
|||||||
import type { CommerceAPIConfig } from '@commerce/api'
|
import {
|
||||||
|
CommerceAPI,
|
||||||
|
CommerceAPIConfig,
|
||||||
|
getCommerceApi as commerceApi,
|
||||||
|
} from '@commerce/api'
|
||||||
import {
|
import {
|
||||||
API_URL,
|
API_URL,
|
||||||
REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
||||||
@ -17,6 +20,15 @@ if (!API_URL) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
import fetchGraphqlApi from './utils/fetch-graphql-api'
|
import fetchGraphqlApi from './utils/fetch-graphql-api'
|
||||||
|
import login from './operations/login'
|
||||||
|
import getAllPages from './operations/get-all-pages'
|
||||||
|
import getPage from './operations/get-page'
|
||||||
|
import getSiteInfo from './operations/get-site-info'
|
||||||
|
import getCustomerWishlist from './operations/get-customer-wishlist'
|
||||||
|
import getAllProductPaths from './operations/get-all-product-paths'
|
||||||
|
import getAllProducts from './operations/get-all-products'
|
||||||
|
import getProduct from './operations/get-product'
|
||||||
|
import type { CartAPI } from './endpoints/cart'
|
||||||
|
|
||||||
export interface ReactionCommerceConfig
|
export interface ReactionCommerceConfig
|
||||||
extends Omit<CommerceAPIConfig, 'apiToken'> {
|
extends Omit<CommerceAPIConfig, 'apiToken'> {
|
||||||
@ -27,26 +39,7 @@ export interface ReactionCommerceConfig
|
|||||||
anonymousCartTokenCookieMaxAge?: number
|
anonymousCartTokenCookieMaxAge?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Config {
|
const config: ReactionCommerceConfig = {
|
||||||
private config: ReactionCommerceConfig
|
|
||||||
|
|
||||||
constructor(config: ReactionCommerceConfig) {
|
|
||||||
this.config = config
|
|
||||||
}
|
|
||||||
|
|
||||||
getConfig(userConfig: Partial<ReactionCommerceConfig> = {}) {
|
|
||||||
return Object.entries(userConfig).reduce<ReactionCommerceConfig>(
|
|
||||||
(cfg, [key, value]) => Object.assign(cfg, { [key]: value }),
|
|
||||||
{ ...this.config }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
setConfig(newConfig: Partial<ReactionCommerceConfig>) {
|
|
||||||
Object.assign(this.config, newConfig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = new Config({
|
|
||||||
locale: 'en-US',
|
locale: 'en-US',
|
||||||
commerceUrl: API_URL,
|
commerceUrl: API_URL,
|
||||||
cartCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
cartCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
||||||
@ -58,12 +51,29 @@ const config = new Config({
|
|||||||
fetch: fetchGraphqlApi,
|
fetch: fetchGraphqlApi,
|
||||||
customerCookie: REACTION_CUSTOMER_TOKEN_COOKIE,
|
customerCookie: REACTION_CUSTOMER_TOKEN_COOKIE,
|
||||||
shopId: SHOP_ID,
|
shopId: SHOP_ID,
|
||||||
})
|
|
||||||
|
|
||||||
export function getConfig(userConfig?: Partial<ReactionCommerceConfig>) {
|
|
||||||
return config.getConfig(userConfig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setConfig(newConfig: Partial<ReactionCommerceConfig>) {
|
const operations = {
|
||||||
return config.setConfig(newConfig)
|
login,
|
||||||
|
getAllPages,
|
||||||
|
getPage,
|
||||||
|
getSiteInfo,
|
||||||
|
getCustomerWishlist,
|
||||||
|
getAllProductPaths,
|
||||||
|
getAllProducts,
|
||||||
|
getProduct,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const provider = { config, operations }
|
||||||
|
|
||||||
|
export type Provider = typeof provider
|
||||||
|
|
||||||
|
export type APIs = CartAPI
|
||||||
|
|
||||||
|
export type ReactionCommerceAPI<P extends Provider = Provider> = CommerceAPI<P>
|
||||||
|
|
||||||
|
export function getCommerceApi<P extends Provider>(
|
||||||
|
customProvider: P = provider as any
|
||||||
|
): ReactionCommerceAPI<P> {
|
||||||
|
return commerceApi(customProvider)
|
||||||
}
|
}
|
||||||
|
40
framework/reactioncommerce/api/operations/get-all-pages.ts
Normal file
40
framework/reactioncommerce/api/operations/get-all-pages.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { ReactionCommerceConfig } from '../'
|
||||||
|
import { OperationContext } from '@commerce/api/operations'
|
||||||
|
import { Provider } from '@commerce'
|
||||||
|
|
||||||
|
export type Page = any
|
||||||
|
|
||||||
|
export type GetAllPagesResult<T extends { pages: any[] } = { pages: Page[] }> =
|
||||||
|
T
|
||||||
|
|
||||||
|
export default function getAllPagesOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getAllPages(opts?: {
|
||||||
|
config?: Partial<ReactionCommerceConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<GetAllPagesResult>
|
||||||
|
|
||||||
|
async function getAllPages<T extends { pages: any[] }>(opts: {
|
||||||
|
url: string
|
||||||
|
config?: Partial<ReactionCommerceConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<GetAllPagesResult<T>>
|
||||||
|
|
||||||
|
async function getAllPages({
|
||||||
|
config: cfg,
|
||||||
|
preview,
|
||||||
|
}: {
|
||||||
|
url?: string
|
||||||
|
config?: Partial<ReactionCommerceConfig>
|
||||||
|
preview?: boolean
|
||||||
|
} = {}): Promise<GetAllPagesResult> {
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
|
||||||
|
return {
|
||||||
|
pages: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAllPages
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
import { OperationContext, OperationOptions } from '@commerce/api/operations'
|
||||||
|
import type { CatalogItem } from '../../schema'
|
||||||
|
import { Provider } from '../index'
|
||||||
|
import getAllProductsPathsQuery from '../../utils/queries/get-all-products-paths-query'
|
||||||
|
import { GetAllProductPathsOperation } from '@commerce/types/product'
|
||||||
|
import { ReactionCommerceConfig } from '..'
|
||||||
|
|
||||||
|
export type GetAllProductPathsResult = {
|
||||||
|
products: Array<{ node: { path: string } }>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getAllProductPathsOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getAllProductPaths<
|
||||||
|
T extends GetAllProductPathsOperation
|
||||||
|
>(opts?: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: ReactionCommerceConfig
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
async function getAllProductPaths<T extends GetAllProductPathsOperation>(
|
||||||
|
opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: ReactionCommerceConfig
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
|
||||||
|
async function getAllProductPaths<T extends GetAllProductPathsOperation>({
|
||||||
|
query = getAllProductsPathsQuery,
|
||||||
|
variables,
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: ReactionCommerceConfig
|
||||||
|
} = {}): Promise<T['data']> {
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
// RecursivePartial forces the method to check for every prop in the data, which is
|
||||||
|
// required in case there's a custom `query`
|
||||||
|
const { data } = await config.fetch<CatalogItem>(query, {
|
||||||
|
variables,
|
||||||
|
})
|
||||||
|
const products = data.products.items
|
||||||
|
|
||||||
|
return {
|
||||||
|
products: products.map((p) => ({ path: `/${p.slug}` })),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAllProductPaths
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
import { Product } from '@commerce/types/product'
|
||||||
|
import { OperationContext } from '@commerce/api/operations'
|
||||||
|
import { normalizeProduct } from '@framework/utils'
|
||||||
|
import catalogItemsQuery from '../../utils/queries/catalog-items-query'
|
||||||
|
import { CatalogItemConnection } from '../../schema'
|
||||||
|
import { Provider, ReactionCommerceConfig } from '..'
|
||||||
|
|
||||||
|
export type ProductVariables = {
|
||||||
|
first?: number
|
||||||
|
shopIds?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getAllProductsOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getAllProducts(opts?: {
|
||||||
|
variables?: ProductVariables
|
||||||
|
config?: Partial<ReactionCommerceConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<{ products: Product[] }>
|
||||||
|
|
||||||
|
async function getAllProducts({
|
||||||
|
query = catalogItemsQuery,
|
||||||
|
variables: { ...vars } = { first: 250 },
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables?: ProductVariables
|
||||||
|
config?: Partial<ReactionCommerceConfig>
|
||||||
|
preview?: boolean
|
||||||
|
} = {}): Promise<{ products: Product[] | any[] }> {
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
const { data } = await config.fetch<CatalogItemConnection>(query, {
|
||||||
|
variables: {
|
||||||
|
...vars,
|
||||||
|
shopIds: [config.shopId],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
products:
|
||||||
|
data.catalogItems?.edges?.map((item) => normalizeProduct(item?.node)) ||
|
||||||
|
[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAllProducts
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import { OperationContext } from '@commerce/api/operations'
|
||||||
|
import { Provider, VendureConfig } from '../'
|
||||||
|
|
||||||
|
export default function getCustomerWishlistOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getCustomerWishlist({
|
||||||
|
config: cfg,
|
||||||
|
variables,
|
||||||
|
includeProducts,
|
||||||
|
}: {
|
||||||
|
url?: string
|
||||||
|
variables: any
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
includeProducts?: boolean
|
||||||
|
}): Promise<any> {
|
||||||
|
// Not implemented as Vendure does not ship with wishlist functionality at present
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
return { wishlist: {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
return getCustomerWishlist
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import { Page } from '../../schema'
|
import { OperationContext } from '@commerce/api/operations'
|
||||||
import { ReactionCommerceConfig, getConfig } from '..'
|
import { Page } from '../../common/get-all-pages'
|
||||||
|
import { ReactionCommerceConfig, Provider } from '..'
|
||||||
|
|
||||||
export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
|
export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
|
||||||
|
|
||||||
@ -7,19 +8,37 @@ export type PageVariables = {
|
|||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getPage({
|
export default function getPageOperation({
|
||||||
url,
|
commerce,
|
||||||
variables,
|
}: OperationContext<Provider>) {
|
||||||
config,
|
async function getPage(opts: {
|
||||||
preview,
|
|
||||||
}: {
|
|
||||||
url?: string
|
url?: string
|
||||||
variables: PageVariables
|
variables: PageVariables
|
||||||
config?: ReactionCommerceConfig
|
config?: ReactionCommerceConfig
|
||||||
preview?: boolean
|
preview?: boolean
|
||||||
}): Promise<GetPageResult> {
|
}): Promise<GetPageResult>
|
||||||
config = getConfig(config)
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getPage
|
async function getPage<T extends { page?: any }, V = any>(opts: {
|
||||||
|
url: string
|
||||||
|
variables: V
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<GetPageResult<T>>
|
||||||
|
|
||||||
|
async function getPage({
|
||||||
|
url,
|
||||||
|
variables,
|
||||||
|
config: cfg,
|
||||||
|
preview,
|
||||||
|
}: {
|
||||||
|
url?: string
|
||||||
|
variables: PageVariables
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<GetPageResult> {
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getPage
|
||||||
|
}
|
||||||
|
69
framework/reactioncommerce/api/operations/get-product.ts
Normal file
69
framework/reactioncommerce/api/operations/get-product.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { Product } from '@commerce/types/product'
|
||||||
|
import { OperationContext } from '@commerce/api/operations'
|
||||||
|
import { Provider, VendureConfig } from '../'
|
||||||
|
import { GetProductQuery } from '../../schema'
|
||||||
|
import { getProductQuery } from '../../utils/queries/get-product-query'
|
||||||
|
|
||||||
|
export default function getProductOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getProduct({
|
||||||
|
query = getProductQuery,
|
||||||
|
variables,
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables: { slug: string }
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<Product | {} | any> {
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
|
||||||
|
const locale = config.locale
|
||||||
|
const { data } = await config.fetch<GetProductQuery>(query, { variables })
|
||||||
|
const product = data.product
|
||||||
|
|
||||||
|
if (product) {
|
||||||
|
const getOptionGroupName = (id: string): string => {
|
||||||
|
return product.optionGroups.find((og) => og.id === id)!.name
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
product: {
|
||||||
|
id: product.id,
|
||||||
|
name: product.name,
|
||||||
|
description: product.description,
|
||||||
|
slug: product.slug,
|
||||||
|
images: product.assets.map((a) => ({
|
||||||
|
url: a.preview,
|
||||||
|
alt: a.name,
|
||||||
|
})),
|
||||||
|
variants: product.variants.map((v) => ({
|
||||||
|
id: v.id,
|
||||||
|
options: v.options.map((o) => ({
|
||||||
|
// This __typename property is required in order for the correct
|
||||||
|
// variant selection to work, see `components/product/helpers.ts`
|
||||||
|
// `getVariant()` function.
|
||||||
|
__typename: 'MultipleChoiceOption',
|
||||||
|
id: o.id,
|
||||||
|
displayName: getOptionGroupName(o.groupId),
|
||||||
|
values: [{ label: o.name }],
|
||||||
|
})),
|
||||||
|
})),
|
||||||
|
price: {
|
||||||
|
value: product.variants[0].priceWithTax / 100,
|
||||||
|
currencyCode: product.variants[0].currencyCode,
|
||||||
|
},
|
||||||
|
options: product.optionGroups.map((og) => ({
|
||||||
|
id: og.id,
|
||||||
|
displayName: og.name,
|
||||||
|
values: og.options.map((o) => ({ label: o.name })),
|
||||||
|
})),
|
||||||
|
} as Product,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getProduct
|
||||||
|
}
|
41
framework/reactioncommerce/api/operations/get-site-info.ts
Normal file
41
framework/reactioncommerce/api/operations/get-site-info.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { Provider, ReactionCommerceConfig } from '../'
|
||||||
|
import { GetCollectionsQuery } from '../../schema'
|
||||||
|
import getCollectionsQuery from '../../utils/queries/get-all-collections-query'
|
||||||
|
import { OperationContext } from '@commerce/api/operations'
|
||||||
|
import { Category } from '@commerce/types/site'
|
||||||
|
import getCategories from '../../utils/get-categories'
|
||||||
|
import getVendors from '../../utils/get-vendors'
|
||||||
|
|
||||||
|
export type GetSiteInfoResult<
|
||||||
|
T extends { categories: any[]; brands: any[] } = {
|
||||||
|
categories: Category[]
|
||||||
|
brands: any[]
|
||||||
|
}
|
||||||
|
> = T
|
||||||
|
|
||||||
|
export default function getSiteInfoOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getSiteInfo({
|
||||||
|
query = getCollectionsQuery,
|
||||||
|
variables,
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables?: any
|
||||||
|
config?: Partial<ReactionCommerceConfig>
|
||||||
|
preview?: boolean
|
||||||
|
} = {}): Promise<GetSiteInfoResult> {
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
|
||||||
|
const categories = await getCategories(config)
|
||||||
|
const brands = await getVendors(config)
|
||||||
|
|
||||||
|
return {
|
||||||
|
categories: categories ?? [],
|
||||||
|
brands,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getSiteInfo
|
||||||
|
}
|
52
framework/reactioncommerce/api/operations/login.ts
Normal file
52
framework/reactioncommerce/api/operations/login.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import type { ServerResponse } from 'http'
|
||||||
|
import type {
|
||||||
|
OperationContext,
|
||||||
|
OperationOptions,
|
||||||
|
} from '@commerce/api/operations'
|
||||||
|
import { ValidationError } from '@commerce/utils/errors'
|
||||||
|
import type { LoginOperation } from '../../types/login'
|
||||||
|
import type { MutationAuthenticateArgs } from '../../schema'
|
||||||
|
import { Provider, ReactionCommerceConfig } from '..'
|
||||||
|
import loginMutation from '../../utils/mutations/authenticate'
|
||||||
|
|
||||||
|
export default function loginOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function login<T extends LoginOperation>(opts: {
|
||||||
|
variables: T['variables']
|
||||||
|
config?: Partial<ReactionCommerceConfig>
|
||||||
|
res: ServerResponse
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
async function login<T extends LoginOperation>(
|
||||||
|
opts: {
|
||||||
|
variables: T['variables']
|
||||||
|
config?: Partial<ReactionCommerceConfig>
|
||||||
|
res: ServerResponse
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
|
||||||
|
async function login<T extends LoginOperation>({
|
||||||
|
query = loginMutation,
|
||||||
|
variables,
|
||||||
|
res: response,
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables: T['variables']
|
||||||
|
res: ServerResponse
|
||||||
|
config?: Partial<ReactionCommerceConfig>
|
||||||
|
}): Promise<T['data']> {
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
|
||||||
|
const { data, res } = await config.fetch<any>(query, {
|
||||||
|
variables,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: data.authenticate?.tokens?.accessToken,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return login
|
||||||
|
}
|
@ -13,14 +13,16 @@ export const handler: SWRHook<
|
|||||||
> = {
|
> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/api/reactioncommerce/cart',
|
url: '/api/cart',
|
||||||
},
|
},
|
||||||
async fetcher({ input: { cartId }, options, fetch }) {
|
async fetcher({ input: { cartId }, options, fetch }) {
|
||||||
console.log('cart API fetcher', options)
|
console.log('cart API fetcher', options)
|
||||||
const data = await fetch(options)
|
const data = await fetch(options)
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
useHook: ({ useData }) => (input) => {
|
useHook:
|
||||||
|
({ useData }) =>
|
||||||
|
(input) => {
|
||||||
const response = useData({
|
const response = useData({
|
||||||
swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
|
swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
import commerce from '@lib/api/commerce'
|
||||||
import getCategories, { Category } from '../utils/get-categories'
|
import getCategories, { Category } from '../utils/get-categories'
|
||||||
import getVendors, { Brands } from '../utils/get-vendors'
|
import getVendors, { Brands } from '../utils/get-vendors'
|
||||||
|
import { ReactionCommerceConfig } from '../api'
|
||||||
import { getConfig, ReactionCommerceConfig } from '../api'
|
|
||||||
|
|
||||||
export type GetSiteInfoResult<
|
export type GetSiteInfoResult<
|
||||||
T extends { categories: any[]; brands: any[] } = {
|
T extends { categories: any[]; brands: any[] } = {
|
||||||
@ -17,7 +17,7 @@ const getSiteInfo = async (options?: {
|
|||||||
}): Promise<GetSiteInfoResult> => {
|
}): Promise<GetSiteInfoResult> => {
|
||||||
let { config } = options ?? {}
|
let { config } = options ?? {}
|
||||||
|
|
||||||
config = getConfig(config)
|
config = commerce.getConfig(config)
|
||||||
|
|
||||||
const categories = await getCategories(config)
|
const categories = await getCategories(config)
|
||||||
const brands = await getVendors(config)
|
const brands = await getVendors(config)
|
||||||
|
@ -26,6 +26,7 @@ const getCategories = async (
|
|||||||
entityId,
|
entityId,
|
||||||
name,
|
name,
|
||||||
path: `/${handle}`,
|
path: `/${handle}`,
|
||||||
|
slug: handle,
|
||||||
})
|
})
|
||||||
) ?? []
|
) ?? []
|
||||||
)
|
)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "nextjs-commerce",
|
"name": "nextjs-commerce",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "NODE_OPTIONS='--inspect' next dev",
|
"dev": "NODE_OPTIONS='--inspect' next dev -p 4000",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"analyze": "BUNDLE_ANALYZE=both yarn build",
|
"analyze": "BUNDLE_ANALYZE=both yarn build",
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
import cartApi from '@framework/api/cart'
|
|
||||||
|
|
||||||
export default cartApi()
|
|
Loading…
x
Reference in New Issue
Block a user