mirror of
https://github.com/vercel/commerce.git
synced 2025-05-17 15:06:59 +00:00
Updated types, schemas & providers
This commit is contained in:
parent
163a22ec88
commit
ba0e7beb73
@ -1130,7 +1130,7 @@ export interface definitions {
|
|||||||
*/
|
*/
|
||||||
search_keywords?: string
|
search_keywords?: string
|
||||||
/**
|
/**
|
||||||
* Image URL used for this category on the storefront. Images can be uploaded via form file post to `/brands/{brandId}/image`, or by providing a publicly accessible URL in this field.
|
* Image URL used for this category on the storefront. Images can be uploaded via form file post to `/{brandId}/image`, or by providing a publicly accessible URL in this field.
|
||||||
*/
|
*/
|
||||||
image_url?: string
|
image_url?: string
|
||||||
custom_url?: definitions['customUrl_Full']
|
custom_url?: definitions['customUrl_Full']
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import type { Wishlist } from '../../../types/wishlist'
|
import type { Wishlist } from '../../../types/wishlist'
|
||||||
import type { WishlistEndpoint } from '.'
|
import type { WishlistEndpoint } from '.'
|
||||||
import getCustomerId from '../../utils/get-customer-id'
|
import getCustomerId from '../../utils/get-customer-id'
|
||||||
import getCustomerWishlist from '../../operations/get-customer-wishlist'
|
|
||||||
|
|
||||||
// Return wishlist info
|
// Return wishlist info
|
||||||
const getWishlist: WishlistEndpoint['handlers']['getWishlist'] = async ({
|
const getWishlist: WishlistEndpoint['handlers']['getWishlist'] = async ({
|
||||||
|
@ -49,7 +49,7 @@ export default function getCustomerWishlistOperation({
|
|||||||
|
|
||||||
if (includeProducts && wishlist?.items?.length) {
|
if (includeProducts && wishlist?.items?.length) {
|
||||||
const ids = wishlist.items
|
const ids = wishlist.items
|
||||||
?.map((item) => (item?.product_id ? String(item?.product_id) : null))
|
?.map((item) => (item?.productId ? String(item?.productId) : null))
|
||||||
.filter((id): id is string => !!id)
|
.filter((id): id is string => !!id)
|
||||||
|
|
||||||
if (ids?.length) {
|
if (ids?.length) {
|
||||||
@ -66,7 +66,7 @@ export default function getCustomerWishlistOperation({
|
|||||||
}, {})
|
}, {})
|
||||||
// Populate the wishlist items with the graphql products
|
// Populate the wishlist items with the graphql products
|
||||||
wishlist.items.forEach((item) => {
|
wishlist.items.forEach((item) => {
|
||||||
const product = item && productsById[item.product_id!]
|
const product = item && productsById[Number(item.productId)]
|
||||||
if (item && product) {
|
if (item && product) {
|
||||||
// @ts-ignore Fix this type when the wishlist type is properly defined
|
// @ts-ignore Fix this type when the wishlist type is properly defined
|
||||||
item.product = product
|
item.product = product
|
||||||
|
@ -7,7 +7,7 @@ import type { GetSiteInfoQuery } from '../../../schema'
|
|||||||
import filterEdges from '../utils/filter-edges'
|
import filterEdges from '../utils/filter-edges'
|
||||||
import type { BigcommerceConfig, Provider } from '..'
|
import type { BigcommerceConfig, Provider } from '..'
|
||||||
import { categoryTreeItemFragment } from '../fragments/category-tree'
|
import { categoryTreeItemFragment } from '../fragments/category-tree'
|
||||||
import { normalizeCategory } from '../../lib/normalize'
|
import { normalizeBrand, normalizeCategory } from '../../lib/normalize'
|
||||||
|
|
||||||
// Get 3 levels of categories
|
// Get 3 levels of categories
|
||||||
export const getSiteInfoQuery = /* GraphQL */ `
|
export const getSiteInfoQuery = /* GraphQL */ `
|
||||||
@ -79,7 +79,7 @@ export default function getSiteInfoOperation({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
categories: categories ?? [],
|
categories: categories ?? [],
|
||||||
brands: filterEdges(brands),
|
brands: filterEdges(brands).map(normalizeBrand),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { WishlistItemBody } from '../../types/wishlist'
|
import type { WishlistItemBody } from '../../types/wishlist'
|
||||||
import type { CartItemBody, OptionSelections } from '../../types/cart'
|
import type { CartItemBody, SelectedOption } from '../../types/cart'
|
||||||
|
|
||||||
type BCWishlistItemBody = {
|
type BCWishlistItemBody = {
|
||||||
product_id: number
|
product_id: number
|
||||||
@ -10,7 +10,7 @@ type BCCartItemBody = {
|
|||||||
product_id: number
|
product_id: number
|
||||||
variant_id: number
|
variant_id: number
|
||||||
quantity?: number
|
quantity?: number
|
||||||
option_selections?: OptionSelections[]
|
option_selections?: SelectedOption[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseWishlistItem = (
|
export const parseWishlistItem = (
|
||||||
@ -24,5 +24,5 @@ export const parseCartItem = (item: CartItemBody): BCCartItemBody => ({
|
|||||||
quantity: item.quantity,
|
quantity: item.quantity,
|
||||||
product_id: Number(item.productId),
|
product_id: Number(item.productId),
|
||||||
variant_id: Number(item.variantId),
|
variant_id: Number(item.variantId),
|
||||||
option_selections: item.optionSelections,
|
option_selections: item.optionsSelected,
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { Product } from '../types/product'
|
import type { Product } from '../types/product'
|
||||||
import type { Cart, BigcommerceCart, LineItem } from '../types/cart'
|
import type { Cart, BigcommerceCart, LineItem } from '../types/cart'
|
||||||
import type { Page } from '../types/page'
|
import type { Page } from '../types/page'
|
||||||
import type { BCCategory, Category } from '../types/site'
|
import type { BCCategory, BCBrand, Category, Brand } from '../types/site'
|
||||||
import { definitions } from '../api/definitions/store-content'
|
import { definitions } from '../api/definitions/store-content'
|
||||||
import update from './immutability'
|
import update from './immutability'
|
||||||
import getSlug from './get-slug'
|
import getSlug from './get-slug'
|
||||||
@ -54,7 +54,7 @@ export function normalizeProduct(productNode: any): Product {
|
|||||||
: [],
|
: [],
|
||||||
},
|
},
|
||||||
brand: {
|
brand: {
|
||||||
$apply: (brand: any) => (brand?.entityId ? brand?.entityId : null),
|
$apply: (brand: any) => (brand?.id ? brand.id : null),
|
||||||
},
|
},
|
||||||
slug: {
|
slug: {
|
||||||
$set: path?.replace(/^\/+|\/+$/g, ''),
|
$set: path?.replace(/^\/+|\/+$/g, ''),
|
||||||
@ -134,3 +134,12 @@ export function normalizeCategory(category: BCCategory): Category {
|
|||||||
path: category.path,
|
path: category.path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function normalizeBrand(brand: BCBrand): Brand {
|
||||||
|
return {
|
||||||
|
id: `${brand.node.entityId}`,
|
||||||
|
name: brand.node.name,
|
||||||
|
slug: getSlug(brand.node.path),
|
||||||
|
path: brand.node.path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import * as Core from '@vercel/commerce/types/cart'
|
|
||||||
|
|
||||||
export * from '@vercel/commerce/types/cart'
|
export * from '@vercel/commerce/types/cart'
|
||||||
|
|
||||||
// TODO: this type should match:
|
// TODO: this type should match:
|
||||||
@ -24,43 +22,3 @@ export type BigcommerceCart = {
|
|||||||
discounts?: { id: number; discounted_amount: number }[]
|
discounts?: { id: number; discounted_amount: number }[]
|
||||||
// TODO: add missing fields
|
// TODO: add missing fields
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extend core cart types
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type Cart = Core.Cart & {
|
|
||||||
lineItems: Core.LineItem[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export type OptionSelections = {
|
|
||||||
option_id: number
|
|
||||||
option_value: number | string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CartItemBody = Core.CartItemBody & {
|
|
||||||
productId: string // The product id is always required for BC
|
|
||||||
optionSelections?: OptionSelections[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CartTypes = {
|
|
||||||
cart: Cart
|
|
||||||
item: Core.LineItem
|
|
||||||
itemBody: CartItemBody
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CartHooks = Core.CartHooks
|
|
||||||
|
|
||||||
export type GetCartHook = CartHooks['getCart']
|
|
||||||
export type AddItemHook = CartHooks['addItem']
|
|
||||||
export type UpdateItemHook = CartHooks['updateItem']
|
|
||||||
export type RemoveItemHook = CartHooks['removeItem']
|
|
||||||
|
|
||||||
export type CartSchema = Core.CartSchema
|
|
||||||
|
|
||||||
export type CartHandlers = Core.CartHandlers
|
|
||||||
|
|
||||||
export type GetCartHandler = CartHandlers['getCart']
|
|
||||||
export type AddItemHandler = CartHandlers['addItem']
|
|
||||||
export type UpdateItemHandler = CartHandlers['updateItem']
|
|
||||||
export type RemoveItemHandler = CartHandlers['removeItem']
|
|
||||||
|
@ -1,5 +1 @@
|
|||||||
import * as Core from '@vercel/commerce/types/customer'
|
|
||||||
|
|
||||||
export * from '@vercel/commerce/types/customer'
|
export * from '@vercel/commerce/types/customer'
|
||||||
|
|
||||||
export type CustomerSchema = Core.CustomerSchema
|
|
||||||
|
@ -1,8 +1 @@
|
|||||||
import * as Core from '@vercel/commerce/types/login'
|
|
||||||
import type { LoginMutationVariables } from '../../schema'
|
|
||||||
|
|
||||||
export * from '@vercel/commerce/types/login'
|
export * from '@vercel/commerce/types/login'
|
||||||
|
|
||||||
export type LoginOperation = Core.LoginOperation & {
|
|
||||||
variables: LoginMutationVariables
|
|
||||||
}
|
|
||||||
|
@ -1,11 +1 @@
|
|||||||
import * as Core from '@vercel/commerce/types/page'
|
|
||||||
export * from '@vercel/commerce/types/page'
|
export * from '@vercel/commerce/types/page'
|
||||||
|
|
||||||
export type Page = Core.Page
|
|
||||||
|
|
||||||
export type PageTypes = {
|
|
||||||
page: Page
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GetAllPagesOperation = Core.GetAllPagesOperation<PageTypes>
|
|
||||||
export type GetPageOperation = Core.GetPageOperation<PageTypes>
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import * as Core from '@vercel/commerce/types/site'
|
import type { GetSiteInfoQuery } from '../../schema'
|
||||||
import type { GetSiteInfoQuery, GetSiteInfoQueryVariables } from '../../schema'
|
|
||||||
|
|
||||||
export * from '@vercel/commerce/types/site'
|
export * from '@vercel/commerce/types/site'
|
||||||
|
|
||||||
@ -7,13 +6,6 @@ export type BCCategory = NonNullable<
|
|||||||
GetSiteInfoQuery['site']['categoryTree']
|
GetSiteInfoQuery['site']['categoryTree']
|
||||||
>[0]
|
>[0]
|
||||||
|
|
||||||
export type Brand = NonNullable<
|
export type BCBrand = NonNullable<
|
||||||
NonNullable<GetSiteInfoQuery['site']['brands']['edges']>[0]
|
NonNullable<GetSiteInfoQuery['site']['brands']['edges']>[0]
|
||||||
>
|
>
|
||||||
|
|
||||||
export type SiteTypes = {
|
|
||||||
category: Core.Category
|
|
||||||
brand: Brand
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GetSiteInfoOperation = Core.GetSiteInfoOperation<SiteTypes>
|
|
||||||
|
@ -1,24 +1 @@
|
|||||||
import * as Core from '@vercel/commerce/types/wishlist'
|
|
||||||
import { definitions } from '../api/definitions/wishlist'
|
|
||||||
import type { ProductEdge } from '../api/operations/get-all-products'
|
|
||||||
|
|
||||||
export * from '@vercel/commerce/types/wishlist'
|
export * from '@vercel/commerce/types/wishlist'
|
||||||
|
|
||||||
export type WishlistItem = NonNullable<
|
|
||||||
definitions['wishlist_Full']['items']
|
|
||||||
>[0] & {
|
|
||||||
product?: ProductEdge['node']
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Wishlist = Omit<definitions['wishlist_Full'], 'items'> & {
|
|
||||||
items?: WishlistItem[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export type WishlistTypes = {
|
|
||||||
wishlist: Wishlist
|
|
||||||
itemBody: Core.WishlistItemBody
|
|
||||||
}
|
|
||||||
|
|
||||||
export type WishlistSchema = Core.WishlistSchema<WishlistTypes>
|
|
||||||
export type GetCustomerWishlistOperation =
|
|
||||||
Core.GetCustomerWishlistOperation<WishlistTypes>
|
|
||||||
|
@ -3,58 +3,60 @@ import { CommerceAPIError } from '../utils/errors'
|
|||||||
import isAllowedOperation from '../utils/is-allowed-operation'
|
import isAllowedOperation from '../utils/is-allowed-operation'
|
||||||
import type { GetAPISchema } from '..'
|
import type { GetAPISchema } from '..'
|
||||||
|
|
||||||
const cartEndpoint: GetAPISchema<any, CartSchema<any>>['endpoint']['handler'] =
|
const cartEndpoint: GetAPISchema<
|
||||||
async (ctx) => {
|
any,
|
||||||
const { req, res, handlers, config } = ctx
|
CartSchema
|
||||||
|
>['endpoint']['handler'] = async (ctx) => {
|
||||||
|
const { req, res, handlers, config } = ctx
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isAllowedOperation(req, res, {
|
!isAllowedOperation(req, res, {
|
||||||
GET: handlers['getCart'],
|
GET: handlers['getCart'],
|
||||||
POST: handlers['addItem'],
|
POST: handlers['addItem'],
|
||||||
PUT: handlers['updateItem'],
|
PUT: handlers['updateItem'],
|
||||||
DELETE: handlers['removeItem'],
|
DELETE: handlers['removeItem'],
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
const { cookies } = req
|
|
||||||
const cartId = cookies[config.cartCookie]
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Return current cart info
|
|
||||||
if (req.method === 'GET') {
|
|
||||||
const body = { cartId }
|
|
||||||
return await handlers['getCart']({ ...ctx, body })
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or add an item to the cart
|
|
||||||
if (req.method === 'POST') {
|
|
||||||
const body = { ...req.body, cartId }
|
|
||||||
return await handlers['addItem']({ ...ctx, body })
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update item in cart
|
|
||||||
if (req.method === 'PUT') {
|
|
||||||
const body = { ...req.body, cartId }
|
|
||||||
return await handlers['updateItem']({ ...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 }] })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { cookies } = req
|
||||||
|
const cartId = cookies[config.cartCookie]
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Return current cart info
|
||||||
|
if (req.method === 'GET') {
|
||||||
|
const body = { cartId }
|
||||||
|
return await handlers['getCart']({ ...ctx, body })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or add an item to the cart
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
const body = { ...req.body, cartId }
|
||||||
|
return await handlers['addItem']({ ...ctx, body })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update item in cart
|
||||||
|
if (req.method === 'PUT') {
|
||||||
|
const body = { ...req.body, cartId }
|
||||||
|
return await handlers['updateItem']({ ...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 }] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default cartEndpoint
|
export default cartEndpoint
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { ProductsSchema } from '../../../types/product'
|
import type { ProductsSchema } from '../../../types/product'
|
||||||
import { CommerceAPIError } from '../../utils/errors'
|
import { getErrorMessage } from '../../utils/errors'
|
||||||
import isAllowedOperation from '../../utils/is-allowed-operation'
|
import isAllowedOperation from '../../utils/is-allowed-operation'
|
||||||
import type { GetAPISchema } from '../..'
|
import type { GetAPISchema } from '../..'
|
||||||
|
|
||||||
@ -18,12 +18,7 @@ const productsEndpoint: GetAPISchema<
|
|||||||
return await handlers['getProducts']({ ...ctx, body })
|
return await handlers['getProducts']({ ...ctx, body })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
const message = getErrorMessage(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 }] })
|
res.status(500).json({ data: null, errors: [{ message }] })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
0
packages/commerce/src/api/endpoints/index.ts
Normal file
0
packages/commerce/src/api/endpoints/index.ts
Normal file
@ -1,11 +1,11 @@
|
|||||||
import type { LoginSchema } from '../../types/login'
|
import type { LoginSchema } from '../../types/login'
|
||||||
import { CommerceAPIError } from '../utils/errors'
|
import { CommerceAPIError, getErrorMessage } from '../utils/errors'
|
||||||
import isAllowedOperation from '../utils/is-allowed-operation'
|
import isAllowedOperation from '../utils/is-allowed-operation'
|
||||||
import type { GetAPISchema } from '..'
|
import type { GetAPISchema } from '..'
|
||||||
|
|
||||||
const loginEndpoint: GetAPISchema<
|
const loginEndpoint: GetAPISchema<
|
||||||
any,
|
any,
|
||||||
LoginSchema<any>
|
LoginSchema
|
||||||
>['endpoint']['handler'] = async (ctx) => {
|
>['endpoint']['handler'] = async (ctx) => {
|
||||||
const { req, res, handlers } = ctx
|
const { req, res, handlers } = ctx
|
||||||
|
|
||||||
@ -24,10 +24,7 @@ const loginEndpoint: GetAPISchema<
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|
||||||
const message =
|
const message = getErrorMessage(error)
|
||||||
error instanceof CommerceAPIError
|
|
||||||
? 'An unexpected error ocurred with the Commerce API'
|
|
||||||
: 'An unexpected error ocurred'
|
|
||||||
|
|
||||||
res.status(500).json({ data: null, errors: [{ message }] })
|
res.status(500).json({ data: null, errors: [{ message }] })
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import type { GetAPISchema } from '..'
|
|||||||
|
|
||||||
const wishlistEndpoint: GetAPISchema<
|
const wishlistEndpoint: GetAPISchema<
|
||||||
any,
|
any,
|
||||||
WishlistSchema<any>
|
WishlistSchema
|
||||||
>['endpoint']['handler'] = async (ctx) => {
|
>['endpoint']['handler'] = async (ctx) => {
|
||||||
const { req, res, handlers, config } = ctx
|
const { req, res, handlers, config } = ctx
|
||||||
|
|
||||||
|
@ -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,38 @@ export class CommerceNetworkError extends Error {
|
|||||||
this.name = 'CommerceNetworkError'
|
this.name = 'CommerceNetworkError'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getErrorMessage = (error: unknown) => {
|
||||||
|
return error instanceof CommerceAPIError
|
||||||
|
? 'An unexpected error ocurred with the Commerce API'
|
||||||
|
: 'An unexpected error ocurred'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getOperationError = (operation: string, error: unknown) => {
|
||||||
|
if (error instanceof ZodError) {
|
||||||
|
error = 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'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error instanceof Error) {
|
||||||
|
return new CommerceError({
|
||||||
|
code: 'OPERATION_ERROR',
|
||||||
|
message: `An unexpected error ocurred with the ${operation} operation: ${error.message}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { z } from 'zod'
|
|
||||||
|
|
||||||
import { productSchema } from '../../schemas/product'
|
|
||||||
import { CommerceError } from '../../utils/errors'
|
|
||||||
|
|
||||||
import type { AllowedOperations, OperationsData } from '../operations'
|
import type { AllowedOperations, OperationsData } from '../operations'
|
||||||
|
|
||||||
|
import { z } from 'zod'
|
||||||
|
import { getOperationError } from './errors'
|
||||||
|
import { pageSchema } from '../../schemas/page'
|
||||||
|
import { siteInfoSchema } from '../../schemas/site'
|
||||||
|
import { productSchema, productsPathsSchema } from '../../schemas/product'
|
||||||
|
|
||||||
export const withSchemaParser =
|
export const withSchemaParser =
|
||||||
(
|
(
|
||||||
operation: AllowedOperations,
|
operation: AllowedOperations,
|
||||||
@ -16,27 +17,7 @@ export const withSchemaParser =
|
|||||||
parse(operation, result)
|
parse(operation, result)
|
||||||
return result
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof z.ZodError) {
|
return Promise.reject(getOperationError(operation, error))
|
||||||
return Promise.reject(
|
|
||||||
new CommerceError({
|
|
||||||
code: 'SCHEMA_VALIDATION_ERROR',
|
|
||||||
message:
|
|
||||||
`The ${operation} opration returned invalid data and has ${
|
|
||||||
error.issues.length
|
|
||||||
} parse ${error.issues.length === 1 ? 'error' : 'errors'}: \n` +
|
|
||||||
error.issues
|
|
||||||
.map(
|
|
||||||
(e, index) =>
|
|
||||||
`${index + 1}. Property ${e.path.join('.')} (${e.code}): ${
|
|
||||||
e.message
|
|
||||||
}`
|
|
||||||
)
|
|
||||||
.join('\n'),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return Promise.reject(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,11 +28,26 @@ const parse = (operation: AllowedOperations, data: OperationsData) => {
|
|||||||
break
|
break
|
||||||
|
|
||||||
case 'getAllProducts':
|
case 'getAllProducts':
|
||||||
data.products?.forEach((product: any) => productSchema.parse(product))
|
z.array(productSchema).parse(data.products)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'getAllProductPaths':
|
case 'getAllProductPaths':
|
||||||
data.products?.forEach((p) => z.string().parse(p.path))
|
productsPathsSchema.parse(data.products)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'getPage':
|
||||||
|
pageSchema.parse(data.page)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'getAllPages':
|
||||||
|
z.array(pageSchema).parse(data.pages)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'getSiteInfo':
|
||||||
|
siteInfoSchema.parse({
|
||||||
|
categories: data.categories,
|
||||||
|
brands: data.brands,
|
||||||
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import type { LoginHook } from '../types/login'
|
|||||||
import type { Provider } from '..'
|
import type { Provider } from '..'
|
||||||
|
|
||||||
export type UseLogin<
|
export type UseLogin<
|
||||||
H extends MutationHook<LoginHook<any>> = MutationHook<LoginHook>
|
H extends MutationHook<LoginHook> = MutationHook<LoginHook>
|
||||||
> = ReturnType<H['useHook']>
|
> = ReturnType<H['useHook']>
|
||||||
|
|
||||||
export const fetcher: HookFetcherFn<LoginHook> = mutationFetcher
|
export const fetcher: HookFetcherFn<LoginHook> = mutationFetcher
|
||||||
|
@ -5,7 +5,7 @@ import type { LogoutHook } from '../types/logout'
|
|||||||
import type { Provider } from '..'
|
import type { Provider } from '..'
|
||||||
|
|
||||||
export type UseLogout<
|
export type UseLogout<
|
||||||
H extends MutationHook<LogoutHook<any>> = MutationHook<LogoutHook>
|
H extends MutationHook<LogoutHook> = MutationHook<LogoutHook>
|
||||||
> = ReturnType<H['useHook']>
|
> = ReturnType<H['useHook']>
|
||||||
|
|
||||||
export const fetcher: HookFetcherFn<LogoutHook> = mutationFetcher
|
export const fetcher: HookFetcherFn<LogoutHook> = mutationFetcher
|
||||||
|
@ -5,7 +5,7 @@ import type { SignupHook } from '../types/signup'
|
|||||||
import type { Provider } from '..'
|
import type { Provider } from '..'
|
||||||
|
|
||||||
export type UseSignup<
|
export type UseSignup<
|
||||||
H extends MutationHook<SignupHook<any>> = MutationHook<SignupHook>
|
H extends MutationHook<SignupHook> = MutationHook<SignupHook>
|
||||||
> = ReturnType<H['useHook']>
|
> = ReturnType<H['useHook']>
|
||||||
|
|
||||||
export const fetcher: HookFetcherFn<SignupHook> = mutationFetcher
|
export const fetcher: HookFetcherFn<SignupHook> = mutationFetcher
|
||||||
|
@ -7,7 +7,7 @@ import { useHook, useSWRHook } from '../utils/use-hook'
|
|||||||
import { Provider, useCommerce } from '..'
|
import { Provider, useCommerce } from '..'
|
||||||
|
|
||||||
export type UseCheckout<
|
export type UseCheckout<
|
||||||
H extends SWRHook<GetCheckoutHook<any>> = SWRHook<GetCheckoutHook>
|
H extends SWRHook<GetCheckoutHook> = SWRHook<GetCheckoutHook>
|
||||||
> = ReturnType<H['useHook']>
|
> = ReturnType<H['useHook']>
|
||||||
|
|
||||||
export const fetcher: HookFetcherFn<GetCheckoutHook> = async ({
|
export const fetcher: HookFetcherFn<GetCheckoutHook> = async ({
|
||||||
|
@ -6,9 +6,7 @@ import { useHook, useMutationHook } from '../utils/use-hook'
|
|||||||
import { mutationFetcher } from '../utils/default-fetcher'
|
import { mutationFetcher } from '../utils/default-fetcher'
|
||||||
|
|
||||||
export type UseSubmitCheckout<
|
export type UseSubmitCheckout<
|
||||||
H extends MutationHook<
|
H extends MutationHook<SubmitCheckoutHook> = MutationHook<SubmitCheckoutHook>
|
||||||
SubmitCheckoutHook<any>
|
|
||||||
> = MutationHook<SubmitCheckoutHook>
|
|
||||||
> = ReturnType<H['useHook']>
|
> = ReturnType<H['useHook']>
|
||||||
|
|
||||||
export const fetcher: HookFetcherFn<SubmitCheckoutHook> = mutationFetcher
|
export const fetcher: HookFetcherFn<SubmitCheckoutHook> = mutationFetcher
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
import * as product from './product'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
product,
|
|
||||||
}
|
|
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('/'),
|
||||||
|
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(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
@ -2,7 +2,7 @@ import { z } from 'zod'
|
|||||||
|
|
||||||
export const productPriceSchema = z.object({
|
export const productPriceSchema = z.object({
|
||||||
value: z.number(),
|
value: z.number(),
|
||||||
currencyCode: z.string().optional(),
|
currencyCode: z.string().max(3).optional(),
|
||||||
retailPrice: z.number().optional(),
|
retailPrice: z.number().optional(),
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ export const productOptionSchema = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const productImageSchema = z.object({
|
export const productImageSchema = z.object({
|
||||||
url: z.string(),
|
url: z.string().url().or(z.string().startsWith('/')),
|
||||||
alt: z.string().optional(),
|
alt: z.string().optional(),
|
||||||
width: z.number().optional(),
|
width: z.number().optional(),
|
||||||
height: z.number().optional(),
|
height: z.number().optional(),
|
||||||
@ -26,7 +26,7 @@ export const productImageSchema = z.object({
|
|||||||
|
|
||||||
export const productVariantSchema = z.object({
|
export const productVariantSchema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
sku: z.string(),
|
sku: z.string().optional(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
options: z.array(productOptionSchema),
|
options: z.array(productOptionSchema),
|
||||||
image: productImageSchema.optional(),
|
image: productImageSchema.optional(),
|
||||||
@ -46,3 +46,15 @@ export const productSchema = z.object({
|
|||||||
options: z.array(productOptionSchema),
|
options: z.array(productOptionSchema),
|
||||||
vendor: z.string().optional(),
|
vendor: z.string().optional(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const productsPathsSchema = z.array(
|
||||||
|
z.object({ path: z.string().startsWith('/') })
|
||||||
|
)
|
||||||
|
|
||||||
|
export const searchProductBodySchema = z.object({
|
||||||
|
search: z.string(),
|
||||||
|
categoryId: z.string(),
|
||||||
|
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('/'),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
@ -3,13 +3,13 @@ import type { Discount, Image } from './common'
|
|||||||
// TODO: This should use the same type as the `ProductVariant` type from `product.ts`
|
// TODO: This should use the same type as the `ProductVariant` type from `product.ts`
|
||||||
export interface ProductVariant {
|
export interface ProductVariant {
|
||||||
/**
|
/**
|
||||||
* The variant's id.
|
* The unique identifier for the variant.
|
||||||
*/
|
*/
|
||||||
id: string | number
|
id: string
|
||||||
/**
|
/**
|
||||||
* The SKU (stock keeping unit) associated with the product variant.
|
* The SKU (stock keeping unit) associated with the product variant.
|
||||||
*/
|
*/
|
||||||
sku: string
|
sku?: string
|
||||||
/**
|
/**
|
||||||
* The product variant’s name, or the product's name.
|
* The product variant’s name, or the product's name.
|
||||||
*/
|
*/
|
||||||
@ -19,7 +19,7 @@ export interface ProductVariant {
|
|||||||
*/
|
*/
|
||||||
price: number
|
price: number
|
||||||
/**
|
/**
|
||||||
* Product variant’s price, as quoted by the manufacturer/distributor.
|
* The product variant’s price before discounts are applied.
|
||||||
*/
|
*/
|
||||||
listPrice: number
|
listPrice: number
|
||||||
/**
|
/**
|
||||||
@ -39,38 +39,38 @@ export interface ProductVariant {
|
|||||||
|
|
||||||
export interface SelectedOption {
|
export interface SelectedOption {
|
||||||
/**
|
/**
|
||||||
* The selected option's id
|
* The unique identifier for the option.
|
||||||
*/
|
*/
|
||||||
id?: string
|
id?: string
|
||||||
/**
|
/**
|
||||||
* The product option’s name.
|
* The product option’s name, such as "Color" or "Size".
|
||||||
*/
|
*/
|
||||||
name: string
|
name: string
|
||||||
/**
|
/**
|
||||||
* The product option’s value.
|
* The product option’s value, such as "Red" or "XL".
|
||||||
*/
|
*/
|
||||||
value: string
|
value: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LineItem {
|
export interface LineItem {
|
||||||
/**
|
/**
|
||||||
* The line item's id.
|
* The unique identifier for the line item.
|
||||||
*/
|
*/
|
||||||
id: string
|
id: string
|
||||||
/**
|
/**
|
||||||
* The product variant’s id.
|
* The unique identifier for the product variant.
|
||||||
*/
|
*/
|
||||||
variantId: string
|
variantId: string
|
||||||
/**
|
/**
|
||||||
* The product's id.
|
* The unique identifier for the product, if the variant is not provided.
|
||||||
*/
|
*/
|
||||||
productId: string
|
productId: string
|
||||||
/**
|
/**
|
||||||
* The name of the line item.
|
* This is usually the product's name.
|
||||||
*/
|
*/
|
||||||
name: string
|
name: string
|
||||||
/**
|
/**
|
||||||
* List of discounts applied to the line item.
|
* The quantity of the product variant in the line item.
|
||||||
*/
|
*/
|
||||||
quantity: number
|
quantity: number
|
||||||
/**
|
/**
|
||||||
@ -86,7 +86,7 @@ export interface LineItem {
|
|||||||
*/
|
*/
|
||||||
variant: ProductVariant
|
variant: ProductVariant
|
||||||
/**
|
/**
|
||||||
* List of selected options.
|
* List of selected options, to be used when displaying the line item, such as Color: Red, Size: XL.
|
||||||
*/
|
*/
|
||||||
options?: SelectedOption[]
|
options?: SelectedOption[]
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ export interface LineItem {
|
|||||||
*/
|
*/
|
||||||
export interface Cart {
|
export interface Cart {
|
||||||
/**
|
/**
|
||||||
* The cart's id.
|
* The unique identifier for the cart.
|
||||||
*/
|
*/
|
||||||
id: string
|
id: string
|
||||||
/**
|
/**
|
||||||
@ -119,7 +119,7 @@ export interface Cart {
|
|||||||
* The currency used for this cart */
|
* The currency used for this cart */
|
||||||
currency: { code: string }
|
currency: { code: string }
|
||||||
/**
|
/**
|
||||||
* Specifies if taxes are included in the line items.
|
* Indicates if taxes are included in the line items.
|
||||||
*/
|
*/
|
||||||
taxesIncluded: boolean
|
taxesIncluded: boolean
|
||||||
/**
|
/**
|
||||||
@ -135,12 +135,13 @@ export interface Cart {
|
|||||||
* Price of the cart before duties, shipping and taxes.*/
|
* Price of the cart before duties, shipping and taxes.*/
|
||||||
subtotalPrice: number
|
subtotalPrice: number
|
||||||
/**
|
/**
|
||||||
* The sum of all the prices of all the items in the cart.*/
|
* The sum of all the prices of all the items in the cart.
|
||||||
/**
|
* Duties, taxes and discounts included.
|
||||||
* Duties, taxes and discounts included.*/
|
*/
|
||||||
totalPrice: number
|
totalPrice: number
|
||||||
/**
|
/**
|
||||||
* Discounts that have been applied on the cart.*/
|
* Discounts that have been applied on the cart.
|
||||||
|
*/
|
||||||
discounts?: Discount[]
|
discounts?: Discount[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,17 +150,22 @@ export interface Cart {
|
|||||||
*/
|
*/
|
||||||
export interface CartItemBody {
|
export interface CartItemBody {
|
||||||
/**
|
/**
|
||||||
* The product variant's id.
|
* The unique identifier for the product variant.
|
||||||
*/
|
*/
|
||||||
variantId: string
|
variantId: string
|
||||||
/**
|
/**
|
||||||
* The product's id.
|
* The unique identifier for the product, if the variant is not provided.
|
||||||
*/
|
*/
|
||||||
productId?: string
|
productId?: string
|
||||||
/**
|
/**
|
||||||
* The quantity of the product variant.
|
* The quantity of the product variant.
|
||||||
*/
|
*/
|
||||||
quantity?: number
|
quantity?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The product variant's selected options.
|
||||||
|
*/
|
||||||
|
optionsSelected?: SelectedOption[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,6 +5,8 @@ import type { Card, CardFields } from './customer/card'
|
|||||||
// Index
|
// Index
|
||||||
export type Checkout = any
|
export type Checkout = any
|
||||||
|
|
||||||
|
export type CheckoutBody = any
|
||||||
|
|
||||||
export type CheckoutTypes = {
|
export type CheckoutTypes = {
|
||||||
card?: Card | CardFields
|
card?: Card | CardFields
|
||||||
address?: Address | AddressFields
|
address?: Address | AddressFields
|
||||||
@ -13,45 +15,43 @@ export type CheckoutTypes = {
|
|||||||
hasShipping?: boolean
|
hasShipping?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SubmitCheckoutHook<T extends CheckoutTypes = CheckoutTypes> = {
|
export type SubmitCheckoutHook = {
|
||||||
data: T
|
data: Checkout
|
||||||
input?: T
|
input?: CheckoutBody
|
||||||
fetcherInput: T
|
fetcherInput: CheckoutBody
|
||||||
body: { item: T }
|
body: { item: CheckoutBody }
|
||||||
actionInput: T
|
actionInput: CheckoutBody
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetCheckoutHook<T extends CheckoutTypes = CheckoutTypes> = {
|
export type GetCheckoutHook = {
|
||||||
data: T['checkout'] | null
|
data: Checkout | null | undefined
|
||||||
input: {}
|
input: {}
|
||||||
fetcherInput: { cartId?: string }
|
fetcherInput: { cartId?: string }
|
||||||
swrState: { isEmpty: boolean }
|
swrState: { isEmpty: boolean }
|
||||||
mutations: { submit: UseSubmitCheckout }
|
mutations: { submit: UseSubmitCheckout }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CheckoutHooks<T extends CheckoutTypes = CheckoutTypes> = {
|
export type CheckoutHooks = {
|
||||||
submitCheckout?: SubmitCheckoutHook<T>
|
submitCheckout?: SubmitCheckoutHook
|
||||||
getCheckout: GetCheckoutHook<T>
|
getCheckout: GetCheckoutHook
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetCheckoutHandler<T extends CheckoutTypes = CheckoutTypes> =
|
export type GetCheckoutHandler = GetCheckoutHook & {
|
||||||
GetCheckoutHook<T> & {
|
body: { cartId: string }
|
||||||
body: { cartId: string }
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SubmitCheckoutHandler<T extends CheckoutTypes = CheckoutTypes> =
|
|
||||||
SubmitCheckoutHook<T> & {
|
|
||||||
body: { cartId: string }
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CheckoutHandlers<T extends CheckoutTypes = CheckoutTypes> = {
|
|
||||||
getCheckout: GetCheckoutHandler<T>
|
|
||||||
submitCheckout?: SubmitCheckoutHandler<T>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CheckoutSchema<T extends CheckoutTypes = CheckoutTypes> = {
|
export type SubmitCheckoutHandler = SubmitCheckoutHook & {
|
||||||
|
body: { cartId: string }
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CheckoutHandlers = {
|
||||||
|
getCheckout: GetCheckoutHandler
|
||||||
|
submitCheckout?: SubmitCheckoutHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CheckoutSchema = {
|
||||||
endpoint: {
|
endpoint: {
|
||||||
options: {}
|
options: {}
|
||||||
handlers: CheckoutHandlers<T>
|
handlers: CheckoutHandlers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ export interface Measurement {
|
|||||||
*/
|
*/
|
||||||
value: number
|
value: number
|
||||||
/**
|
/**
|
||||||
* The measurement's unit.
|
* The measurement's unit, such as "KILOGRAMS", "GRAMS", "POUNDS" & "OOUNCES".
|
||||||
*/
|
*/
|
||||||
unit: 'KILOGRAMS' | 'GRAMS' | 'POUNDS' | 'OUNCES'
|
unit: 'KILOGRAMS' | 'GRAMS' | 'POUNDS' | 'OUNCES'
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,62 @@
|
|||||||
export interface Address {
|
export interface Address {
|
||||||
|
/**
|
||||||
|
* The unique identifier for the address.
|
||||||
|
*/
|
||||||
id: string
|
id: string
|
||||||
|
/**
|
||||||
|
* The customer's first name.
|
||||||
|
*/
|
||||||
mask: string
|
mask: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AddressFields {
|
export interface AddressFields {
|
||||||
|
/**
|
||||||
|
* The type of address.
|
||||||
|
* @example "billing, shipping"
|
||||||
|
*/
|
||||||
type: string
|
type: string
|
||||||
|
/**
|
||||||
|
* The customer's first name.
|
||||||
|
*/
|
||||||
firstName: string
|
firstName: string
|
||||||
|
/**
|
||||||
|
* The customer's last name.
|
||||||
|
*/
|
||||||
lastName: string
|
lastName: string
|
||||||
|
/**
|
||||||
|
* Company name.
|
||||||
|
*/
|
||||||
company: string
|
company: string
|
||||||
|
/**
|
||||||
|
* The customer's billing address street number.
|
||||||
|
*/
|
||||||
streetNumber: string
|
streetNumber: string
|
||||||
|
/**
|
||||||
|
* The customer's billing address apartment number.
|
||||||
|
*/
|
||||||
apartments: string
|
apartments: string
|
||||||
|
/**
|
||||||
|
* The customer's billing address zip code.
|
||||||
|
*/
|
||||||
zipCode: string
|
zipCode: string
|
||||||
|
/**
|
||||||
|
* The customer's billing address city.
|
||||||
|
*/
|
||||||
city: string
|
city: string
|
||||||
|
/**
|
||||||
|
* The customer's billing address country.
|
||||||
|
*/
|
||||||
country: string
|
country: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetAddressesHook = {
|
export interface GetAddressesHook {
|
||||||
data: Address[] | null
|
data: Address[] | null
|
||||||
input: {}
|
input: {}
|
||||||
fetcherInput: { cartId?: string }
|
fetcherInput: { cartId?: string }
|
||||||
swrState: { isEmpty: boolean }
|
swrState: { isEmpty: boolean }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AddItemHook = {
|
export interface AddItemHook {
|
||||||
data: Address
|
data: Address
|
||||||
input?: AddressFields
|
input?: AddressFields
|
||||||
fetcherInput: AddressFields
|
fetcherInput: AddressFields
|
||||||
@ -30,7 +64,7 @@ export type AddItemHook = {
|
|||||||
actionInput: AddressFields
|
actionInput: AddressFields
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UpdateItemHook = {
|
export interface UpdateItemHook {
|
||||||
data: Address | null
|
data: Address | null
|
||||||
input: { item?: AddressFields; wait?: number }
|
input: { item?: AddressFields; wait?: number }
|
||||||
fetcherInput: { itemId: string; item: AddressFields }
|
fetcherInput: { itemId: string; item: AddressFields }
|
||||||
@ -38,25 +72,21 @@ export type UpdateItemHook = {
|
|||||||
actionInput: AddressFields & { id: string }
|
actionInput: AddressFields & { id: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RemoveItemHook = {
|
export interface RemoveItemHook {
|
||||||
data: Address | null
|
data: Address | null | undefined
|
||||||
input: { item?: Address }
|
input: { item?: Address }
|
||||||
fetcherInput: { itemId: string }
|
fetcherInput: { itemId: string }
|
||||||
body: { itemId: string }
|
body: { itemId: string }
|
||||||
actionInput: { id: string }
|
actionInput: { id: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CustomerAddressHooks = {
|
export interface CustomerAddressHooks {
|
||||||
getAddresses: GetAddressesHook
|
getAddresses: GetAddressesHook
|
||||||
addItem: AddItemHook
|
addItem: AddItemHook
|
||||||
updateItem: UpdateItemHook
|
updateItem: UpdateItemHook
|
||||||
removeItem: RemoveItemHook
|
removeItem: RemoveItemHook
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AddressHandler = GetAddressesHook & {
|
|
||||||
body: { cartId?: string }
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AddItemHandler = AddItemHook & {
|
export type AddItemHandler = AddItemHook & {
|
||||||
body: { cartId: string }
|
body: { cartId: string }
|
||||||
}
|
}
|
||||||
|
@ -1,102 +1,156 @@
|
|||||||
export interface Card {
|
export interface Card {
|
||||||
|
/**
|
||||||
|
* Unique identifier for the card.
|
||||||
|
*/
|
||||||
id: string
|
id: string
|
||||||
|
/**
|
||||||
|
* Masked card number.
|
||||||
|
* @example "************4242"
|
||||||
|
*/
|
||||||
mask: string
|
mask: string
|
||||||
|
/**
|
||||||
|
* The card's brand.
|
||||||
|
* @example "Visa, Mastercard, etc."
|
||||||
|
*/
|
||||||
provider: string
|
provider: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fields required to create a new card.
|
||||||
|
*/
|
||||||
export interface CardFields {
|
export interface CardFields {
|
||||||
|
/**
|
||||||
|
* Name on the card.
|
||||||
|
*/
|
||||||
cardHolder: string
|
cardHolder: string
|
||||||
|
/**
|
||||||
|
* The card's number, consisting of 16 digits.
|
||||||
|
*/
|
||||||
cardNumber: string
|
cardNumber: string
|
||||||
|
/**
|
||||||
|
* The card's expiry month and year, in the format MM/YY.
|
||||||
|
* @example "01/25"
|
||||||
|
*/
|
||||||
cardExpireDate: string
|
cardExpireDate: string
|
||||||
|
/**
|
||||||
|
* The card's security code, consisting of 3 digits.
|
||||||
|
*/
|
||||||
cardCvc: string
|
cardCvc: string
|
||||||
|
/**
|
||||||
|
* The customer's first name.
|
||||||
|
*/
|
||||||
firstName: string
|
firstName: string
|
||||||
|
/**
|
||||||
|
* The customer's last name.
|
||||||
|
*/
|
||||||
lastName: string
|
lastName: string
|
||||||
|
/**
|
||||||
|
* Company name.
|
||||||
|
*/
|
||||||
company: string
|
company: string
|
||||||
|
/**
|
||||||
|
* The customer's billing address street number.
|
||||||
|
*/
|
||||||
streetNumber: string
|
streetNumber: string
|
||||||
|
/**
|
||||||
|
* The customer's billing address zip code.
|
||||||
|
*/
|
||||||
zipCode: string
|
zipCode: string
|
||||||
|
/**
|
||||||
|
* The customer's billing address city.
|
||||||
|
*/
|
||||||
city: string
|
city: string
|
||||||
|
/**
|
||||||
|
* The customer's billing address country.
|
||||||
|
*/
|
||||||
country: string
|
country: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CustomerCardTypes = {
|
/**
|
||||||
card?: Card
|
* Hook for getting a customer's cards.
|
||||||
fields: CardFields
|
*/
|
||||||
}
|
export interface GetCardsHook {
|
||||||
|
data: Card[] | null
|
||||||
export type GetCardsHook<T extends CustomerCardTypes = CustomerCardTypes> = {
|
|
||||||
data: T['card'][] | null
|
|
||||||
input: {}
|
input: {}
|
||||||
fetcherInput: { cartId?: string }
|
fetcherInput: { cartId?: string }
|
||||||
swrState: { isEmpty: boolean }
|
swrState: { isEmpty: boolean }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AddItemHook<T extends CustomerCardTypes = CustomerCardTypes> = {
|
/**
|
||||||
data: T['card']
|
* Hook for adding a card to a customer's account.
|
||||||
input?: T['fields']
|
*/
|
||||||
fetcherInput: T['fields']
|
export interface AddItemHook {
|
||||||
body: { item: T['fields'] }
|
data: Card
|
||||||
actionInput: T['fields']
|
input?: CardFields
|
||||||
|
fetcherInput: CardFields
|
||||||
|
body: { item: CardFields }
|
||||||
|
actionInput: CardFields
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UpdateItemHook<T extends CustomerCardTypes = CustomerCardTypes> = {
|
/**
|
||||||
data: T['card'] | null
|
* Hook for updating a card from a customer's account.
|
||||||
input: { item?: T['fields']; wait?: number }
|
*/
|
||||||
fetcherInput: { itemId: string; item: T['fields'] }
|
export interface UpdateItemHook {
|
||||||
body: { itemId: string; item: T['fields'] }
|
data: Card | null | undefined
|
||||||
actionInput: T['fields'] & { id: string }
|
input: { item?: CardFields; wait?: number }
|
||||||
|
fetcherInput: { itemId: string; item: CardFields }
|
||||||
|
body: { itemId: string; item: CardFields }
|
||||||
|
actionInput: CardFields & { id: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RemoveItemHook<T extends CustomerCardTypes = CustomerCardTypes> = {
|
/**
|
||||||
data: T['card'] | null
|
* Hook for removing a card from a customer's account.
|
||||||
input: { item?: T['card'] }
|
*/
|
||||||
|
export interface RemoveItemHook {
|
||||||
|
data: Card | null | undefined
|
||||||
|
input: { item?: Card }
|
||||||
fetcherInput: { itemId: string }
|
fetcherInput: { itemId: string }
|
||||||
body: { itemId: string }
|
body: { itemId: string }
|
||||||
actionInput: { id: string }
|
actionInput: { id: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CustomerCardHooks<T extends CustomerCardTypes = CustomerCardTypes> =
|
/**
|
||||||
{
|
* Hooks for add, update & remove items from the cart.
|
||||||
getCards: GetCardsHook<T>
|
*/
|
||||||
addItem: AddItemHook<T>
|
export interface CustomerCardHooks {
|
||||||
updateItem: UpdateItemHook<T>
|
getCards: GetCardsHook
|
||||||
removeItem: RemoveItemHook<T>
|
addItem: AddItemHook
|
||||||
}
|
updateItem: UpdateItemHook
|
||||||
|
removeItem: RemoveItemHook
|
||||||
export type CardsHandler<T extends CustomerCardTypes = CustomerCardTypes> =
|
|
||||||
GetCardsHook<T> & {
|
|
||||||
body: { cartId?: string }
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AddItemHandler<T extends CustomerCardTypes = CustomerCardTypes> =
|
|
||||||
AddItemHook<T> & {
|
|
||||||
body: { cartId: string }
|
|
||||||
}
|
|
||||||
|
|
||||||
export type UpdateItemHandler<T extends CustomerCardTypes = CustomerCardTypes> =
|
|
||||||
UpdateItemHook<T> & {
|
|
||||||
data: T['card']
|
|
||||||
body: { cartId: string }
|
|
||||||
}
|
|
||||||
|
|
||||||
export type RemoveItemHandler<T extends CustomerCardTypes = CustomerCardTypes> =
|
|
||||||
RemoveItemHook<T> & {
|
|
||||||
body: { cartId: string }
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CustomerCardHandlers<
|
|
||||||
T extends CustomerCardTypes = CustomerCardTypes
|
|
||||||
> = {
|
|
||||||
getCards: GetCardsHook<T>
|
|
||||||
addItem: AddItemHandler<T>
|
|
||||||
updateItem: UpdateItemHandler<T>
|
|
||||||
removeItem: RemoveItemHandler<T>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CustomerCardSchema<
|
/**
|
||||||
T extends CustomerCardTypes = CustomerCardTypes
|
* Customer card API handler
|
||||||
> = {
|
*/
|
||||||
|
export type AddItemHandler = AddItemHook & {
|
||||||
|
body: { cartId: string }
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateItemHandler = UpdateItemHook & {
|
||||||
|
data: Card
|
||||||
|
body: { cartId: string }
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RemoveItemHandler = RemoveItemHook & {
|
||||||
|
body: { cartId: string }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customer card API handlers.
|
||||||
|
*/
|
||||||
|
export type CustomerCardHandlers = {
|
||||||
|
getCards: GetCardsHook
|
||||||
|
addItem: AddItemHandler
|
||||||
|
updateItem: UpdateItemHandler
|
||||||
|
removeItem: RemoveItemHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customer card API endpoints.
|
||||||
|
*/
|
||||||
|
export type CustomerCardSchema = {
|
||||||
endpoint: {
|
endpoint: {
|
||||||
options: {}
|
options: {}
|
||||||
handlers: CustomerCardHandlers<T>
|
handlers: CustomerCardHandlers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,26 @@
|
|||||||
export type LoginBody = {
|
export interface LoginBody {
|
||||||
|
/**
|
||||||
|
* The user's email address.
|
||||||
|
*/
|
||||||
email: string
|
email: string
|
||||||
|
/**
|
||||||
|
* The user's password.
|
||||||
|
*/
|
||||||
password: string
|
password: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LoginTypes = {
|
export interface LoginHook {
|
||||||
body: LoginBody
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LoginHook<T extends LoginTypes = LoginTypes> = {
|
|
||||||
data: null
|
data: null
|
||||||
actionInput: LoginBody
|
actionInput: LoginBody
|
||||||
fetcherInput: LoginBody
|
fetcherInput: LoginBody
|
||||||
body: T['body']
|
body: LoginBody
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LoginSchema<T extends LoginTypes = LoginTypes> = {
|
export type LoginSchema = {
|
||||||
endpoint: {
|
endpoint: {
|
||||||
options: {}
|
options: {}
|
||||||
handlers: {
|
handlers: {
|
||||||
login: LoginHook<T>
|
login: LoginHook
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
export type LogoutTypes = {
|
export interface LogoutHook {
|
||||||
body: { redirectTo?: string }
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LogoutHook<T extends LogoutTypes = LogoutTypes> = {
|
|
||||||
data: null
|
data: null
|
||||||
body: T['body']
|
body: {
|
||||||
|
redirectTo?: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LogoutSchema<T extends LogoutTypes = LogoutTypes> = {
|
export type LogoutSchema = {
|
||||||
endpoint: {
|
endpoint: {
|
||||||
options: {}
|
options: {}
|
||||||
handlers: {
|
handlers: {
|
||||||
logout: LogoutHook<T>
|
logout: LogoutHook
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,43 @@
|
|||||||
// TODO: define this type
|
|
||||||
export type Page = {
|
export type Page = {
|
||||||
// ID of the Web page.
|
/**
|
||||||
|
* The unique identifier for the page.
|
||||||
|
*/
|
||||||
id: string
|
id: string
|
||||||
// Page name, as displayed on the storefront.
|
/**
|
||||||
|
* Page name, as displayed on the storefront.
|
||||||
|
*/
|
||||||
name: string
|
name: string
|
||||||
// Relative URL on the storefront for this page.
|
/**
|
||||||
|
* Relative URL on the storefront for this page.
|
||||||
|
*/
|
||||||
url?: string
|
url?: string
|
||||||
// HTML or variable that populates this page’s `<body>` element, in default/desktop view. Required in POST if page type is `raw`.
|
/**
|
||||||
|
* HTML or variable that populates this page’s `<body>` element, in default/desktop view. Required in POST if page type is `raw`.
|
||||||
|
*/
|
||||||
body: string
|
body: string
|
||||||
// If true, this page appears in the storefront’s navigation menu.
|
/**
|
||||||
|
* If true, this page appears in the storefront’s navigation menu.
|
||||||
|
*/
|
||||||
is_visible?: boolean
|
is_visible?: boolean
|
||||||
// Order in which this page should display on the storefront. (Lower integers specify earlier display.)
|
/**
|
||||||
|
* Order in which this page should display on the storefront. (Lower integers specify earlier display.)
|
||||||
|
*/
|
||||||
sort_order?: number
|
sort_order?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PageTypes = {
|
/**
|
||||||
page: Page
|
* Operation to get all pages.
|
||||||
|
*/
|
||||||
|
export type GetAllPagesOperation = {
|
||||||
|
data: { pages: Page[] }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetAllPagesOperation<T extends PageTypes = PageTypes> = {
|
export type GetPageOperation = {
|
||||||
data: { pages: T['page'][] }
|
data: { page?: Page }
|
||||||
}
|
variables: {
|
||||||
|
/**
|
||||||
export type GetPageOperation<T extends PageTypes = PageTypes> = {
|
* The unique identifier of the page.
|
||||||
data: { page?: T['page'] }
|
*/
|
||||||
variables: { id: string }
|
id: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,11 @@ export interface ProductPrice {
|
|||||||
*/
|
*/
|
||||||
value: number
|
value: number
|
||||||
/**
|
/**
|
||||||
* Currency code of the product price.
|
* The currency code for the price. This is a 3-letter ISO 4217 code.
|
||||||
*/
|
*/
|
||||||
currencyCode?: 'USD' | 'EUR' | 'ARS' | 'GBP' | string
|
currencyCode?: 'USD' | 'EUR' | 'ARS' | 'GBP' | string
|
||||||
/**
|
/**
|
||||||
* The retail price of the product. This can be used to mark a product as on sale, when `retailPrice` is higher than the price a.k.a `value`.
|
* The retail price of the product. This can be used to mark a product as on sale, when `retailPrice` is higher than the price a.k.a `value`.
|
||||||
*/
|
*/
|
||||||
retailPrice?: number
|
retailPrice?: number
|
||||||
}
|
}
|
||||||
@ -18,11 +18,11 @@ export interface ProductPrice {
|
|||||||
export interface ProductOption {
|
export interface ProductOption {
|
||||||
__typename?: 'MultipleChoiceOption'
|
__typename?: 'MultipleChoiceOption'
|
||||||
/**
|
/**
|
||||||
* The option's id.
|
* The unique identifier for the option.
|
||||||
*/
|
*/
|
||||||
id: string
|
id: string
|
||||||
/**
|
/**
|
||||||
* The option's name.
|
* The product option’s name.
|
||||||
*/
|
*/
|
||||||
displayName: string
|
displayName: string
|
||||||
/**
|
/**
|
||||||
@ -44,17 +44,17 @@ export interface ProductOptionValues {
|
|||||||
|
|
||||||
export interface ProductVariant {
|
export interface ProductVariant {
|
||||||
/**
|
/**
|
||||||
* The variant's id.
|
* The unique identifier for the variant.
|
||||||
*/
|
*/
|
||||||
id: string | number
|
id: string
|
||||||
/**
|
/**
|
||||||
* The SKU (stock keeping unit) associated with the product variant.
|
* The SKU (stock keeping unit) associated with the product variant.
|
||||||
*/
|
*/
|
||||||
sku: string
|
sku?: string
|
||||||
/**
|
/**
|
||||||
* The product variant’s name, or the product's name.
|
* The product variant’s name, or the product's name.
|
||||||
*/
|
*/
|
||||||
name: string
|
name?: string
|
||||||
/**
|
/**
|
||||||
* List of product options.
|
* List of product options.
|
||||||
*/
|
*/
|
||||||
@ -62,11 +62,11 @@ export interface ProductVariant {
|
|||||||
/**
|
/**
|
||||||
* The product variant’s price after all discounts are applied.
|
* The product variant’s price after all discounts are applied.
|
||||||
*/
|
*/
|
||||||
price: ProductPrice
|
price?: ProductPrice
|
||||||
/**
|
/**
|
||||||
* Product variant’s price, as quoted by the manufacturer/distributor.
|
* The retail price of the product. This can be used to mark a product as on sale, when `retailPrice` is higher than the `price`.
|
||||||
*/
|
*/
|
||||||
listPrice: ProductPrice
|
retailPrice?: ProductPrice
|
||||||
/**
|
/**
|
||||||
* Indicates if the variant is available for sale.
|
* Indicates if the variant is available for sale.
|
||||||
*/
|
*/
|
||||||
@ -83,11 +83,11 @@ export interface ProductVariant {
|
|||||||
|
|
||||||
export interface Product {
|
export interface Product {
|
||||||
/**
|
/**
|
||||||
* The product's id.
|
* The unique identifier for the product.
|
||||||
*/
|
*/
|
||||||
id: string
|
id: string
|
||||||
/**
|
/**
|
||||||
* The product's name.
|
* The name of the product.
|
||||||
*/
|
*/
|
||||||
name: string
|
name: string
|
||||||
/**
|
/**
|
||||||
@ -107,7 +107,7 @@ export interface Product {
|
|||||||
*/
|
*/
|
||||||
slug?: string
|
slug?: string
|
||||||
/**
|
/**
|
||||||
* A human-friendly string for the product, containing U.
|
* Relative URL on the storefront for the product.
|
||||||
*/
|
*/
|
||||||
path?: string
|
path?: string
|
||||||
/**
|
/**
|
||||||
@ -123,7 +123,7 @@ export interface Product {
|
|||||||
*/
|
*/
|
||||||
price: ProductPrice
|
price: ProductPrice
|
||||||
/**
|
/**
|
||||||
* The product's price.
|
* List of product's options.
|
||||||
*/
|
*/
|
||||||
options: ProductOption[]
|
options: ProductOption[]
|
||||||
/**
|
/**
|
||||||
@ -140,13 +140,14 @@ export interface SearchProductsBody {
|
|||||||
/**
|
/**
|
||||||
* The category ID to filter the products by.
|
* The category ID to filter the products by.
|
||||||
*/
|
*/
|
||||||
categoryId?: string | number
|
categoryId?: string
|
||||||
/**
|
/**
|
||||||
* The brand ID to filter the products by.
|
* The brand ID to filter the products by.
|
||||||
*/
|
*/
|
||||||
brandId?: string | number
|
brandId?: string
|
||||||
/**
|
/**
|
||||||
* The sort order to sort the products by.
|
* The sort key to sort the products by.
|
||||||
|
* @example 'trending-desc' | 'latest-desc' | 'price-asc' | 'price-desc'
|
||||||
*/
|
*/
|
||||||
sort?: string
|
sort?: string
|
||||||
/**
|
/**
|
||||||
|
@ -1,26 +1,34 @@
|
|||||||
export type SignupBody = {
|
export type SignupBody = {
|
||||||
|
/**
|
||||||
|
* The user's first name.
|
||||||
|
*/
|
||||||
firstName: string
|
firstName: string
|
||||||
|
/**
|
||||||
|
* The user's last name.
|
||||||
|
*/
|
||||||
lastName: string
|
lastName: string
|
||||||
|
/**
|
||||||
|
* The user's email address.
|
||||||
|
*/
|
||||||
email: string
|
email: string
|
||||||
|
/**
|
||||||
|
* The user's password.
|
||||||
|
*/
|
||||||
password: string
|
password: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SignupTypes = {
|
export interface SignupHook {
|
||||||
body: SignupBody
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SignupHook<T extends SignupTypes = SignupTypes> = {
|
|
||||||
data: null
|
data: null
|
||||||
body: T['body']
|
body: SignupBody
|
||||||
actionInput: T['body']
|
actionInput: SignupBody
|
||||||
fetcherInput: T['body']
|
fetcherInput: SignupBody
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SignupSchema<T extends SignupTypes = SignupTypes> = {
|
export type SignupSchema = {
|
||||||
endpoint: {
|
endpoint: {
|
||||||
options: {}
|
options: {}
|
||||||
handlers: {
|
handlers: {
|
||||||
signup: SignupHook<T>
|
signup: SignupHook
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,51 @@
|
|||||||
export type Category = {
|
export type Category = {
|
||||||
|
/**
|
||||||
|
* Unique identifier for the category.
|
||||||
|
*/
|
||||||
id: string
|
id: string
|
||||||
|
/**
|
||||||
|
* Name of the category.
|
||||||
|
*/
|
||||||
name: string
|
name: string
|
||||||
|
/**
|
||||||
|
* A human-friendly unique string for the category, automatically generated from its name.
|
||||||
|
* @example "t-shirts"
|
||||||
|
*/
|
||||||
slug: string
|
slug: string
|
||||||
|
/**
|
||||||
|
* Relative URL on the storefront for the category.
|
||||||
|
* @example /t-shirts
|
||||||
|
*/
|
||||||
path: string
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Brand = any
|
export type Brand = {
|
||||||
|
/**
|
||||||
export type SiteTypes = {
|
* Unique identifier for the brand.
|
||||||
category: Category
|
*/
|
||||||
brand: Brand
|
id: string
|
||||||
|
/**
|
||||||
|
* Name of the brand.
|
||||||
|
*/
|
||||||
|
name: string
|
||||||
|
/**
|
||||||
|
* A human-friendly unique string for the category, automatically generated from its name.
|
||||||
|
* @example "acme"
|
||||||
|
*/
|
||||||
|
slug: string
|
||||||
|
/**
|
||||||
|
* Relative URL on the storefront for this brand.
|
||||||
|
* @example "/acme"
|
||||||
|
*/
|
||||||
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetSiteInfoOperation<T extends SiteTypes = SiteTypes> = {
|
/**
|
||||||
|
* Operation to get site information. This includes categories and brands.
|
||||||
|
*/
|
||||||
|
export type GetSiteInfoOperation = {
|
||||||
data: {
|
data: {
|
||||||
categories: T['category'][]
|
categories: Category[]
|
||||||
brands: T['brand'][]
|
brands: Brand[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,60 +1,98 @@
|
|||||||
// TODO: define this type
|
import { Product } from './product'
|
||||||
export type Wishlist = any
|
|
||||||
|
|
||||||
export type WishlistItemBody = {
|
export interface WishlistItem {
|
||||||
variantId: string | number
|
/**
|
||||||
|
* The unique identifier for the item.
|
||||||
|
*/
|
||||||
|
id: string
|
||||||
|
/**
|
||||||
|
* The unique identifier for the product associated with the wishlist item.
|
||||||
|
*/
|
||||||
productId: string
|
productId: string
|
||||||
|
/**
|
||||||
|
* The unique identifier for the product variant associated with the wishlist item.
|
||||||
|
*/
|
||||||
|
variantId: string
|
||||||
|
/**
|
||||||
|
* The product associated with the wishlist item.
|
||||||
|
*/
|
||||||
|
product: Product
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WishlistTypes = {
|
export interface Wishlist {
|
||||||
wishlist: Wishlist
|
/**
|
||||||
itemBody: WishlistItemBody
|
* The unique identifier for the wishlist.
|
||||||
|
*/
|
||||||
|
id: string
|
||||||
|
/**
|
||||||
|
* List of items in the wishlist.
|
||||||
|
*/
|
||||||
|
items: WishlistItem[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Spree provider specific
|
||||||
|
*/
|
||||||
|
token?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetWishlistHook<T extends WishlistTypes = WishlistTypes> = {
|
export interface WishlistItemBody {
|
||||||
data: T['wishlist'] | null
|
/**
|
||||||
|
* The product's variant id.
|
||||||
|
*/
|
||||||
|
variantId: string
|
||||||
|
/**
|
||||||
|
* The product's ID.
|
||||||
|
*/
|
||||||
|
productId: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Spree provider specific
|
||||||
|
*/
|
||||||
|
wishlistToken?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetWishlistHook {
|
||||||
|
data: Wishlist | null | undefined
|
||||||
body: { includeProducts?: boolean }
|
body: { includeProducts?: boolean }
|
||||||
input: { includeProducts?: boolean }
|
input: { includeProducts?: boolean }
|
||||||
fetcherInput: { customerId: string; includeProducts?: boolean }
|
fetcherInput: { customerId: string; includeProducts?: boolean }
|
||||||
swrState: { isEmpty: boolean }
|
swrState: { isEmpty: boolean }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AddItemHook<T extends WishlistTypes = WishlistTypes> = {
|
export interface AddItemHook {
|
||||||
data: T['wishlist']
|
data: Wishlist | null | undefined
|
||||||
body: { item: T['itemBody'] }
|
body: { item: WishlistItemBody }
|
||||||
fetcherInput: { item: T['itemBody'] }
|
fetcherInput: { item: WishlistItemBody }
|
||||||
actionInput: T['itemBody']
|
actionInput: WishlistItemBody
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RemoveItemHook<T extends WishlistTypes = WishlistTypes> = {
|
export interface RemoveItemHook {
|
||||||
data: T['wishlist'] | null
|
data: Wishlist | null | undefined
|
||||||
body: { itemId: string }
|
body: { itemId: string; wishlistToken?: string }
|
||||||
fetcherInput: { itemId: string }
|
fetcherInput: { itemId: string; wishlistToken?: string }
|
||||||
actionInput: { id: string }
|
actionInput: { id: string }
|
||||||
input: { wishlist?: { includeProducts?: boolean } }
|
input: { wishlist?: { includeProducts?: boolean } }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WishlistSchema<T extends WishlistTypes = WishlistTypes> = {
|
export type WishlistSchema = {
|
||||||
endpoint: {
|
endpoint: {
|
||||||
options: {}
|
options: {}
|
||||||
handlers: {
|
handlers: {
|
||||||
getWishlist: GetWishlistHook<T> & {
|
getWishlist: GetWishlistHook & {
|
||||||
data: T['wishlist'] | null
|
data: Wishlist | null
|
||||||
body: { customerToken?: string }
|
body: { customerToken?: string }
|
||||||
}
|
}
|
||||||
addItem: AddItemHook<T> & {
|
addItem: AddItemHook & {
|
||||||
body: { customerToken?: string }
|
body: { customerToken?: string }
|
||||||
}
|
}
|
||||||
removeItem: RemoveItemHook<T> & {
|
removeItem: RemoveItemHook & {
|
||||||
body: { customerToken?: string }
|
body: { customerToken?: string }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetCustomerWishlistOperation<
|
export interface GetCustomerWishlistOperation {
|
||||||
T extends WishlistTypes = WishlistTypes
|
data: { wishlist?: Wishlist }
|
||||||
> = {
|
|
||||||
data: { wishlist?: T['wishlist'] }
|
|
||||||
variables: { customerId: string }
|
variables: { customerId: string }
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import type { AddItemHook } from '../types/wishlist'
|
|||||||
import type { Provider } from '..'
|
import type { Provider } from '..'
|
||||||
|
|
||||||
export type UseAddItem<
|
export type UseAddItem<
|
||||||
H extends MutationHook<AddItemHook<any>> = MutationHook<AddItemHook>
|
H extends MutationHook<AddItemHook> = MutationHook<AddItemHook>
|
||||||
> = ReturnType<H['useHook']>
|
> = ReturnType<H['useHook']>
|
||||||
|
|
||||||
export const fetcher = mutationFetcher
|
export const fetcher = mutationFetcher
|
||||||
|
@ -5,7 +5,7 @@ import type { RemoveItemHook } from '../types/wishlist'
|
|||||||
import type { Provider } from '..'
|
import type { Provider } from '..'
|
||||||
|
|
||||||
export type UseRemoveItem<
|
export type UseRemoveItem<
|
||||||
H extends MutationHook<RemoveItemHook<any>> = MutationHook<RemoveItemHook>
|
H extends MutationHook<RemoveItemHook> = MutationHook<RemoveItemHook>
|
||||||
> = ReturnType<H['useHook']>
|
> = ReturnType<H['useHook']>
|
||||||
|
|
||||||
export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher
|
export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher
|
||||||
|
@ -5,7 +5,7 @@ import type { GetWishlistHook } from '../types/wishlist'
|
|||||||
import type { Provider } from '..'
|
import type { Provider } from '..'
|
||||||
|
|
||||||
export type UseWishlist<
|
export type UseWishlist<
|
||||||
H extends SWRHook<GetWishlistHook<any>> = SWRHook<GetWishlistHook>
|
H extends SWRHook<GetWishlistHook> = SWRHook<GetWishlistHook>
|
||||||
> = ReturnType<H['useHook']>
|
> = ReturnType<H['useHook']>
|
||||||
|
|
||||||
export const fetcher: HookFetcherFn<GetWishlistHook> = SWRFetcher
|
export const fetcher: HookFetcherFn<GetWishlistHook> = SWRFetcher
|
||||||
|
@ -1,25 +1,17 @@
|
|||||||
import type { AddItemHook } from '@vercel/commerce/types/customer/address'
|
import useAddItem, {
|
||||||
import type { MutationHook } from '@vercel/commerce/utils/types'
|
UseAddItem,
|
||||||
import { useCallback } from 'react'
|
} from '@vercel/commerce/customer/address/use-add-item'
|
||||||
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/address/use-add-item'
|
import { MutationHook } from '@vercel/commerce/utils/types'
|
||||||
import { useCheckoutContext } from '@components/checkout/context'
|
|
||||||
|
|
||||||
export default useAddItem as UseAddItem<typeof handler>
|
export default useAddItem as UseAddItem<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<any> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
query: '_',
|
query: '',
|
||||||
method: '_',
|
|
||||||
},
|
},
|
||||||
useHook: () =>
|
async fetcher({ input, options, fetch }) {},
|
||||||
function useHook() {
|
useHook:
|
||||||
const { setAddressFields } = useCheckoutContext()
|
({ fetch }) =>
|
||||||
return useCallback(
|
() =>
|
||||||
async function addItem(input) {
|
async () => ({}),
|
||||||
setAddressFields(input)
|
|
||||||
return undefined
|
|
||||||
},
|
|
||||||
[setAddressFields]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,17 @@
|
|||||||
import type { AddItemHook } from '@vercel/commerce/types/customer/card'
|
import useAddItem, {
|
||||||
import type { MutationHook } from '@vercel/commerce/utils/types'
|
UseAddItem,
|
||||||
import { useCallback } from 'react'
|
} from '@vercel/commerce/customer/card/use-add-item'
|
||||||
import useAddItem, { UseAddItem } from '@vercel/commerce/customer/card/use-add-item'
|
import { MutationHook } from '@vercel/commerce/utils/types'
|
||||||
import { useCheckoutContext } from '@components/checkout/context'
|
|
||||||
|
|
||||||
export default useAddItem as UseAddItem<typeof handler>
|
export default useAddItem as UseAddItem<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<any> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '_',
|
query: '',
|
||||||
method: '_',
|
|
||||||
},
|
},
|
||||||
useHook: () =>
|
async fetcher({ input, options, fetch }) {},
|
||||||
function useHook() {
|
useHook:
|
||||||
const { setCardFields } = useCheckoutContext()
|
({ fetch }) =>
|
||||||
return useCallback(
|
() =>
|
||||||
async function addItem(input) {
|
async () => ({}),
|
||||||
setCardFields(input)
|
|
||||||
return undefined
|
|
||||||
},
|
|
||||||
[setCardFields]
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1 @@
|
|||||||
import { LoginBody, LoginTypes } from '@vercel/commerce/types/login'
|
|
||||||
export * from '@vercel/commerce/types/login'
|
export * from '@vercel/commerce/types/login'
|
||||||
|
|
||||||
export type LoginHook<T extends LoginTypes = LoginTypes> = {
|
|
||||||
data: null
|
|
||||||
actionInput: LoginBody
|
|
||||||
fetcherInput: LoginBody
|
|
||||||
body: T['body']
|
|
||||||
}
|
|
||||||
|
@ -26,6 +26,7 @@ function normalizeVariants(
|
|||||||
if (!Array.isArray(variants)) return []
|
if (!Array.isArray(variants)) return []
|
||||||
return variants?.map((variant) => ({
|
return variants?.map((variant) => ({
|
||||||
id: variant.id,
|
id: variant.id,
|
||||||
|
sku: variant.sku ?? variant.id,
|
||||||
options: Object.entries(variant.options).map(
|
options: Object.entries(variant.options).map(
|
||||||
([variantGroupId, variantOptionId]) => {
|
([variantGroupId, variantOptionId]) => {
|
||||||
const variantGroupFromId = variantGroups.find(
|
const variantGroupFromId = variantGroups.find(
|
||||||
|
@ -1,16 +1,6 @@
|
|||||||
|
import type { Wishlist } from '@vercel/commerce/types/wishlist'
|
||||||
import { HookFetcher } from '@vercel/commerce/utils/types'
|
import { HookFetcher } from '@vercel/commerce/utils/types'
|
||||||
|
|
||||||
export type Wishlist = {
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
product_id: number
|
|
||||||
variant_id: number
|
|
||||||
id: number
|
|
||||||
product: any
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UseWishlistOptions {
|
export interface UseWishlistOptions {
|
||||||
includeProducts?: boolean
|
includeProducts?: boolean
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,29 @@
|
|||||||
import type { OperationContext } from '@vercel/commerce/api/operations'
|
import type { OperationContext } from '@vercel/commerce/api/operations'
|
||||||
import type { KiboCommerceConfig } from '../index'
|
import type { KiboCommerceConfig } from '../index'
|
||||||
import { getAllPagesQuery } from '../queries/get-all-pages-query'
|
import { getAllPagesQuery } from '../queries/get-all-pages-query'
|
||||||
import { GetPagesQueryParams } from "../../types/page";
|
|
||||||
import { normalizePage } from '../../lib/normalize'
|
import { normalizePage } from '../../lib/normalize'
|
||||||
|
|
||||||
export type GetAllPagesResult<
|
export type GetAllPagesResult<T extends { pages: any[] } = { pages: any[] }> = T
|
||||||
T extends { pages: any[] } = { pages: any[] }
|
|
||||||
> = T
|
|
||||||
|
|
||||||
export default function getAllPagesOperation({
|
export default function getAllPagesOperation({
|
||||||
commerce,
|
commerce,
|
||||||
}: OperationContext<any>) {
|
}: OperationContext<any>) {
|
||||||
|
|
||||||
async function getAllPages({
|
async function getAllPages({
|
||||||
query = getAllPagesQuery,
|
query = getAllPagesQuery,
|
||||||
config,
|
config,
|
||||||
variables,
|
|
||||||
}: {
|
}: {
|
||||||
url?: string
|
url?: string
|
||||||
config?: Partial<KiboCommerceConfig>
|
config?: Partial<KiboCommerceConfig>
|
||||||
variables?: GetPagesQueryParams
|
|
||||||
preview?: boolean
|
preview?: boolean
|
||||||
query?: string
|
query?: string
|
||||||
} = {}): Promise<GetAllPagesResult> {
|
} = {}): Promise<GetAllPagesResult> {
|
||||||
const cfg = commerce.getConfig(config)
|
const cfg = commerce.getConfig(config)
|
||||||
variables = {
|
const variables = {
|
||||||
documentListName: cfg.documentListName
|
documentListName: cfg.documentListName,
|
||||||
}
|
}
|
||||||
const { data } = await cfg.fetch(query, { variables });
|
const { data } = await cfg.fetch(query, { variables })
|
||||||
|
|
||||||
const pages = data.documentListDocuments.items.map(normalizePage);
|
const pages = data.documentListDocuments.items.map(normalizePage)
|
||||||
|
|
||||||
return { pages }
|
return { pages }
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,11 @@ import type {
|
|||||||
OperationContext,
|
OperationContext,
|
||||||
OperationOptions,
|
OperationOptions,
|
||||||
} from '@vercel/commerce/api/operations'
|
} from '@vercel/commerce/api/operations'
|
||||||
import type {
|
import type { GetCustomerWishlistOperation } from '@vercel/commerce/types/wishlist'
|
||||||
GetCustomerWishlistOperation,
|
|
||||||
Wishlist,
|
|
||||||
} from '@vercel/commerce/types/wishlist'
|
|
||||||
// import type { RecursivePartial, RecursiveRequired } from '../utils/types'
|
// import type { RecursivePartial, RecursiveRequired } from '../utils/types'
|
||||||
import { KiboCommerceConfig } from '..'
|
import { KiboCommerceConfig } from '..'
|
||||||
// import getAllProducts, { ProductEdge } from './get-all-products'
|
// import getAllProducts, { ProductEdge } from './get-all-products'
|
||||||
import {getCustomerWishlistQuery} from '../queries/get-customer-wishlist-query'
|
import { getCustomerWishlistQuery } from '../queries/get-customer-wishlist-query'
|
||||||
|
|
||||||
export default function getCustomerWishlistOperation({
|
export default function getCustomerWishlistOperation({
|
||||||
commerce,
|
commerce,
|
||||||
@ -40,14 +37,15 @@ export default function getCustomerWishlistOperation({
|
|||||||
config?: KiboCommerceConfig
|
config?: KiboCommerceConfig
|
||||||
includeProducts?: boolean
|
includeProducts?: boolean
|
||||||
}): Promise<T['data']> {
|
}): Promise<T['data']> {
|
||||||
let customerWishlist ={}
|
let customerWishlist = {}
|
||||||
try {
|
try {
|
||||||
|
|
||||||
config = commerce.getConfig(config)
|
config = commerce.getConfig(config)
|
||||||
const result= await config?.fetch(getCustomerWishlistQuery,{variables})
|
const result = await config?.fetch(getCustomerWishlistQuery, {
|
||||||
customerWishlist= result?.data?.customerWishlist;
|
variables,
|
||||||
} catch(e) {
|
})
|
||||||
customerWishlist= {}
|
customerWishlist = result?.data?.customerWishlist
|
||||||
|
} catch (e) {
|
||||||
|
customerWishlist = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { wishlist: customerWishlist as any }
|
return { wishlist: customerWishlist as any }
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
import type {
|
import type { OperationContext } from '@vercel/commerce/api/operations'
|
||||||
OperationContext,
|
|
||||||
} from '@vercel/commerce/api/operations'
|
|
||||||
import type { KiboCommerceConfig, KiboCommerceProvider } from '..'
|
import type { KiboCommerceConfig, KiboCommerceProvider } from '..'
|
||||||
import { normalizePage } from '../../lib/normalize'
|
import { normalizePage } from '../../lib/normalize'
|
||||||
import { getPageQuery } from '../queries/get-page-query'
|
import { getPageQuery } from '../queries/get-page-query'
|
||||||
import type { Page, GetPageQueryParams } from "../../types/page";
|
import type { Page, GetPageOperation } from '../../types/page'
|
||||||
import type { Document } from '../../../schema'
|
import type { Document } from '../../../schema'
|
||||||
|
|
||||||
export default function getPageOperation({
|
export default function getPageOperation({ commerce }: OperationContext<any>) {
|
||||||
commerce,
|
|
||||||
}: OperationContext<any>) {
|
|
||||||
async function getPage<T extends Page>({
|
async function getPage<T extends Page>({
|
||||||
url,
|
url,
|
||||||
variables,
|
variables,
|
||||||
@ -17,18 +13,21 @@ export default function getPageOperation({
|
|||||||
preview,
|
preview,
|
||||||
}: {
|
}: {
|
||||||
url?: string
|
url?: string
|
||||||
variables: GetPageQueryParams
|
variables: GetPageOperation['variables']
|
||||||
config?: Partial<KiboCommerceConfig>
|
config?: Partial<KiboCommerceConfig>
|
||||||
preview?: boolean
|
preview?: boolean
|
||||||
}): Promise<any> {
|
}): Promise<any> {
|
||||||
// RecursivePartial forces the method to check for every prop in the data, which is
|
// RecursivePartial forces the method to check for every prop in the data, which is
|
||||||
// required in case there's a custom `url`
|
// required in case there's a custom `url`
|
||||||
const cfg = commerce.getConfig(config)
|
const cfg = commerce.getConfig(config)
|
||||||
const pageVariables = { documentListName: cfg.documentListName, filter: `id eq ${variables.id}` }
|
const pageVariables = {
|
||||||
|
documentListName: cfg.documentListName,
|
||||||
|
filter: `id eq ${variables.id}`,
|
||||||
|
}
|
||||||
|
|
||||||
const { data } = await cfg.fetch(getPageQuery, { variables: pageVariables })
|
const { data } = await cfg.fetch(getPageQuery, { variables: pageVariables })
|
||||||
|
|
||||||
const firstPage = data.documentListDocuments.items?.[0];
|
const firstPage = data.documentListDocuments.items?.[0]
|
||||||
const page = firstPage as Document
|
const page = firstPage as Document
|
||||||
if (preview || page?.properties?.is_visible) {
|
if (preview || page?.properties?.is_visible) {
|
||||||
return { page: normalizePage(page as any) }
|
return { page: normalizePage(page as any) }
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import type { PrCategory, CustomerAccountInput, Document } from '../../schema'
|
import type { PrCategory, CustomerAccountInput, Document } from '../../schema'
|
||||||
import { Page } from '../types/page';
|
import { Page } from '../types/page'
|
||||||
import { Customer } from '../types/customer'
|
import { Customer } from '../types/customer'
|
||||||
|
import { WishlistItem } from '@vercel/commerce/types/wishlist'
|
||||||
|
|
||||||
export function normalizeProduct(productNode: any, config: any): any {
|
export function normalizeProduct(productNode: any, config: any): any {
|
||||||
const product = {
|
const product = {
|
||||||
@ -57,7 +58,7 @@ export function normalizePage(page: Document): Page {
|
|||||||
url: page.properties.url,
|
url: page.properties.url,
|
||||||
body: page.properties.body,
|
body: page.properties.body,
|
||||||
is_visible: page.properties.is_visible,
|
is_visible: page.properties.is_visible,
|
||||||
sort_order: page.properties.sort_order
|
sort_order: page.properties.sort_order,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ export function normalizeCustomer(customer: CustomerAccountInput): Customer {
|
|||||||
lastName: customer.lastName,
|
lastName: customer.lastName,
|
||||||
email: customer.emailAddress,
|
email: customer.emailAddress,
|
||||||
userName: customer.userName,
|
userName: customer.userName,
|
||||||
isAnonymous: customer.isAnonymous
|
isAnonymous: customer.isAnonymous,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,11 +134,13 @@ export function normalizeCategory(category: PrCategory): any {
|
|||||||
export function normalizeWishlistItem(
|
export function normalizeWishlistItem(
|
||||||
item: any,
|
item: any,
|
||||||
config: any,
|
config: any,
|
||||||
includeProducts=false
|
includeProducts = false
|
||||||
): any {
|
): WishlistItem {
|
||||||
if (includeProducts) {
|
if (includeProducts) {
|
||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
|
productId: String(item.product.productCode),
|
||||||
|
variantId: item.product.variationProductCode,
|
||||||
product: getProuducts(item, config),
|
product: getProuducts(item, config),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,35 +1,16 @@
|
|||||||
import * as Core from '@vercel/commerce/types/page'
|
|
||||||
export type Maybe<T> = T | null
|
|
||||||
export type Scalars = {
|
|
||||||
ID: string
|
|
||||||
String: string
|
|
||||||
Boolean: boolean
|
|
||||||
Int: number
|
|
||||||
Float: number
|
|
||||||
/** The `AnyScalar` type allows any scalar value by examining the input and passing the serialize, parseValue, and parseLiteral operations to their respective types. */
|
|
||||||
AnyScalar: any
|
|
||||||
/** DateTime custom scalar type */
|
|
||||||
DateTime: any
|
|
||||||
/** Object custom scalar type */
|
|
||||||
Object: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export * from '@vercel/commerce/types/page'
|
export * from '@vercel/commerce/types/page'
|
||||||
|
|
||||||
export type Page = Core.Page
|
export type Maybe<T> = T | null
|
||||||
|
export type Scalars = {
|
||||||
export type PageTypes = {
|
ID: string
|
||||||
page: Page
|
String: string
|
||||||
|
Boolean: boolean
|
||||||
|
Int: number
|
||||||
|
Float: number
|
||||||
|
/** The `AnyScalar` type allows any scalar value by examining the input and passing the serialize, parseValue, and parseLiteral operations to their respective types. */
|
||||||
|
AnyScalar: any
|
||||||
|
/** DateTime custom scalar type */
|
||||||
|
DateTime: any
|
||||||
|
/** Object custom scalar type */
|
||||||
|
Object: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetPagesQueryParams = {
|
|
||||||
documentListName: Maybe<Scalars["String"]>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GetPageQueryParams = {
|
|
||||||
id: Maybe<Scalars["String"]>
|
|
||||||
documentListName: Maybe<Scalars["String"]>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GetAllPagesOperation = Core.GetAllPagesOperation<PageTypes>
|
|
||||||
export type GetPageOperation = Core.GetPageOperation<PageTypes>
|
|
||||||
|
@ -4,9 +4,7 @@ import { GetProductOperation } from '@vercel/commerce/types/product'
|
|||||||
import data from '../../data.json'
|
import data from '../../data.json'
|
||||||
import type { OperationContext } from '@vercel/commerce/api/operations'
|
import type { OperationContext } from '@vercel/commerce/api/operations'
|
||||||
|
|
||||||
export default function getProductOperation({
|
export default function getProductOperation(_p: OperationContext<any>) {
|
||||||
commerce,
|
|
||||||
}: OperationContext<any>) {
|
|
||||||
async function getProduct<T extends GetProductOperation>({
|
async function getProduct<T extends GetProductOperation>({
|
||||||
query = '',
|
query = '',
|
||||||
variables,
|
variables,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { OperationContext } from '@vercel/commerce/api/operations'
|
import { OperationContext } from '@vercel/commerce/api/operations'
|
||||||
import { Category } from '@vercel/commerce/types/site'
|
import { Category, GetSiteInfoOperation } from '@vercel/commerce/types/site'
|
||||||
import { LocalConfig } from '../index'
|
import { LocalConfig } from '../index'
|
||||||
|
|
||||||
export type GetSiteInfoResult<
|
export type GetSiteInfoResult<
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
"path": "/new-short-sleeve-t-shirt",
|
"path": "/new-short-sleeve-t-shirt",
|
||||||
"slug": "new-short-sleeve-t-shirt",
|
"slug": "new-short-sleeve-t-shirt",
|
||||||
"price": { "value": 25, "currencyCode": "USD" },
|
"price": { "value": 25, "currencyCode": "USD" },
|
||||||
"descriptionHtml": "<p><span>Show off your love for Next.js and Vercel with this unique, </span><strong>limited edition</strong><span> t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last – only 200 of these shirts will be made! </span><strong>All proceeds will be donated to charity.</strong></p>",
|
"description": "Show off your love for Next.js and Vercel with this unique, limited edition t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last - only 200 of these shirts will be made! All proceeds will be donated to charity.",
|
||||||
|
"descriptionHtml": "<p><span>Show off your love for Next.js and Vercel with this unique, </span><strong>limited edition</strong><span> t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last - only 200 of these shirts will be made! </span><strong>All proceeds will be donated to charity.</strong></p>",
|
||||||
"images": [
|
"images": [
|
||||||
{
|
{
|
||||||
"url": "/assets/drop-shirt-0.png",
|
"url": "/assets/drop-shirt-0.png",
|
||||||
@ -31,6 +32,8 @@
|
|||||||
"variants": [
|
"variants": [
|
||||||
{
|
{
|
||||||
"id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjAss=",
|
"id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjAss=",
|
||||||
|
"name": "New Short Sleeve T-Shirt",
|
||||||
|
"sku": "new-short-sleeve-t-shirt",
|
||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
"__typename": "MultipleChoiceOption",
|
"__typename": "MultipleChoiceOption",
|
||||||
@ -80,6 +83,7 @@
|
|||||||
"path": "/lightweight-jacket",
|
"path": "/lightweight-jacket",
|
||||||
"slug": "lightweight-jacket",
|
"slug": "lightweight-jacket",
|
||||||
"price": { "value": 249.99, "currencyCode": "USD" },
|
"price": { "value": 249.99, "currencyCode": "USD" },
|
||||||
|
"description": "Show off your love for Next.js and Vercel with this unique, limited edition t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last - only 200 of these shirts will be made! All proceeds will be donated to charity.",
|
||||||
"descriptionHtml": "<p><span>Show off your love for Next.js and Vercel with this unique, </span><strong>limited edition</strong><span> t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last – only 200 of these shirts will be made! </span><strong>All proceeds will be donated to charity.</strong></p>",
|
"descriptionHtml": "<p><span>Show off your love for Next.js and Vercel with this unique, </span><strong>limited edition</strong><span> t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last – only 200 of these shirts will be made! </span><strong>All proceeds will be donated to charity.</strong></p>",
|
||||||
"images": [
|
"images": [
|
||||||
{
|
{
|
||||||
@ -104,6 +108,8 @@
|
|||||||
"variants": [
|
"variants": [
|
||||||
{
|
{
|
||||||
"id": "Z2lkOid8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjAss=",
|
"id": "Z2lkOid8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjAss=",
|
||||||
|
"name": "Lightweight Jacket",
|
||||||
|
"sku": "lightweight-jacket",
|
||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
"__typename": "MultipleChoiceOption",
|
"__typename": "MultipleChoiceOption",
|
||||||
@ -153,6 +159,7 @@
|
|||||||
"path": "/shirt",
|
"path": "/shirt",
|
||||||
"slug": "shirt",
|
"slug": "shirt",
|
||||||
"price": { "value": 25, "currencyCode": "USD" },
|
"price": { "value": 25, "currencyCode": "USD" },
|
||||||
|
"description": "Show off your love for Next.js and Vercel with this unique, limited edition t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last - only 200 of these shirts will be made! All proceeds will be donated to charity.",
|
||||||
"descriptionHtml": "<p><span>Show off your love for Next.js and Vercel with this unique, </span><strong>limited edition</strong><span> t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last – only 200 of these shirts will be made! </span><strong>All proceeds will be donated to charity.</strong></p>",
|
"descriptionHtml": "<p><span>Show off your love for Next.js and Vercel with this unique, </span><strong>limited edition</strong><span> t-shirt. This design is part of a limited run, numbered drop at the June 2021 Next.js Conf. It features a unique, handcrafted triangle design. Get it while supplies last – only 200 of these shirts will be made! </span><strong>All proceeds will be donated to charity.</strong></p>",
|
||||||
"images": [
|
"images": [
|
||||||
{
|
{
|
||||||
@ -189,6 +196,8 @@
|
|||||||
"variants": [
|
"variants": [
|
||||||
{
|
{
|
||||||
"id": "Z2lkOi8vc2hvcGlmeS9Qcms9kdWN0LzU0NDczMjUwMjQ0MjAss=",
|
"id": "Z2lkOi8vc2hvcGlmeS9Qcms9kdWN0LzU0NDczMjUwMjQ0MjAss=",
|
||||||
|
"name": "Shirt",
|
||||||
|
"sku": "shirt",
|
||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
"__typename": "MultipleChoiceOption",
|
"__typename": "MultipleChoiceOption",
|
||||||
|
@ -1,19 +1,8 @@
|
|||||||
import { HookFetcher } from '@vercel/commerce/utils/types'
|
import { HookFetcher } from '@vercel/commerce/utils/types'
|
||||||
import type { Product } from '@vercel/commerce/types/product'
|
import { Wishlist } from '@vercel/commerce/types/wishlist'
|
||||||
|
|
||||||
const defaultOpts = {}
|
const defaultOpts = {}
|
||||||
|
|
||||||
export type Wishlist = {
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
product_id: number
|
|
||||||
variant_id: number
|
|
||||||
id: number
|
|
||||||
product: Product
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UseWishlistOptions {
|
export interface UseWishlistOptions {
|
||||||
includeProducts?: boolean
|
includeProducts?: boolean
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import * as Core from '@vercel/commerce/types/cart'
|
|
||||||
|
|
||||||
export * from '@vercel/commerce/types/cart'
|
export * from '@vercel/commerce/types/cart'
|
||||||
|
|
||||||
export interface OrdercloudCart {
|
export interface OrdercloudCart {
|
||||||
@ -97,30 +95,3 @@ export interface OrdercloudLineItem {
|
|||||||
Specs: []
|
Specs: []
|
||||||
xp: null
|
xp: null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extend core cart types
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type Cart = Core.Cart & {
|
|
||||||
lineItems: Core.LineItem[]
|
|
||||||
url?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CartTypes = Core.CartTypes
|
|
||||||
|
|
||||||
export type CartHooks = Core.CartHooks<CartTypes>
|
|
||||||
|
|
||||||
export type GetCartHook = CartHooks['getCart']
|
|
||||||
export type AddItemHook = CartHooks['addItem']
|
|
||||||
export type UpdateItemHook = CartHooks['updateItem']
|
|
||||||
export type RemoveItemHook = CartHooks['removeItem']
|
|
||||||
|
|
||||||
export type CartSchema = Core.CartSchema<CartTypes>
|
|
||||||
|
|
||||||
export type CartHandlers = Core.CartHandlers<CartTypes>
|
|
||||||
|
|
||||||
export type GetCartHandler = CartHandlers['getCart']
|
|
||||||
export type AddItemHandler = CartHandlers['addItem']
|
|
||||||
export type UpdateItemHandler = CartHandlers['updateItem']
|
|
||||||
export type RemoveItemHandler = CartHandlers['removeItem']
|
|
||||||
|
@ -1,4 +1 @@
|
|||||||
import * as Core from '@vercel/commerce/types/checkout'
|
export * from '@vercel/commerce/types/checkout'
|
||||||
|
|
||||||
export type CheckoutTypes = Core.CheckoutTypes
|
|
||||||
export type CheckoutSchema = Core.CheckoutSchema<CheckoutTypes>
|
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
import * as Core from '@vercel/commerce/types/customer/address'
|
export * from '@vercel/commerce/types/customer/address'
|
||||||
|
|
||||||
export type CustomerAddressTypes = Core.CustomerAddressTypes
|
|
||||||
export type CustomerAddressSchema =
|
|
||||||
Core.CustomerAddressSchema<CustomerAddressTypes>
|
|
||||||
|
|
||||||
export interface OrdercloudAddress {
|
export interface OrdercloudAddress {
|
||||||
ID: string
|
ID: string
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
import * as Core from '@vercel/commerce/types/customer/card'
|
export * from '@vercel/commerce/types/customer/card'
|
||||||
|
|
||||||
export type CustomerCardTypes = Core.CustomerCardTypes
|
|
||||||
export type CustomerCardSchema = Core.CustomerCardSchema<CustomerCardTypes>
|
|
||||||
|
|
||||||
export interface OredercloudCreditCard {
|
export interface OredercloudCreditCard {
|
||||||
ID: string
|
ID: string
|
||||||
|
@ -8,6 +8,7 @@ export function normalize(product: RawProduct): Product {
|
|||||||
name: product.Name,
|
name: product.Name,
|
||||||
description: product.Description,
|
description: product.Description,
|
||||||
slug: product.ID,
|
slug: product.ID,
|
||||||
|
path: `/${product.ID}`,
|
||||||
images: product.xp.Images,
|
images: product.xp.Images,
|
||||||
price: {
|
price: {
|
||||||
value: product.xp.Price,
|
value: product.xp.Price,
|
||||||
@ -16,6 +17,8 @@ export function normalize(product: RawProduct): Product {
|
|||||||
variants: product.xp.Variants?.length
|
variants: product.xp.Variants?.length
|
||||||
? product.xp.Variants.map((variant) => ({
|
? product.xp.Variants.map((variant) => ({
|
||||||
id: variant.ID,
|
id: variant.ID,
|
||||||
|
sku: variant.ID,
|
||||||
|
name: product.Name,
|
||||||
options: variant.Specs.map((spec) => ({
|
options: variant.Specs.map((spec) => ({
|
||||||
id: spec.SpecID,
|
id: spec.SpecID,
|
||||||
__typename: 'MultipleChoiceOption',
|
__typename: 'MultipleChoiceOption',
|
||||||
@ -27,12 +30,7 @@ export function normalize(product: RawProduct): Product {
|
|||||||
],
|
],
|
||||||
})),
|
})),
|
||||||
}))
|
}))
|
||||||
: [
|
: [],
|
||||||
{
|
|
||||||
id: '',
|
|
||||||
options: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: product.xp.Specs?.length
|
options: product.xp.Specs?.length
|
||||||
? product.xp.Specs.map((spec) => ({
|
? product.xp.Specs.map((spec) => ({
|
||||||
id: spec.ID,
|
id: spec.ID,
|
||||||
|
@ -1,19 +1,8 @@
|
|||||||
import { HookFetcher } from '@vercel/commerce/utils/types'
|
import { HookFetcher } from '@vercel/commerce/utils/types'
|
||||||
import type { Product } from '@vercel/commerce/types/product'
|
import type { Wishlist } from '@vercel/commerce/types/wishlist'
|
||||||
|
|
||||||
const defaultOpts = {}
|
const defaultOpts = {}
|
||||||
|
|
||||||
export type Wishlist = {
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
product_id: number
|
|
||||||
variant_id: number
|
|
||||||
id: number
|
|
||||||
product: Product
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UseWishlistOptions {
|
export interface UseWishlistOptions {
|
||||||
includeProducts?: boolean
|
includeProducts?: boolean
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,12 @@ import * as Query from '../../utils/queries'
|
|||||||
|
|
||||||
export type Page = any
|
export type Page = any
|
||||||
|
|
||||||
export type GetAllPagesResult<T extends { pages: any[] } = { pages: Page[] }> = T
|
export type GetAllPagesResult<T extends { pages: any[] } = { pages: Page[] }> =
|
||||||
|
T
|
||||||
|
|
||||||
export default function getAllPagesOperation({ commerce }: OperationContext<Provider>) {
|
export default function getAllPagesOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
async function getAllPages({
|
async function getAllPages({
|
||||||
query = Query.PageMany,
|
query = Query.PageMany,
|
||||||
config,
|
config,
|
||||||
@ -34,11 +37,15 @@ export default function getAllPagesOperation({ commerce }: OperationContext<Prov
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const pages = data.pages?.edges?.map(({ node: { title: name, slug, ...node } }: PageCountableEdge) => ({
|
const pages = data?.pages?.edges?.map(
|
||||||
...node,
|
({ node: { title: name, slug, ...node } }: PageCountableEdge) =>
|
||||||
url: `/${locale}/${slug}`,
|
({
|
||||||
name,
|
id: node.id,
|
||||||
}))
|
url: `/${locale}/${slug}`,
|
||||||
|
body: node.content || '',
|
||||||
|
name,
|
||||||
|
} ?? [])
|
||||||
|
)
|
||||||
|
|
||||||
return { pages }
|
return { pages }
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,16 @@ import { ProductCountableEdge } from '../../../schema'
|
|||||||
import type { Provider, SaleorConfig } from '..'
|
import type { Provider, SaleorConfig } from '..'
|
||||||
|
|
||||||
import { getAllProductsPathsQuery } from '../../utils/queries'
|
import { getAllProductsPathsQuery } from '../../utils/queries'
|
||||||
import fetchAllProducts from '../utils/fetch-all-products'
|
|
||||||
|
|
||||||
export type GetAllProductPathsResult = {
|
export type GetAllProductPathsResult = {
|
||||||
products: Array<{ path: string }>
|
products: Array<{ path: string }>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function getAllProductPathsOperation({ commerce }: OperationContext<Provider>) {
|
export default function getAllProductPathsOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
async function getAllProductPaths({
|
async function getAllProductPaths({
|
||||||
query,
|
query = getAllProductsPathsQuery,
|
||||||
config,
|
config,
|
||||||
variables,
|
variables,
|
||||||
}: {
|
}: {
|
||||||
@ -21,16 +22,15 @@ export default function getAllProductPathsOperation({ commerce }: OperationConte
|
|||||||
} = {}): Promise<GetAllProductPathsResult> {
|
} = {}): Promise<GetAllProductPathsResult> {
|
||||||
config = commerce.getConfig(config)
|
config = commerce.getConfig(config)
|
||||||
|
|
||||||
const products = await fetchAllProducts({
|
const { data }: any = await config.fetch(query, { variables })
|
||||||
config,
|
|
||||||
query: getAllProductsPathsQuery,
|
|
||||||
variables,
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
products: products?.map(({ node: { slug } }: ProductCountableEdge) => ({
|
products: data?.products?.edges?.map(
|
||||||
path: `/${slug}`,
|
({ node: { slug } }: ProductCountableEdge) =>
|
||||||
})),
|
({
|
||||||
|
path: `/${slug}`,
|
||||||
|
} ?? [])
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,9 @@ type ReturnType = {
|
|||||||
products: Product[]
|
products: Product[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function getAllProductsOperation({ commerce }: OperationContext<Provider>) {
|
export default function getAllProductsOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
async function getAllProducts({
|
async function getAllProducts({
|
||||||
query = Query.ProductMany,
|
query = Query.ProductMany,
|
||||||
variables,
|
variables,
|
||||||
@ -46,13 +48,18 @@ export default function getAllProductsOperation({ commerce }: OperationContext<P
|
|||||||
|
|
||||||
if (featured) {
|
if (featured) {
|
||||||
const products =
|
const products =
|
||||||
data.collection.products?.edges?.map(({ node: p }: ProductCountableEdge) => normalizeProduct(p)) ?? []
|
data?.collection.products?.edges?.map(
|
||||||
|
({ node: p }: ProductCountableEdge) => normalizeProduct(p)
|
||||||
|
) ?? []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
products,
|
products,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const products = data.products?.edges?.map(({ node: p }: ProductCountableEdge) => normalizeProduct(p)) ?? []
|
const products =
|
||||||
|
data?.products?.edges?.map(({ node: p }: ProductCountableEdge) =>
|
||||||
|
normalizeProduct(p)
|
||||||
|
) ?? []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
products,
|
products,
|
||||||
|
@ -8,7 +8,9 @@ export type Page = any
|
|||||||
|
|
||||||
export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
|
export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
|
||||||
|
|
||||||
export default function getPageOperation({ commerce }: OperationContext<Provider>) {
|
export default function getPageOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
async function getPage({
|
async function getPage({
|
||||||
query = Query.PageOne,
|
query = Query.PageOne,
|
||||||
variables,
|
variables,
|
||||||
@ -21,9 +23,7 @@ export default function getPageOperation({ commerce }: OperationContext<Provider
|
|||||||
}): Promise<GetPageResult> {
|
}): Promise<GetPageResult> {
|
||||||
const { fetch, locale = 'en-US' } = commerce.getConfig(config)
|
const { fetch, locale = 'en-US' } = commerce.getConfig(config)
|
||||||
|
|
||||||
const {
|
const { data } = await fetch(
|
||||||
data: { page },
|
|
||||||
} = await fetch(
|
|
||||||
query,
|
query,
|
||||||
{ variables },
|
{ variables },
|
||||||
{
|
{
|
||||||
@ -36,13 +36,15 @@ export default function getPageOperation({ commerce }: OperationContext<Provider
|
|||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
page: page
|
page:
|
||||||
? {
|
data && data.page
|
||||||
...page,
|
? {
|
||||||
name: page.title,
|
...data.page,
|
||||||
url: `/${locale}/${page.slug}`,
|
name: data.page.title,
|
||||||
}
|
body: data.page.content || '',
|
||||||
: null,
|
url: `/${locale}/${data.page.slug}`,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,9 @@ type ReturnType = {
|
|||||||
product: any
|
product: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function getProductOperation({ commerce }: OperationContext<Provider>) {
|
export default function getProductOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
async function getProduct({
|
async function getProduct({
|
||||||
query = Query.ProductOneBySlug,
|
query = Query.ProductOneBySlug,
|
||||||
variables,
|
variables,
|
||||||
@ -38,7 +40,7 @@ export default function getProductOperation({ commerce }: OperationContext<Provi
|
|||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
product: data?.product ? normalizeProduct(data.product) : null,
|
product: data && data.product ? normalizeProduct(data.product) : null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
import { ProductCountableEdge } from '../../../schema'
|
|
||||||
import { SaleorConfig } from '..'
|
|
||||||
|
|
||||||
const fetchAllProducts = async ({
|
|
||||||
config,
|
|
||||||
query,
|
|
||||||
variables,
|
|
||||||
acc = [],
|
|
||||||
cursor,
|
|
||||||
}: {
|
|
||||||
config: SaleorConfig
|
|
||||||
query: string
|
|
||||||
acc?: ProductCountableEdge[]
|
|
||||||
variables?: any
|
|
||||||
cursor?: string
|
|
||||||
}): Promise<ProductCountableEdge[]> => {
|
|
||||||
const { data } = await config.fetch(query, {
|
|
||||||
variables: { ...variables, cursor },
|
|
||||||
})
|
|
||||||
|
|
||||||
const edges: ProductCountableEdge[] = data.products?.edges ?? []
|
|
||||||
const hasNextPage = data.products?.pageInfo?.hasNextPage
|
|
||||||
acc = acc.concat(edges)
|
|
||||||
|
|
||||||
if (hasNextPage) {
|
|
||||||
const cursor = edges.pop()?.cursor
|
|
||||||
if (cursor) {
|
|
||||||
return fetchAllProducts({
|
|
||||||
config,
|
|
||||||
query,
|
|
||||||
variables,
|
|
||||||
acc,
|
|
||||||
cursor,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc
|
|
||||||
}
|
|
||||||
|
|
||||||
export default fetchAllProducts
|
|
@ -38,7 +38,7 @@ export const handler: SWRHook<SearchProductsHook> = {
|
|||||||
let edges
|
let edges
|
||||||
|
|
||||||
if (categoryId) {
|
if (categoryId) {
|
||||||
edges = data.collection?.products?.edges ?? []
|
edges = data?.collection?.products?.edges ?? []
|
||||||
// FIXME @zaiste, no `vendor` in Saleor
|
// FIXME @zaiste, no `vendor` in Saleor
|
||||||
// if (brandId) {
|
// if (brandId) {
|
||||||
// edges = edges.filter(
|
// edges = edges.filter(
|
||||||
@ -47,11 +47,13 @@ export const handler: SWRHook<SearchProductsHook> = {
|
|||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
} else {
|
} else {
|
||||||
edges = data.products?.edges ?? []
|
edges = data?.products?.edges ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
products: edges.map(({ node }: ProductCountableEdge) => normalizeProduct(node)),
|
products: edges.map(({ node }: ProductCountableEdge) =>
|
||||||
|
normalizeProduct(node)
|
||||||
|
),
|
||||||
found: !!edges.length,
|
found: !!edges.length,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -6,17 +6,19 @@ import * as query from './queries'
|
|||||||
const getCategories = async (config: SaleorConfig): Promise<Category[]> => {
|
const getCategories = async (config: SaleorConfig): Promise<Category[]> => {
|
||||||
const { data } = await config.fetch(query.CollectionMany, {
|
const { data } = await config.fetch(query.CollectionMany, {
|
||||||
variables: {
|
variables: {
|
||||||
first: 100,
|
first: 50,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
data.collections?.edges?.map(({ node: { id, name, slug } }: CollectionCountableEdge) => ({
|
data?.collections?.edges?.map(
|
||||||
id,
|
({ node: { id, name, slug } }: CollectionCountableEdge) => ({
|
||||||
name,
|
id,
|
||||||
slug,
|
name,
|
||||||
path: `/${slug}`,
|
slug,
|
||||||
})) ?? []
|
path: `/${slug}`,
|
||||||
|
})
|
||||||
|
) ?? []
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ const getVendors = async (config: SaleorConfig): Promise<BrandEdge[]> => {
|
|||||||
// node: {
|
// node: {
|
||||||
// entityId: id,
|
// entityId: id,
|
||||||
// name: v,
|
// name: v,
|
||||||
// path: `brands/${id}`,
|
// path: `/${id}`,
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
// })
|
// })
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
import { Product } from '@vercel/commerce/types/product'
|
import { Product } from '@vercel/commerce/types/product'
|
||||||
|
|
||||||
import { Product as SaleorProduct, Checkout, CheckoutLine, Money, ProductVariant } from '../../schema'
|
import {
|
||||||
|
Product as SaleorProduct,
|
||||||
|
Checkout,
|
||||||
|
CheckoutLine,
|
||||||
|
Money,
|
||||||
|
ProductVariant,
|
||||||
|
} from '../../schema'
|
||||||
|
|
||||||
import type { Cart, LineItem } from '../types'
|
import type { Cart, LineItem } from '../types'
|
||||||
|
|
||||||
@ -19,11 +25,14 @@ const normalizeProductOptions = (options: ProductVariant[]) => {
|
|||||||
?.map((option) => option?.attributes)
|
?.map((option) => option?.attributes)
|
||||||
.flat(1)
|
.flat(1)
|
||||||
.reduce<any>((acc, x) => {
|
.reduce<any>((acc, x) => {
|
||||||
if (acc.find(({ displayName }: any) => displayName === x.attribute.name)) {
|
if (
|
||||||
|
acc.find(({ displayName }: any) => displayName === x.attribute.name)
|
||||||
|
) {
|
||||||
return acc.map((opt: any) => {
|
return acc.map((opt: any) => {
|
||||||
return opt.displayName === x.attribute.name
|
return opt.displayName === x.attribute.name
|
||||||
? {
|
? {
|
||||||
...opt,
|
...opt,
|
||||||
|
id: x.attribute.id,
|
||||||
values: [
|
values: [
|
||||||
...opt.values,
|
...opt.values,
|
||||||
...x.values.map((value: any) => ({
|
...x.values.map((value: any) => ({
|
||||||
@ -37,6 +46,7 @@ const normalizeProductOptions = (options: ProductVariant[]) => {
|
|||||||
|
|
||||||
return acc.concat({
|
return acc.concat({
|
||||||
__typename: 'MultipleChoiceOption',
|
__typename: 'MultipleChoiceOption',
|
||||||
|
id: x.attribute.id,
|
||||||
displayName: x.attribute.name,
|
displayName: x.attribute.name,
|
||||||
variant: 'size',
|
variant: 'size',
|
||||||
values: x.values.map((value: any) => ({
|
values: x.values.map((value: any) => ({
|
||||||
@ -54,7 +64,7 @@ const normalizeProductVariants = (variants: ProductVariant[]) => {
|
|||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
sku: sku ?? id,
|
...(!!sku && { sku }),
|
||||||
price,
|
price,
|
||||||
listPrice: price,
|
listPrice: price,
|
||||||
requiresShipping: true,
|
requiresShipping: true,
|
||||||
@ -64,23 +74,41 @@ const normalizeProductVariants = (variants: ProductVariant[]) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeProduct(productNode: SaleorProduct): Product {
|
export function normalizeProduct(productNode: SaleorProduct): Product {
|
||||||
const { id, name, media = [], variants, description, slug, pricing, ...rest } = productNode
|
const {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
media = [],
|
||||||
|
variants,
|
||||||
|
description,
|
||||||
|
slug,
|
||||||
|
pricing,
|
||||||
|
...rest
|
||||||
|
} = productNode
|
||||||
|
|
||||||
const product = {
|
const product = {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
vendor: '',
|
vendor: '',
|
||||||
description: description ? JSON.parse(description)?.blocks[0]?.data.text : '',
|
description: description
|
||||||
|
? JSON.parse(description)?.blocks[0]?.data.text
|
||||||
|
: '',
|
||||||
path: `/${slug}`,
|
path: `/${slug}`,
|
||||||
slug: slug?.replace(/^\/+|\/+$/g, ''),
|
slug: slug?.replace(/^\/+|\/+$/g, ''),
|
||||||
price: (pricing?.priceRange?.start?.net && money(pricing.priceRange.start.net)) || {
|
price: (pricing?.priceRange?.start?.net &&
|
||||||
|
money(pricing.priceRange.start.net)) || {
|
||||||
value: 0,
|
value: 0,
|
||||||
currencyCode: 'USD',
|
currencyCode: 'USD',
|
||||||
},
|
},
|
||||||
// TODO: Check nextjs-commerce bug if no images are added for a product
|
// TODO: Check nextjs-commerce bug if no images are added for a product
|
||||||
images: media?.length ? media : [{ url: placeholderImg }],
|
images: media?.length ? media : [{ url: placeholderImg }],
|
||||||
variants: variants && variants.length > 0 ? normalizeProductVariants(variants as ProductVariant[]) : [],
|
variants:
|
||||||
options: variants && variants.length > 0 ? normalizeProductOptions(variants as ProductVariant[]) : [],
|
variants && variants.length > 0
|
||||||
|
? normalizeProductVariants(variants as ProductVariant[])
|
||||||
|
: [],
|
||||||
|
options:
|
||||||
|
variants && variants.length > 0
|
||||||
|
? normalizeProductOptions(variants as ProductVariant[])
|
||||||
|
: [],
|
||||||
...rest,
|
...rest,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +117,8 @@ export function normalizeProduct(productNode: SaleorProduct): Product {
|
|||||||
|
|
||||||
export function normalizeCart(checkout: Checkout): Cart {
|
export function normalizeCart(checkout: Checkout): Cart {
|
||||||
const lines = checkout.lines as CheckoutLine[]
|
const lines = checkout.lines as CheckoutLine[]
|
||||||
const lineItems: LineItem[] = lines.length > 0 ? lines?.map<LineItem>(normalizeLineItem) : []
|
const lineItems: LineItem[] =
|
||||||
|
lines.length > 0 ? lines?.map<LineItem>(normalizeLineItem) : []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: checkout.id,
|
id: checkout.id,
|
||||||
@ -117,7 +146,7 @@ function normalizeLineItem({ id, variant, quantity }: CheckoutLine): LineItem {
|
|||||||
quantity,
|
quantity,
|
||||||
variant: {
|
variant: {
|
||||||
id: String(variant?.id),
|
id: String(variant?.id),
|
||||||
sku: variant?.sku ?? '',
|
...(variant?.sku && { sku: variant.sku }),
|
||||||
name: variant?.name!,
|
name: variant?.name!,
|
||||||
image: {
|
image: {
|
||||||
url: variant?.media![0] ? variant?.media![0].url : placeholderImg,
|
url: variant?.media![0] ? variant?.media![0].url : placeholderImg,
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import * as fragment from '../fragments'
|
import * as fragment from '../fragments'
|
||||||
|
|
||||||
export const CollectionOne = /* GraphQL */ `
|
export const CollectionOne = /* GraphQL */ `
|
||||||
query getProductsFromCollection($categoryId: ID!, $first: Int = 100, $channel: String = "default-channel") {
|
query getProductsFromCollection(
|
||||||
|
$categoryId: ID!
|
||||||
|
$first: Int = 50
|
||||||
|
$channel: String = "default-channel"
|
||||||
|
) {
|
||||||
collection(id: $categoryId, channel: $channel) {
|
collection(id: $categoryId, channel: $channel) {
|
||||||
id
|
id
|
||||||
products(first: $first) {
|
products(first: $first) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export const getAllProductVendors = /* GraphQL */ `
|
export const getAllProductVendors = /* GraphQL */ `
|
||||||
query getAllProductVendors($first: Int = 250, $cursor: String) {
|
query getAllProductVendors($first: Int = 50, $cursor: String) {
|
||||||
products(first: $first, after: $cursor) {
|
products(first: $first, after: $cursor) {
|
||||||
pageInfo {
|
pageInfo {
|
||||||
hasNextPage
|
hasNextPage
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
export const getAllProductsPathsQuery = /* GraphQL */ `
|
export const getAllProductsPathsQuery = /* GraphQL */ `
|
||||||
query getAllProductPaths($first: Int = 100, $cursor: String, $channel: String = "default-channel") {
|
query getAllProductPaths(
|
||||||
|
$first: Int = 50
|
||||||
|
$cursor: String
|
||||||
|
$channel: String = "default-channel"
|
||||||
|
) {
|
||||||
products(first: $first, after: $cursor, channel: $channel) {
|
products(first: $first, after: $cursor, channel: $channel) {
|
||||||
pageInfo {
|
pageInfo {
|
||||||
hasNextPage
|
hasNextPage
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export const PageMany = /* GraphQL */ `
|
export const PageMany = /* GraphQL */ `
|
||||||
query PageMany($first: Int = 100) {
|
query PageMany($first: Int = 50) {
|
||||||
pages(first: $first) {
|
pages(first: $first) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
|
@ -2,12 +2,17 @@ import * as fragment from '../fragments'
|
|||||||
|
|
||||||
export const ProductMany = /* GraphQL */ `
|
export const ProductMany = /* GraphQL */ `
|
||||||
query ProductMany(
|
query ProductMany(
|
||||||
$first: Int = 100
|
$first: Int = 50
|
||||||
$filter: ProductFilterInput
|
$filter: ProductFilterInput
|
||||||
$sortBy: ProductOrder
|
$sortBy: ProductOrder
|
||||||
$channel: String = "default-channel"
|
$channel: String = "default-channel"
|
||||||
) {
|
) {
|
||||||
products(first: $first, channel: $channel, filter: $filter, sortBy: $sortBy) {
|
products(
|
||||||
|
first: $first
|
||||||
|
channel: $channel
|
||||||
|
filter: $filter
|
||||||
|
sortBy: $sortBy
|
||||||
|
) {
|
||||||
...ProductConnection
|
...ProductConnection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ export const ProductOneBySlug = /* GraphQL */ `
|
|||||||
name
|
name
|
||||||
attributes {
|
attributes {
|
||||||
attribute {
|
attribute {
|
||||||
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
values {
|
values {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Product as SFCCProduct, Search } from 'commerce-sdk'
|
import { Product as SFCCProduct, Search } from 'commerce-sdk'
|
||||||
import type {
|
import type {
|
||||||
Product,
|
Product,
|
||||||
ProductImage,
|
|
||||||
ProductOption,
|
ProductOption,
|
||||||
ProductVariant,
|
ProductVariant,
|
||||||
} from '@vercel/commerce/types/product'
|
} from '@vercel/commerce/types/product'
|
||||||
@ -64,9 +63,9 @@ export function normalizeProduct(
|
|||||||
currencyCode: product.currency,
|
currencyCode: product.currency,
|
||||||
},
|
},
|
||||||
images: product.imageGroups![0].images.map((image) => ({
|
images: product.imageGroups![0].images.map((image) => ({
|
||||||
url: image.disBaseLink,
|
url: image.disBaseLink || image.link,
|
||||||
altText: image.title,
|
alt: image.title || '',
|
||||||
})) as ProductImage[],
|
})),
|
||||||
variants: normaliseVariants(product.variants),
|
variants: normaliseVariants(product.variants),
|
||||||
options: normaliseOptions(product.variationAttributes),
|
options: normaliseOptions(product.variationAttributes),
|
||||||
}
|
}
|
||||||
@ -87,8 +86,8 @@ export function normalizeSearchProducts(
|
|||||||
images: [
|
images: [
|
||||||
{
|
{
|
||||||
url: product.image!.link,
|
url: product.image!.link,
|
||||||
altText: product.productName,
|
alt: product.productName,
|
||||||
} as ProductImage,
|
},
|
||||||
],
|
],
|
||||||
variants: normaliseVariants(product.variants),
|
variants: normaliseVariants(product.variants),
|
||||||
options: normaliseOptions(product.variationAttributes),
|
options: normaliseOptions(product.variationAttributes),
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export default function (_commerce: any) {}
|
|
@ -0,0 +1,26 @@
|
|||||||
|
import { ProductsEndpoint } from '.'
|
||||||
|
|
||||||
|
const SORT: { [key: string]: string | undefined } = {
|
||||||
|
latest: 'id',
|
||||||
|
trending: 'total_sold',
|
||||||
|
price: 'price',
|
||||||
|
}
|
||||||
|
|
||||||
|
const LIMIT = 12
|
||||||
|
|
||||||
|
// Return current cart info
|
||||||
|
const getProducts: ProductsEndpoint['handlers']['getProducts'] = async ({
|
||||||
|
res,
|
||||||
|
body: { search, categoryId, brandId, sort },
|
||||||
|
config,
|
||||||
|
commerce,
|
||||||
|
}) => {
|
||||||
|
res.status(200).json({
|
||||||
|
data: {
|
||||||
|
products: [],
|
||||||
|
found: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getProducts
|
19
packages/shopify/src/api/endpoints/catalog/products/index.ts
Normal file
19
packages/shopify/src/api/endpoints/catalog/products/index.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
|
||||||
|
import productsEndpoint from '@vercel/commerce/api/endpoints/catalog/products'
|
||||||
|
import type { ProductsSchema } from '@vercel/commerce/types/product'
|
||||||
|
import type { ShopifyAPI } from '../../..'
|
||||||
|
|
||||||
|
import getProducts from './get-products'
|
||||||
|
|
||||||
|
export type ProductsAPI = GetAPISchema<ShopifyAPI, ProductsSchema>
|
||||||
|
|
||||||
|
export type ProductsEndpoint = ProductsAPI['endpoint']
|
||||||
|
|
||||||
|
export const handlers: ProductsEndpoint['handlers'] = { getProducts }
|
||||||
|
|
||||||
|
const productsApi = createEndpoint<ProductsAPI>({
|
||||||
|
handler: productsEndpoint,
|
||||||
|
handlers,
|
||||||
|
})
|
||||||
|
|
||||||
|
export default productsApi
|
@ -13,30 +13,30 @@ import {
|
|||||||
export default function getProductOperation({
|
export default function getProductOperation({
|
||||||
commerce,
|
commerce,
|
||||||
}: OperationContext<Provider>) {
|
}: OperationContext<Provider>) {
|
||||||
async function getProduct(opts: {
|
async function getProduct<T extends GetProductOperation>(opts: {
|
||||||
variables: GetProductOperation['variables']
|
variables: T['variables']
|
||||||
config?: Partial<ShopifyConfig>
|
config?: Partial<ShopifyConfig>
|
||||||
preview?: boolean
|
preview?: boolean
|
||||||
}): Promise<GetProductOperation['data']>
|
}): Promise<T['data']>
|
||||||
|
|
||||||
async function getProduct(
|
async function getProduct<T extends GetProductOperation>(
|
||||||
opts: {
|
opts: {
|
||||||
variables: GetProductOperation['variables']
|
variables: T['variables']
|
||||||
config?: Partial<ShopifyConfig>
|
config?: Partial<ShopifyConfig>
|
||||||
preview?: boolean
|
preview?: boolean
|
||||||
} & OperationOptions
|
} & OperationOptions
|
||||||
): Promise<GetProductOperation['data']>
|
): Promise<T['data']>
|
||||||
|
|
||||||
async function getProduct({
|
async function getProduct<T extends GetProductOperation>({
|
||||||
query = getProductQuery,
|
query = getProductQuery,
|
||||||
variables,
|
variables,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
}: {
|
}: {
|
||||||
query?: string
|
query?: string
|
||||||
variables: GetProductOperation['variables']
|
variables: T['variables']
|
||||||
config?: Partial<ShopifyConfig>
|
config?: Partial<ShopifyConfig>
|
||||||
preview?: boolean
|
preview?: boolean
|
||||||
}): Promise<GetProductOperation['data']> {
|
}): Promise<T['data']> {
|
||||||
const { fetch, locale } = commerce.getConfig(cfg)
|
const { fetch, locale } = commerce.getConfig(cfg)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -6,7 +6,7 @@ import { GetSiteInfoQueryVariables } from '../../../schema'
|
|||||||
import type { ShopifyConfig, Provider } from '..'
|
import type { ShopifyConfig, Provider } from '..'
|
||||||
import { GetSiteInfoOperation } from '../../types/site'
|
import { GetSiteInfoOperation } from '../../types/site'
|
||||||
|
|
||||||
import { getCategories, getBrands, getSiteInfoQuery } from '../../utils'
|
import { getCategories, getBrands } from '../../utils'
|
||||||
|
|
||||||
export default function getSiteInfoOperation({
|
export default function getSiteInfoOperation({
|
||||||
commerce,
|
commerce,
|
||||||
@ -24,9 +24,7 @@ export default function getSiteInfoOperation({
|
|||||||
): Promise<T['data']>
|
): Promise<T['data']>
|
||||||
|
|
||||||
async function getSiteInfo<T extends GetSiteInfoOperation>({
|
async function getSiteInfo<T extends GetSiteInfoOperation>({
|
||||||
query = getSiteInfoQuery,
|
|
||||||
config,
|
config,
|
||||||
variables,
|
|
||||||
}: {
|
}: {
|
||||||
query?: string
|
query?: string
|
||||||
config?: Partial<ShopifyConfig>
|
config?: Partial<ShopifyConfig>
|
||||||
@ -37,24 +35,15 @@ export default function getSiteInfoOperation({
|
|||||||
|
|
||||||
const categoriesPromise = getCategories(cfg)
|
const categoriesPromise = getCategories(cfg)
|
||||||
const brandsPromise = getBrands(cfg)
|
const brandsPromise = getBrands(cfg)
|
||||||
/*
|
|
||||||
const { fetch, locale } = cfg
|
const [categories, brands] = await Promise.all([
|
||||||
const { data } = await fetch<GetSiteInfoQuery, GetSiteInfoQueryVariables>(
|
categoriesPromise,
|
||||||
query,
|
brandsPromise,
|
||||||
{ variables },
|
])
|
||||||
{
|
|
||||||
...(locale && {
|
|
||||||
headers: {
|
|
||||||
'Accept-Language': locale,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
categories: await categoriesPromise,
|
categories,
|
||||||
brands: await brandsPromise,
|
brands,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ const fetchGraphqlApi: GraphQLFetcher = async (
|
|||||||
throw getError(
|
throw getError(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
message: `${err} \n Most likely related to an unexpected output. e.g the store might be protected with password or not available.`,
|
message: `${err} \n Most likely related to an unexpected output. E.g: NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN & NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN might be incorect.`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
500
|
500
|
||||||
|
@ -1,5 +1 @@
|
|||||||
import * as Core from '@vercel/commerce/types/customer'
|
|
||||||
|
|
||||||
export * from '@vercel/commerce/types/customer'
|
export * from '@vercel/commerce/types/customer'
|
||||||
|
|
||||||
export type CustomerSchema = Core.CustomerSchema
|
|
||||||
|
@ -1,8 +1 @@
|
|||||||
import * as Core from '@vercel/commerce/types/login'
|
|
||||||
import type { CustomerAccessTokenCreateInput } from '../../schema'
|
|
||||||
|
|
||||||
export * from '@vercel/commerce/types/login'
|
export * from '@vercel/commerce/types/login'
|
||||||
|
|
||||||
export type LoginOperation = Core.LoginOperation & {
|
|
||||||
variables: CustomerAccessTokenCreateInput
|
|
||||||
}
|
|
||||||
|
@ -1,11 +1 @@
|
|||||||
import * as Core from '@vercel/commerce/types/page'
|
|
||||||
export * from '@vercel/commerce/types/page'
|
export * from '@vercel/commerce/types/page'
|
||||||
|
|
||||||
export type Page = Core.Page
|
|
||||||
|
|
||||||
export type PageTypes = {
|
|
||||||
page: Page
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GetAllPagesOperation = Core.GetAllPagesOperation<PageTypes>
|
|
||||||
export type GetPageOperation = Core.GetPageOperation<PageTypes>
|
|
||||||
|
@ -5,19 +5,7 @@ import {
|
|||||||
import { ShopifyConfig } from '../api'
|
import { ShopifyConfig } from '../api'
|
||||||
import getAllProductVendors from './queries/get-all-product-vendors-query'
|
import getAllProductVendors from './queries/get-all-product-vendors-query'
|
||||||
|
|
||||||
export type Brand = {
|
const getBrands = async (config: ShopifyConfig) => {
|
||||||
entityId: string
|
|
||||||
name: string
|
|
||||||
path: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type BrandEdge = {
|
|
||||||
node: Brand
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Brands = BrandEdge[]
|
|
||||||
|
|
||||||
const getBrands = async (config: ShopifyConfig): Promise<BrandEdge[]> => {
|
|
||||||
const { data } = await config.fetch<
|
const { data } = await config.fetch<
|
||||||
GetAllProductVendorsQuery,
|
GetAllProductVendorsQuery,
|
||||||
GetAllProductVendorsQueryVariables
|
GetAllProductVendorsQueryVariables
|
||||||
@ -32,11 +20,10 @@ const getBrands = async (config: ShopifyConfig): Promise<BrandEdge[]> => {
|
|||||||
return [...new Set(vendorsStrings)].map((v) => {
|
return [...new Set(vendorsStrings)].map((v) => {
|
||||||
const id = v.replace(/\s+/g, '-').toLowerCase()
|
const id = v.replace(/\s+/g, '-').toLowerCase()
|
||||||
return {
|
return {
|
||||||
node: {
|
id,
|
||||||
entityId: id,
|
name: v,
|
||||||
name: v,
|
slug: id,
|
||||||
path: `brands/${id}`,
|
path: `/${id}`,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ const normalizeProductVariants = ({ edges }: ProductVariantConnection) => {
|
|||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
name: title,
|
name: title,
|
||||||
sku: sku ?? id,
|
sku,
|
||||||
price: +priceV2.amount,
|
price: +priceV2.amount,
|
||||||
listPrice: +compareAtPriceV2?.amount,
|
listPrice: +compareAtPriceV2?.amount,
|
||||||
requiresShipping,
|
requiresShipping,
|
||||||
@ -180,6 +180,7 @@ export const normalizePage = (
|
|||||||
...page,
|
...page,
|
||||||
url: `/${locale}/${handle}`,
|
url: `/${locale}/${handle}`,
|
||||||
name,
|
name,
|
||||||
|
body: page.body ?? '',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const normalizePages = (edges: PageEdge[], locale?: string): Page[] =>
|
export const normalizePages = (edges: PageEdge[], locale?: string): Page[] =>
|
||||||
|
@ -120,11 +120,10 @@ export default function getSiteInfoOperation({
|
|||||||
.sort(taxonsSort)
|
.sort(taxonsSort)
|
||||||
.map((spreeTaxon: TaxonAttr) => {
|
.map((spreeTaxon: TaxonAttr) => {
|
||||||
return {
|
return {
|
||||||
node: {
|
id: spreeTaxon.id,
|
||||||
entityId: spreeTaxon.id,
|
path: `/${spreeTaxon.id}`,
|
||||||
path: `brands/${spreeTaxon.id}`,
|
slug: spreeTaxon.id,
|
||||||
name: spreeTaxon.attributes.name,
|
name: spreeTaxon.attributes.name,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -8,10 +8,9 @@ import type { ResultResponse } from '@spree/storefront-api-v2-sdk/types/interfac
|
|||||||
import type { Response } from '@vercel/fetch'
|
import type { Response } from '@vercel/fetch'
|
||||||
import type { ProductOption, Product } from '@vercel/commerce/types/product'
|
import type { ProductOption, Product } from '@vercel/commerce/types/product'
|
||||||
import type {
|
import type {
|
||||||
AddItemHook,
|
Wishlist as CoreWishlist,
|
||||||
RemoveItemHook,
|
WishlistItemBody as CoreWishlistItemBody,
|
||||||
WishlistItemBody,
|
RemoveItemHook as CoreRemoveItemHook,
|
||||||
WishlistTypes,
|
|
||||||
} from '@vercel/commerce/types/wishlist'
|
} from '@vercel/commerce/types/wishlist'
|
||||||
|
|
||||||
export type UnknownObjectValues = Record<string, unknown>
|
export type UnknownObjectValues = Record<string, unknown>
|
||||||
@ -134,31 +133,22 @@ export type UserOAuthTokens = {
|
|||||||
accessToken: string
|
accessToken: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: ExplicitCommerceWishlist is a temporary type
|
export interface Wishlist extends CoreWishlist {
|
||||||
// derived from tsx views. It will be removed once
|
|
||||||
// Wishlist in @vercel/commerce/types/wishlist is updated
|
|
||||||
// to a more specific type than `any`.
|
|
||||||
export type ExplicitCommerceWishlist = {
|
|
||||||
id: string
|
|
||||||
token: string
|
token: string
|
||||||
items: {
|
|
||||||
id: string
|
|
||||||
product_id: number
|
|
||||||
variant_id: number
|
|
||||||
product: Product
|
|
||||||
}[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExplicitWishlistAddItemHook = AddItemHook<
|
export interface WishlistItemBody extends CoreWishlistItemBody {
|
||||||
WishlistTypes & {
|
wishlistToken: string
|
||||||
wishlist: ExplicitCommerceWishlist
|
}
|
||||||
itemBody: WishlistItemBody & {
|
|
||||||
wishlistToken?: string
|
export type AddItemHook = {
|
||||||
}
|
data: Wishlist | null | undefined
|
||||||
}
|
body: { item: WishlistItemBody }
|
||||||
>
|
fetcherInput: { item: WishlistItemBody }
|
||||||
|
actionInput: WishlistItemBody
|
||||||
export type ExplicitWishlistRemoveItemHook = RemoveItemHook & {
|
}
|
||||||
fetcherInput: { wishlistToken?: string }
|
|
||||||
body: { wishlistToken?: string }
|
export type RemoveItemHook = CoreRemoveItemHook & {
|
||||||
|
fetcherInput: { itemId: string; wishlistToken?: string }
|
||||||
|
body: { temId: string; wishlistToken?: string }
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Based on https://github.com/spark-solutions/spree2vuestorefront/blob/d88d85ae1bcd2ec99b13b81cd2e3c25600a0216e/src/utils/index.ts
|
// Based on https://github.com/spark-solutions/spree2vuestorefront/blob/d88d85ae1bcd2ec99b13b81cd2e3c25600a0216e/src/utils/index.ts
|
||||||
|
|
||||||
import type { ProductImage } from '@vercel/commerce/types/product'
|
import type { Image } from '@vercel/commerce/types/common'
|
||||||
import type { SpreeProductImage } from '../types'
|
import type { SpreeProductImage } from '../types'
|
||||||
|
|
||||||
const getMediaGallery = (
|
const getMediaGallery = (
|
||||||
@ -11,7 +11,7 @@ const getMediaGallery = (
|
|||||||
minHeight: number
|
minHeight: number
|
||||||
) => string | null
|
) => string | null
|
||||||
) => {
|
) => {
|
||||||
return images.reduce<ProductImage[]>((productImages, _, imageIndex) => {
|
return images.reduce<Image[]>((productImages, _, imageIndex) => {
|
||||||
const url = getImageUrl(images[imageIndex], 800, 800)
|
const url = getImageUrl(images[imageIndex], 800, 800)
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
|
@ -88,7 +88,6 @@ const normalizeVariant = (
|
|||||||
price: parseFloat(spreeVariant.attributes.price),
|
price: parseFloat(spreeVariant.attributes.price),
|
||||||
listPrice: parseFloat(spreeVariant.attributes.price),
|
listPrice: parseFloat(spreeVariant.attributes.price),
|
||||||
image,
|
image,
|
||||||
isInStock: spreeVariant.attributes.in_stock,
|
|
||||||
availableForSale: spreeVariant.attributes.purchasable,
|
availableForSale: spreeVariant.attributes.purchasable,
|
||||||
...(spreeVariant.attributes.weight === '0.0'
|
...(spreeVariant.attributes.weight === '0.0'
|
||||||
? {}
|
? {}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import type {
|
import type {
|
||||||
Product,
|
Product,
|
||||||
ProductImage,
|
|
||||||
ProductPrice,
|
ProductPrice,
|
||||||
ProductVariant,
|
ProductVariant,
|
||||||
} from '@vercel/commerce/types/product'
|
} from '@vercel/commerce/types/product'
|
||||||
|
import type { Image } from '@vercel/commerce/types/common'
|
||||||
import type { ProductAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'
|
import type { ProductAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'
|
||||||
import type { RelationType } from '@spree/storefront-api-v2-sdk/types/interfaces/Relationships'
|
import type { RelationType } from '@spree/storefront-api-v2-sdk/types/interfaces/Relationships'
|
||||||
import { jsonApi } from '@spree/storefront-api-v2-sdk'
|
import { jsonApi } from '@spree/storefront-api-v2-sdk'
|
||||||
@ -105,6 +105,7 @@ const normalizeProduct = (
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
id: spreeVariantRecord.id,
|
id: spreeVariantRecord.id,
|
||||||
|
sku: spreeVariantRecord.attributes.sku || spreeVariantRecord.id,
|
||||||
options: variantOptions,
|
options: variantOptions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +214,7 @@ const normalizeProduct = (
|
|||||||
createGetAbsoluteImageUrl(requireConfigValue('imageHost') as string)
|
createGetAbsoluteImageUrl(requireConfigValue('imageHost') as string)
|
||||||
)
|
)
|
||||||
|
|
||||||
const images: ProductImage[] =
|
const images: Image[] =
|
||||||
productImages.length === 0
|
productImages.length === 0
|
||||||
? placeholderImage === false
|
? placeholderImage === false
|
||||||
? []
|
? []
|
||||||
|
@ -4,59 +4,54 @@ import { jsonApi } from '@spree/storefront-api-v2-sdk'
|
|||||||
import type { ProductAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'
|
import type { ProductAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'
|
||||||
import type { WishedItemAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/WishedItem'
|
import type { WishedItemAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/WishedItem'
|
||||||
import type { WishlistAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Wishlist'
|
import type { WishlistAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Wishlist'
|
||||||
import type {
|
import type { SpreeSdkResponse, VariantAttr } from '../../types'
|
||||||
ExplicitCommerceWishlist,
|
|
||||||
SpreeSdkResponse,
|
|
||||||
VariantAttr,
|
|
||||||
} from '../../types'
|
|
||||||
import normalizeProduct from './normalize-product'
|
import normalizeProduct from './normalize-product'
|
||||||
|
import { Wishlist } from '@vercel/commerce/types/wishlist'
|
||||||
|
|
||||||
const normalizeWishlist = (
|
const normalizeWishlist = (
|
||||||
spreeSuccessResponse: SpreeSdkResponse,
|
spreeSuccessResponse: SpreeSdkResponse,
|
||||||
spreeWishlist: WishlistAttr
|
spreeWishlist: WishlistAttr
|
||||||
): ExplicitCommerceWishlist => {
|
): Wishlist => {
|
||||||
const spreeWishedItems = jsonApi.findRelationshipDocuments<WishedItemAttr>(
|
const spreeWishedItems = jsonApi.findRelationshipDocuments<WishedItemAttr>(
|
||||||
spreeSuccessResponse,
|
spreeSuccessResponse,
|
||||||
spreeWishlist,
|
spreeWishlist,
|
||||||
'wished_items'
|
'wished_items'
|
||||||
)
|
)
|
||||||
|
|
||||||
const items: ExplicitCommerceWishlist['items'] = spreeWishedItems.map(
|
const items: Wishlist['items'] = spreeWishedItems.map((spreeWishedItem) => {
|
||||||
(spreeWishedItem) => {
|
const spreeWishedVariant =
|
||||||
const spreeWishedVariant =
|
jsonApi.findSingleRelationshipDocument<VariantAttr>(
|
||||||
jsonApi.findSingleRelationshipDocument<VariantAttr>(
|
spreeSuccessResponse,
|
||||||
spreeSuccessResponse,
|
spreeWishedItem,
|
||||||
spreeWishedItem,
|
'variant'
|
||||||
'variant'
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if (spreeWishedVariant === null) {
|
if (spreeWishedVariant === null) {
|
||||||
throw new MissingVariantError(
|
throw new MissingVariantError(
|
||||||
`Couldn't find variant for wished item with id ${spreeWishedItem.id}.`
|
`Couldn't find variant for wished item with id ${spreeWishedItem.id}.`
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
const spreeWishedProduct =
|
|
||||||
jsonApi.findSingleRelationshipDocument<ProductAttr>(
|
|
||||||
spreeSuccessResponse,
|
|
||||||
spreeWishedVariant,
|
|
||||||
'product'
|
|
||||||
)
|
|
||||||
|
|
||||||
if (spreeWishedProduct === null) {
|
|
||||||
throw new MissingProductError(
|
|
||||||
`Couldn't find product for variant with id ${spreeWishedVariant.id}.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: spreeWishedItem.id,
|
|
||||||
product_id: parseInt(spreeWishedProduct.id, 10),
|
|
||||||
variant_id: parseInt(spreeWishedVariant.id, 10),
|
|
||||||
product: normalizeProduct(spreeSuccessResponse, spreeWishedProduct),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
const spreeWishedProduct =
|
||||||
|
jsonApi.findSingleRelationshipDocument<ProductAttr>(
|
||||||
|
spreeSuccessResponse,
|
||||||
|
spreeWishedVariant,
|
||||||
|
'product'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (spreeWishedProduct === null) {
|
||||||
|
throw new MissingProductError(
|
||||||
|
`Couldn't find product for variant with id ${spreeWishedVariant.id}.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: spreeWishedItem.id,
|
||||||
|
productId: spreeWishedProduct.id,
|
||||||
|
variantId: spreeWishedVariant.id,
|
||||||
|
product: normalizeProduct(spreeSuccessResponse, spreeWishedProduct),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: spreeWishlist.id,
|
id: spreeWishlist.id,
|
||||||
|
@ -2,8 +2,9 @@ import { useCallback } from 'react'
|
|||||||
import type { MutationHook } from '@vercel/commerce/utils/types'
|
import type { MutationHook } from '@vercel/commerce/utils/types'
|
||||||
import useAddItem from '@vercel/commerce/wishlist/use-add-item'
|
import useAddItem from '@vercel/commerce/wishlist/use-add-item'
|
||||||
import type { UseAddItem } from '@vercel/commerce/wishlist/use-add-item'
|
import type { UseAddItem } from '@vercel/commerce/wishlist/use-add-item'
|
||||||
|
import type { AddItemHook } from '@vercel/commerce/types/wishlist'
|
||||||
import useWishlist from './use-wishlist'
|
import useWishlist from './use-wishlist'
|
||||||
import type { ExplicitWishlistAddItemHook } from '../types'
|
|
||||||
import type {
|
import type {
|
||||||
WishedItem,
|
WishedItem,
|
||||||
WishlistsAddWishedItem,
|
WishlistsAddWishedItem,
|
||||||
@ -11,12 +12,12 @@ import type {
|
|||||||
import type { GraphQLFetcherResult } from '@vercel/commerce/api'
|
import type { GraphQLFetcherResult } from '@vercel/commerce/api'
|
||||||
import ensureIToken from '../utils/tokens/ensure-itoken'
|
import ensureIToken from '../utils/tokens/ensure-itoken'
|
||||||
import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'
|
import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'
|
||||||
import type { AddItemHook } from '@vercel/commerce/types/wishlist'
|
|
||||||
import isLoggedIn from '../utils/tokens/is-logged-in'
|
import isLoggedIn from '../utils/tokens/is-logged-in'
|
||||||
|
|
||||||
export default useAddItem as UseAddItem<typeof handler>
|
export default useAddItem as UseAddItem<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<ExplicitWishlistAddItemHook> = {
|
export const handler: MutationHook<AddItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: 'wishlists',
|
url: 'wishlists',
|
||||||
query: 'addWishedItem',
|
query: 'addWishedItem',
|
||||||
@ -31,7 +32,7 @@ export const handler: MutationHook<ExplicitWishlistAddItemHook> = {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
item: { productId, variantId, wishlistToken },
|
item: { variantId, wishlistToken },
|
||||||
} = input
|
} = input
|
||||||
|
|
||||||
if (!isLoggedIn() || !wishlistToken) {
|
if (!isLoggedIn() || !wishlistToken) {
|
||||||
|
@ -2,8 +2,8 @@ import { useCallback } from 'react'
|
|||||||
import type { MutationHook } from '@vercel/commerce/utils/types'
|
import type { MutationHook } from '@vercel/commerce/utils/types'
|
||||||
import useRemoveItem from '@vercel/commerce/wishlist/use-remove-item'
|
import useRemoveItem from '@vercel/commerce/wishlist/use-remove-item'
|
||||||
import type { UseRemoveItem } from '@vercel/commerce/wishlist/use-remove-item'
|
import type { UseRemoveItem } from '@vercel/commerce/wishlist/use-remove-item'
|
||||||
|
import type { RemoveItemHook } from '@vercel/commerce/types/wishlist'
|
||||||
import useWishlist from './use-wishlist'
|
import useWishlist from './use-wishlist'
|
||||||
import type { ExplicitWishlistRemoveItemHook } from '../types'
|
|
||||||
import isLoggedIn from '../utils/tokens/is-logged-in'
|
import isLoggedIn from '../utils/tokens/is-logged-in'
|
||||||
import ensureIToken from '../utils/tokens/ensure-itoken'
|
import ensureIToken from '../utils/tokens/ensure-itoken'
|
||||||
import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'
|
import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'
|
||||||
@ -12,7 +12,7 @@ import type { WishedItem } from '@spree/storefront-api-v2-sdk/types/interfaces/W
|
|||||||
|
|
||||||
export default useRemoveItem as UseRemoveItem<typeof handler>
|
export default useRemoveItem as UseRemoveItem<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<ExplicitWishlistRemoveItemHook> = {
|
export const handler: MutationHook<RemoveItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: 'wishlists',
|
url: 'wishlists',
|
||||||
query: 'removeWishedItem',
|
query: 'removeWishedItem',
|
||||||
@ -45,7 +45,7 @@ export const handler: MutationHook<ExplicitWishlistRemoveItemHook> = {
|
|||||||
},
|
},
|
||||||
useHook: ({ fetch }) => {
|
useHook: ({ fetch }) => {
|
||||||
const useWrappedHook: ReturnType<
|
const useWrappedHook: ReturnType<
|
||||||
MutationHook<ExplicitWishlistRemoveItemHook>['useHook']
|
MutationHook<RemoveItemHook>['useHook']
|
||||||
> = () => {
|
> = () => {
|
||||||
const wishlist = useWishlist()
|
const wishlist = useWishlist()
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import type { Wishlist } from '@spree/storefront-api-v2-sdk/types/interfaces/Wis
|
|||||||
import ensureIToken from '../utils/tokens/ensure-itoken'
|
import ensureIToken from '../utils/tokens/ensure-itoken'
|
||||||
import normalizeWishlist from '../utils/normalizations/normalize-wishlist'
|
import normalizeWishlist from '../utils/normalizations/normalize-wishlist'
|
||||||
import isLoggedIn from '../utils/tokens/is-logged-in'
|
import isLoggedIn from '../utils/tokens/is-logged-in'
|
||||||
|
import { ValidationError } from '@vercel/commerce/utils/errors'
|
||||||
|
|
||||||
export default useWishlist as UseWishlist<typeof handler>
|
export default useWishlist as UseWishlist<typeof handler>
|
||||||
|
|
||||||
@ -28,7 +29,9 @@ export const handler: SWRHook<GetWishlistHook> = {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!isLoggedIn()) {
|
if (!isLoggedIn()) {
|
||||||
return null
|
throw new ValidationError({
|
||||||
|
message: 'Not logged in',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Optimize with includeProducts.
|
// TODO: Optimize with includeProducts.
|
||||||
|
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