Merge branch 'nodejs-provider' of https://github.com/vercel/commerce into shopify-updates

This commit is contained in:
cond0r 2021-05-26 14:00:36 +03:00
commit 61db441df4
33 changed files with 219 additions and 147 deletions

View File

@ -12,7 +12,7 @@ const LIMIT = 12
// Return current cart info // Return current cart info
const getProducts: ProductsEndpoint['handlers']['getProducts'] = async ({ const getProducts: ProductsEndpoint['handlers']['getProducts'] = async ({
res, res,
body: { search, category, brand, sort }, body: { search, categoryId, brandId, sort },
config, config,
commerce, commerce,
}) => { }) => {
@ -24,11 +24,11 @@ const getProducts: ProductsEndpoint['handlers']['getProducts'] = async ({
if (search) url.searchParams.set('keyword', search) if (search) url.searchParams.set('keyword', search)
if (category && Number.isInteger(Number(category))) if (categoryId && Number.isInteger(Number(categoryId)))
url.searchParams.set('categories:in', category) url.searchParams.set('categories:in', categoryId)
if (brand && Number.isInteger(Number(brand))) if (brandId && Number.isInteger(Number(brandId)))
url.searchParams.set('brand_id', brand) url.searchParams.set('brand_id', brandId)
if (sort) { if (sort) {
const [_sort, direction] = sort.split('-') const [_sort, direction] = sort.split('-')

View File

@ -3,13 +3,13 @@ import type { GraphQLFetcher } from '@commerce/api'
import { provider } from '..' import { provider } from '..'
import fetch from './fetch' import fetch from './fetch'
const { config } = provider
const fetchGraphqlApi: GraphQLFetcher = async ( const fetchGraphqlApi: GraphQLFetcher = async (
query: string, query: string,
{ variables, preview } = {}, { variables, preview } = {},
fetchOptions fetchOptions
) => { ) => {
// log.warn(query) // log.warn(query)
const { config } = provider
const res = await fetch(config.commerceUrl + (preview ? '/preview' : ''), { const res = await fetch(config.commerceUrl + (preview ? '/preview' : ''), {
...fetchOptions, ...fetchOptions,
method: 'POST', method: 'POST',

View File

@ -3,12 +3,11 @@ import { provider } from '..'
import { BigcommerceApiError, BigcommerceNetworkError } from './errors' import { BigcommerceApiError, BigcommerceNetworkError } from './errors'
import fetch from './fetch' import fetch from './fetch'
const { config } = provider
export default async function fetchStoreApi<T>( export default async function fetchStoreApi<T>(
endpoint: string, endpoint: string,
options?: RequestInit options?: RequestInit
): Promise<T> { ): Promise<T> {
const { config } = provider
let res: Response let res: Response
try { try {

View File

@ -2,12 +2,12 @@ import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types' import type { MutationHook } from '@commerce/utils/types'
import { CommerceError } from '@commerce/utils/errors' import { CommerceError } from '@commerce/utils/errors'
import useLogin, { UseLogin } from '@commerce/auth/use-login' import useLogin, { UseLogin } from '@commerce/auth/use-login'
import type { LoginBody } from '../api/customers/login' import type { LoginHook } from '../types/login'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
export default useLogin as UseLogin<typeof handler> export default useLogin as UseLogin<typeof handler>
export const handler: MutationHook<null, {}, LoginBody> = { export const handler: MutationHook<LoginHook> = {
fetchOptions: { fetchOptions: {
url: '/api/bigcommerce/customers/login', url: '/api/bigcommerce/customers/login',
method: 'POST', method: 'POST',

View File

@ -1,11 +1,12 @@
import { useCallback } from 'react' import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types' import type { MutationHook } from '@commerce/utils/types'
import useLogout, { UseLogout } from '@commerce/auth/use-logout' import useLogout, { UseLogout } from '@commerce/auth/use-logout'
import type { LogoutHook } from '../types/logout'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
export default useLogout as UseLogout<typeof handler> export default useLogout as UseLogout<typeof handler>
export const handler: MutationHook<null> = { export const handler: MutationHook<LogoutHook> = {
fetchOptions: { fetchOptions: {
url: '/api/bigcommerce/customers/logout', url: '/api/bigcommerce/customers/logout',
method: 'GET', method: 'GET',

View File

@ -2,12 +2,12 @@ import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types' import type { MutationHook } from '@commerce/utils/types'
import { CommerceError } from '@commerce/utils/errors' import { CommerceError } from '@commerce/utils/errors'
import useSignup, { UseSignup } from '@commerce/auth/use-signup' import useSignup, { UseSignup } from '@commerce/auth/use-signup'
import type { SignupBody } from '../api/customers/signup' import type { SignupHook } from '../types/signup'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
export default useSignup as UseSignup<typeof handler> export default useSignup as UseSignup<typeof handler>
export const handler: MutationHook<null, {}, SignupBody, SignupBody> = { export const handler: MutationHook<SignupHook> = {
fetchOptions: { fetchOptions: {
url: '/api/bigcommerce/customers/signup', url: '/api/bigcommerce/customers/signup',
method: 'POST', method: 'POST',

View File

@ -1,16 +1,16 @@
import { SWRHook } from '@commerce/utils/types' import { SWRHook } from '@commerce/utils/types'
import useCustomer, { UseCustomer } from '@commerce/customer/use-customer' import useCustomer, { UseCustomer } from '@commerce/customer/use-customer'
import type { Customer, CustomerData } from '../api/customers' import type { CustomerHook } from '../types/customer'
export default useCustomer as UseCustomer<typeof handler> export default useCustomer as UseCustomer<typeof handler>
export const handler: SWRHook<Customer | null> = { export const handler: SWRHook<CustomerHook> = {
fetchOptions: { fetchOptions: {
url: '/api/bigcommerce/customers', url: '/api/customer',
method: 'GET', method: 'GET',
}, },
async fetcher({ options, fetch }) { async fetcher({ options, fetch }) {
const data = await fetch<CustomerData | null>(options) const data = await fetch(options)
return data?.customer ?? null return data?.customer ?? null
}, },
useHook: ({ useData }) => (input) => { useHook: ({ useData }) => (input) => {

View File

@ -1,6 +1,6 @@
import { SWRHook } from '@commerce/utils/types' import { SWRHook } from '@commerce/utils/types'
import useSearch, { UseSearch } from '@commerce/product/use-search' import useSearch, { UseSearch } from '@commerce/product/use-search'
import type { SearchProductsData } from '../api/catalog/products' import type { SearchProductsHook } from '../types/product'
export default useSearch as UseSearch<typeof handler> export default useSearch as UseSearch<typeof handler>
@ -11,13 +11,9 @@ export type SearchProductsInput = {
sort?: string sort?: string
} }
export const handler: SWRHook< export const handler: SWRHook<SearchProductsHook> = {
SearchProductsData,
SearchProductsInput,
SearchProductsInput
> = {
fetchOptions: { fetchOptions: {
url: '/api/bigcommerce/catalog/products', url: '/api/catalog/products',
method: 'GET', method: 'GET',
}, },
fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) { fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) {

View File

@ -0,0 +1 @@
export * from '@commerce/types/common'

View File

@ -1,2 +1,25 @@
export * from '@commerce/types' import * as Cart from './cart'
export * from './cart' import * as Checkout from './checkout'
import * as Common from './common'
import * as Customer from './customer'
import * as Login from './login'
import * as Logout from './logout'
import * as Page from './page'
import * as Product from './product'
import * as Signup from './signup'
import * as Site from './site'
import * as Wishlist from './wishlist'
export type {
Cart,
Checkout,
Common,
Customer,
Login,
Logout,
Page,
Product,
Signup,
Site,
Wishlist,
}

View File

@ -2,15 +2,15 @@ import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types' import type { MutationHook } from '@commerce/utils/types'
import { CommerceError } from '@commerce/utils/errors' import { CommerceError } from '@commerce/utils/errors'
import useAddItem, { UseAddItem } from '@commerce/wishlist/use-add-item' import useAddItem, { UseAddItem } from '@commerce/wishlist/use-add-item'
import type { ItemBody, AddItemBody } from '../api/wishlist' import type { AddItemHook } from '../types/wishlist'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
import useWishlist from './use-wishlist' import useWishlist from './use-wishlist'
export default useAddItem as UseAddItem<typeof handler> export default useAddItem as UseAddItem<typeof handler>
export const handler: MutationHook<any, {}, ItemBody, AddItemBody> = { export const handler: MutationHook<AddItemHook> = {
fetchOptions: { fetchOptions: {
url: '/api/bigcommerce/wishlist', url: '/api/wishlist',
method: 'POST', method: 'POST',
}, },
useHook: ({ fetch }) => () => { useHook: ({ fetch }) => () => {

View File

@ -2,23 +2,17 @@ import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types' import type { MutationHook } from '@commerce/utils/types'
import { CommerceError } from '@commerce/utils/errors' import { CommerceError } from '@commerce/utils/errors'
import useRemoveItem, { import useRemoveItem, {
RemoveItemInput,
UseRemoveItem, UseRemoveItem,
} from '@commerce/wishlist/use-remove-item' } from '@commerce/wishlist/use-remove-item'
import type { RemoveItemBody, Wishlist } from '../api/wishlist' import type { RemoveItemHook } from '../types/wishlist'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
import useWishlist, { UseWishlistInput } from './use-wishlist' import useWishlist from './use-wishlist'
export default useRemoveItem as UseRemoveItem<typeof handler> export default useRemoveItem as UseRemoveItem<typeof handler>
export const handler: MutationHook< export const handler: MutationHook<RemoveItemHook> = {
Wishlist | null,
{ wishlist?: UseWishlistInput },
RemoveItemInput,
RemoveItemBody
> = {
fetchOptions: { fetchOptions: {
url: '/api/bigcommerce/wishlist', url: '/api/wishlist',
method: 'DELETE', method: 'DELETE',
}, },
useHook: ({ fetch }) => ({ wishlist } = {}) => { useHook: ({ fetch }) => ({ wishlist } = {}) => {

View File

@ -1,19 +1,12 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import { SWRHook } from '@commerce/utils/types' import { SWRHook } from '@commerce/utils/types'
import useWishlist, { UseWishlist } from '@commerce/wishlist/use-wishlist' import useWishlist, { UseWishlist } from '@commerce/wishlist/use-wishlist'
import type { Wishlist } from '../api/wishlist' import type { GetWishlistHook } from '../types/wishlist'
import useCustomer from '../customer/use-customer' import useCustomer from '../customer/use-customer'
export type UseWishlistInput = { includeProducts?: boolean }
export default useWishlist as UseWishlist<typeof handler> export default useWishlist as UseWishlist<typeof handler>
export const handler: SWRHook< export const handler: SWRHook<GetWishlistHook> = {
Wishlist | null,
UseWishlistInput,
{ customerId?: number } & UseWishlistInput,
{ isEmpty?: boolean }
> = {
fetchOptions: { fetchOptions: {
url: '/api/bigcommerce/wishlist', url: '/api/bigcommerce/wishlist',
method: 'GET', method: 'GET',

View File

@ -14,7 +14,16 @@ const noop = () => {
throw new Error('Not implemented') throw new Error('Not implemented')
} }
export const OPERATIONS = ['login'] as const export const OPERATIONS = [
'login',
'getAllPages',
'getPage',
'getSiteInfo',
'getCustomerWishlist',
'getAllProductPaths',
'getAllProducts',
'getProduct',
] as const
export const defaultOperations = OPERATIONS.reduce((ops, k) => { export const defaultOperations = OPERATIONS.reduce((ops, k) => {
ops[k] = noop ops[k] = noop

View File

@ -1,13 +1,14 @@
import { useHook, useMutationHook } from '../utils/use-hook' import { useHook, useMutationHook } from '../utils/use-hook'
import { mutationFetcher } from '../utils/default-fetcher' import { mutationFetcher } from '../utils/default-fetcher'
import type { MutationHook, HookFetcherFn } from '../utils/types' import type { MutationHook, HookFetcherFn } from '../utils/types'
import type { LoginHook } from '../types/login'
import type { Provider } from '..' import type { Provider } from '..'
export type UseLogin< export type UseLogin<
H extends MutationHook<any, any, any> = MutationHook<null, {}, {}> H extends MutationHook<LoginHook<any>> = MutationHook<LoginHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<null, {}> = mutationFetcher export const fetcher: HookFetcherFn<LoginHook> = mutationFetcher
const fn = (provider: Provider) => provider.auth?.useLogin! const fn = (provider: Provider) => provider.auth?.useLogin!

View File

@ -1,13 +1,14 @@
import { useHook, useMutationHook } from '../utils/use-hook' import { useHook, useMutationHook } from '../utils/use-hook'
import { mutationFetcher } from '../utils/default-fetcher' import { mutationFetcher } from '../utils/default-fetcher'
import type { HookFetcherFn, MutationHook } from '../utils/types' import type { HookFetcherFn, MutationHook } from '../utils/types'
import type { LogoutHook } from '../types/logout'
import type { Provider } from '..' import type { Provider } from '..'
export type UseLogout< export type UseLogout<
H extends MutationHook<any, any, any> = MutationHook<null> H extends MutationHook<LogoutHook<any>> = MutationHook<LogoutHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<null> = mutationFetcher export const fetcher: HookFetcherFn<LogoutHook> = mutationFetcher
const fn = (provider: Provider) => provider.auth?.useLogout! const fn = (provider: Provider) => provider.auth?.useLogout!

View File

@ -1,13 +1,14 @@
import { useHook, useMutationHook } from '../utils/use-hook' import { useHook, useMutationHook } from '../utils/use-hook'
import { mutationFetcher } from '../utils/default-fetcher' import { mutationFetcher } from '../utils/default-fetcher'
import type { HookFetcherFn, MutationHook } from '../utils/types' import type { HookFetcherFn, MutationHook } from '../utils/types'
import type { SignupHook } from '../types/signup'
import type { Provider } from '..' import type { Provider } from '..'
export type UseSignup< export type UseSignup<
H extends MutationHook<any, any, any> = MutationHook<null> H extends MutationHook<SignupHook<any>> = MutationHook<SignupHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<null> = mutationFetcher export const fetcher: HookFetcherFn<SignupHook> = mutationFetcher
const fn = (provider: Provider) => provider.auth?.useSignup! const fn = (provider: Provider) => provider.auth?.useSignup!

View File

@ -8,10 +8,6 @@ export type UseAddItem<
H extends MutationHook<AddItemHook<any>> = MutationHook<AddItemHook> H extends MutationHook<AddItemHook<any>> = MutationHook<AddItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export type UseAddItem2<
H extends MutationHook<any> = MutationHook<AddItemHook>
> = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<AddItemHook> = mutationFetcher export const fetcher: HookFetcherFn<AddItemHook> = mutationFetcher
const fn = (provider: Provider) => provider.cart?.useAddItem! const fn = (provider: Provider) => provider.cart?.useAddItem!

View File

@ -1,14 +1,14 @@
import { useHook, useSWRHook } from '../utils/use-hook' import { useHook, useSWRHook } from '../utils/use-hook'
import { SWRFetcher } from '../utils/default-fetcher' import { SWRFetcher } from '../utils/default-fetcher'
import type { CustomerHook } from '../types/customer'
import type { HookFetcherFn, SWRHook } from '../utils/types' import type { HookFetcherFn, SWRHook } from '../utils/types'
import type { Customer } from '../types' import type { Provider } from '..'
import { Provider } from '..'
export type UseCustomer< export type UseCustomer<
H extends SWRHook<any, any, any> = SWRHook<Customer | null> H extends SWRHook<CustomerHook<any>> = SWRHook<CustomerHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<Customer | null, any> = SWRFetcher export const fetcher: HookFetcherFn<CustomerHook> = SWRFetcher
const fn = (provider: Provider) => provider.customer?.useCustomer! const fn = (provider: Provider) => provider.customer?.useCustomer!

View File

@ -1,14 +1,14 @@
import { useHook, useSWRHook } from '../utils/use-hook' import { useHook, useSWRHook } from '../utils/use-hook'
import { SWRFetcher } from '../utils/default-fetcher' import { SWRFetcher } from '../utils/default-fetcher'
import type { HookFetcherFn, SWRHook } from '../utils/types' import type { HookFetcherFn, SWRHook } from '../utils/types'
import type { SearchProductsData } from '../types' import type { SearchProductsHook } from '../types/product'
import { Provider } from '..' import type { Provider } from '..'
export type UseSearch< export type UseSearch<
H extends SWRHook<any, any, any> = SWRHook<SearchProductsData> H extends SWRHook<SearchProductsHook<any>> = SWRHook<SearchProductsHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<SearchProductsData, any> = SWRFetcher export const fetcher: HookFetcherFn<SearchProductsHook> = SWRFetcher
const fn = (provider: Provider) => provider.products?.useSearch! const fn = (provider: Provider) => provider.products?.useSearch!

View File

@ -5,6 +5,13 @@ export type CustomerTypes = {
customer: Customer customer: Customer
} }
export type CustomerHook<T extends CustomerTypes = CustomerTypes> = {
data: T['customer'] | null
fetchData: { customer: T['customer'] } | null
// actionInput: T['body']
// fetchInput: T['body']
}
export type CustomerSchema<T extends CustomerTypes = CustomerTypes> = { export type CustomerSchema<T extends CustomerTypes = CustomerTypes> = {
endpoint: { endpoint: {
options: {} options: {}

View File

@ -1,14 +1,25 @@
import type { Wishlist as BCWishlist } from '../../bigcommerce/api/wishlist' import * as Cart from './cart'
import type { Customer as BCCustomer } from '../../bigcommerce/api/customers' import * as Checkout from './checkout'
import type { SearchProductsData as BCSearchProductsData } from '../../bigcommerce/api/catalog/products' import * as Common from './common'
import * as Customer from './customer'
import * as Login from './login'
import * as Logout from './logout'
import * as Page from './page'
import * as Product from './product'
import * as Signup from './signup'
import * as Site from './site'
import * as Wishlist from './wishlist'
export * from './common' export type {
Cart,
// TODO: Properly define this type Checkout,
export interface Wishlist extends BCWishlist {} Common,
Customer,
// TODO: Properly define this type Login,
export interface Customer extends BCCustomer {} Logout,
Page,
// TODO: Properly define this type Product,
export interface SearchProductsData extends BCSearchProductsData {} Signup,
Site,
Wishlist,
}

View File

@ -7,14 +7,18 @@ export type LoginTypes = {
body: LoginBody body: LoginBody
} }
export type LoginHook<T extends LoginTypes = LoginTypes> = {
data: null
actionInput: LoginBody
fetchInput: LoginBody
body: T['body']
}
export type LoginSchema<T extends LoginTypes = LoginTypes> = { export type LoginSchema<T extends LoginTypes = LoginTypes> = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
login: { login: LoginHook<T>
data: null
body: T['body']
}
} }
} }
} }

View File

@ -1,11 +1,17 @@
export type LogoutSchema = { export type LogoutTypes = {
body: { redirectTo?: string }
}
export type LogoutHook<T extends LogoutTypes = LogoutTypes> = {
data: null
body: T['body']
}
export type LogoutSchema<T extends LogoutTypes = LogoutTypes> = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
logout: { logout: LogoutHook<T>
data: null
body: { redirectTo?: string }
}
} }
} }
} }

View File

@ -42,8 +42,23 @@ export type Product = {
options: ProductOption[] options: ProductOption[]
} }
export type SearchProductsBody = {
search?: string
categoryId?: string
brandId?: string
sort?: string
}
export type ProductTypes = { export type ProductTypes = {
product: Product product: Product
searchBody: SearchProductsBody
}
export type SearchProductsHook<T extends ProductTypes = ProductTypes> = {
data: T['product'][]
body: T['searchBody']
input: T['searchBody']
fetchInput: T['searchBody']
} }
export type ProductsSchema<T extends ProductTypes = ProductTypes> = { export type ProductsSchema<T extends ProductTypes = ProductTypes> = {
@ -55,12 +70,7 @@ export type ProductsSchema<T extends ProductTypes = ProductTypes> = {
products: T['product'][] products: T['product'][]
found: boolean found: boolean
} }
body: { body: SearchProductsHook<T>['body']
search?: string
category?: string
brand?: string
sort?: string
}
} }
} }
} }

View File

@ -9,14 +9,18 @@ export type SignupTypes = {
body: SignupBody body: SignupBody
} }
export type SignupHook<T extends SignupTypes = SignupTypes> = {
data: null
body: T['body']
actionInput: T['body']
fetchInput: T['body']
}
export type SignupSchema<T extends SignupTypes = SignupTypes> = { export type SignupSchema<T extends SignupTypes = SignupTypes> = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
signup: { signup: SignupHook<T>
data: null
body: T['body']
}
} }
} }
} }

View File

@ -11,21 +11,42 @@ export type WishlistTypes = {
itemBody: WishlistItemBody itemBody: WishlistItemBody
} }
export type GetWishlistHook<T extends WishlistTypes = WishlistTypes> = {
data: T['wishlist'] | null
body: { includeProducts?: boolean }
input: { includeProducts?: boolean }
fetchInput: { customerId: string; includeProducts?: boolean }
swrState: { isEmpty: boolean }
}
export type AddItemHook<T extends WishlistTypes = WishlistTypes> = {
data: T['wishlist']
body: { item: T['itemBody'] }
fetchInput: { item: T['itemBody'] }
actionInput: T['itemBody']
}
export type RemoveItemHook<T extends WishlistTypes = WishlistTypes> = {
data: T['wishlist'] | null
body: { itemId: string }
fetchInput: { itemId: string }
actionInput: { id: string }
input: { wishlist?: { includeProducts?: boolean } }
}
export type WishlistSchema<T extends WishlistTypes = WishlistTypes> = { export type WishlistSchema<T extends WishlistTypes = WishlistTypes> = {
endpoint: { endpoint: {
options: {} options: {}
handlers: { handlers: {
getWishlist: { getWishlist: GetWishlistHook<T> & {
data: T['wishlist'] | null data: T['wishlist'] | null
body: { customerToken?: string; includeProducts?: boolean } body: { customerToken?: string }
} }
addItem: { addItem: AddItemHook<T> & {
data: T['wishlist'] body: { customerToken?: string }
body: { customerToken?: string; item: T['itemBody'] }
} }
removeItem: { removeItem: RemoveItemHook<T> & {
data: T['wishlist'] | null body: { customerToken?: string }
body: { customerToken?: string; itemId: string }
} }
} }
} }

View File

@ -43,7 +43,12 @@ export type HookFetcherFn<H extends HookSchemaBase> = (
export type HookFetcherContext<H extends HookSchemaBase> = { export type HookFetcherContext<H extends HookSchemaBase> = {
options: HookFetcherOptions options: HookFetcherOptions
input: H['fetchInput'] input: H['fetchInput']
fetch: <T = any, B = H['body']>(options: FetcherOptions<B>) => Promise<T> fetch: {
(
options: FetcherOptions<H['body'] extends {} ? H['body'] : never>
): Promise<H['fetchData'] extends {} | null ? H['fetchData'] : any>
<T = any, B = any>(options: FetcherOptions<B>): Promise<T>
}
} }
export type HookFetcherOptions = { method?: string } & ( export type HookFetcherOptions = { method?: string } & (
@ -67,19 +72,21 @@ export type HookFunction<
: (input: Input) => T : (input: Input) => T
export type HookSchemaBase = { export type HookSchemaBase = {
// Data obj returned by the hook and fetch operation // Data obj returned by the hook
data: any data: any
// Input expected by the hook // Input expected by the hook
input: {} input?: {}
// Input expected before doing a fetch operation (aka fetch handler) // Input expected before doing a fetch operation (aka fetch handler)
fetchInput?: {} fetchInput?: {}
// Data expected by the fetch operation // Body object expected by the fetch operation
body?: {} body?: {}
// Data returned by the fetch operation
fetchData?: any
} }
export type SWRHookSchemaBase = HookSchemaBase & { export type SWRHookSchemaBase = HookSchemaBase & {
// Custom state added to the response object of SWR // Custom state added to the response object of SWR
swrState: {} swrState?: {}
} }
export type MutationSchemaBase = HookSchemaBase & { export type MutationSchemaBase = HookSchemaBase & {
@ -101,8 +108,6 @@ export type SWRHook<H extends SWRHookSchemaBase> = {
fetcher?: HookFetcherFn<H> fetcher?: HookFetcherFn<H>
} }
type X = {} & undefined
export type SWRHookContext<H extends SWRHookSchemaBase> = { export type SWRHookContext<H extends SWRHookSchemaBase> = {
useData(context?: { useData(context?: {
input?: HookFetchInput | HookSWRInput input?: HookFetchInput | HookSWRInput

View File

@ -2,10 +2,11 @@ import useSWR, { responseInterface } from 'swr'
import type { import type {
HookSWRInput, HookSWRInput,
HookFetchInput, HookFetchInput,
Fetcher,
SwrOptions,
HookFetcherOptions, HookFetcherOptions,
HookFetcherFn, HookFetcherFn,
Fetcher,
SwrOptions,
SWRHookSchemaBase,
} from './types' } from './types'
import defineProperty from './define-property' import defineProperty from './define-property'
import { CommerceError } from './errors' import { CommerceError } from './errors'
@ -14,15 +15,15 @@ export type ResponseState<Result> = responseInterface<Result, CommerceError> & {
isLoading: boolean isLoading: boolean
} }
export type UseData = <Data = any, FetchInput extends HookFetchInput = {}>( export type UseData = <H extends SWRHookSchemaBase>(
options: { options: {
fetchOptions: HookFetcherOptions fetchOptions: HookFetcherOptions
fetcher: HookFetcherFn<Data, FetchInput> fetcher: HookFetcherFn<H>
}, },
input: HookFetchInput | HookSWRInput, input: HookFetchInput | HookSWRInput,
fetcherFn: Fetcher, fetcherFn: Fetcher,
swrOptions?: SwrOptions<Data, FetchInput> swrOptions?: SwrOptions<H['data'], H['fetchInput']>
) => ResponseState<Data> ) => ResponseState<H['data']>
const useData: UseData = (options, input, fetcherFn, swrOptions) => { const useData: UseData = (options, input, fetcherFn, swrOptions) => {
const hookInput = Array.isArray(input) ? input : Object.entries(input) const hookInput = Array.isArray(input) ? input : Object.entries(input)

View File

@ -10,14 +10,14 @@ export function useFetcher() {
export function useHook< export function useHook<
P extends Provider, P extends Provider,
H extends MutationHook<any, any, any> | SWRHook<any, any, any> H extends MutationHook<any> | SWRHook<any>
>(fn: (provider: P) => H) { >(fn: (provider: P) => H) {
const { providerRef } = useCommerce<P>() const { providerRef } = useCommerce<P>()
const provider = providerRef.current const provider = providerRef.current
return fn(provider) return fn(provider)
} }
export function useSWRHook<H extends SWRHook<any, any, any>>( export function useSWRHook<H extends SWRHook<any>>(
hook: PickRequired<H, 'fetcher'> hook: PickRequired<H, 'fetcher'>
) { ) {
const fetcher = useFetcher() const fetcher = useFetcher()
@ -30,7 +30,7 @@ export function useSWRHook<H extends SWRHook<any, any, any>>(
}) })
} }
export function useMutationHook<H extends MutationHook<any, any, any>>( export function useMutationHook<H extends MutationHook<any>>(
hook: PickRequired<H, 'fetcher'> hook: PickRequired<H, 'fetcher'>
) { ) {
const fetcher = useFetcher() const fetcher = useFetcher()

View File

@ -1,10 +1,11 @@
import { useHook, useMutationHook } from '../utils/use-hook' import { useHook, useMutationHook } from '../utils/use-hook'
import { mutationFetcher } from '../utils/default-fetcher' import { mutationFetcher } from '../utils/default-fetcher'
import type { MutationHook } from '../utils/types' import type { MutationHook } from '../utils/types'
import type { AddItemHook } from '../types/wishlist'
import type { Provider } from '..' import type { Provider } from '..'
export type UseAddItem< export type UseAddItem<
H extends MutationHook<any, any, any> = MutationHook<any, {}, {}> H extends MutationHook<AddItemHook<any>> = MutationHook<AddItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher = mutationFetcher export const fetcher = mutationFetcher

View File

@ -1,28 +1,20 @@
import { useHook, useMutationHook } from '../utils/use-hook' import { useHook, useMutationHook } from '../utils/use-hook'
import { mutationFetcher } from '../utils/default-fetcher' import { mutationFetcher } from '../utils/default-fetcher'
import type { HookFetcherFn, MutationHook } from '../utils/types' import type { HookFetcherFn, MutationHook } from '../utils/types'
import type { RemoveItemHook } from '../types/wishlist'
import type { Provider } from '..' import type { Provider } from '..'
export type RemoveItemInput = {
id: string | number
}
export type UseRemoveItem< export type UseRemoveItem<
H extends MutationHook<any, any, any> = MutationHook< H extends MutationHook<RemoveItemHook<any>> = MutationHook<RemoveItemHook>
any | null,
{ wishlist?: any },
RemoveItemInput,
{}
>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<any | null, {}> = mutationFetcher export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher
const fn = (provider: Provider) => provider.wishlist?.useRemoveItem! const fn = (provider: Provider) => provider.wishlist?.useRemoveItem!
const useRemoveItem: UseRemoveItem = (input) => { const useRemoveItem: UseRemoveItem = (...args) => {
const hook = useHook(fn) const hook = useHook(fn)
return useMutationHook({ fetcher, ...hook })(input) return useMutationHook({ fetcher, ...hook })(...args)
} }
export default useRemoveItem export default useRemoveItem

View File

@ -1,25 +1,20 @@
import { useHook, useSWRHook } from '../utils/use-hook' import { useHook, useSWRHook } from '../utils/use-hook'
import { SWRFetcher } from '../utils/default-fetcher' import { SWRFetcher } from '../utils/default-fetcher'
import type { HookFetcherFn, SWRHook } from '../utils/types' import type { HookFetcherFn, SWRHook } from '../utils/types'
import type { Wishlist } from '../types' import type { GetWishlistHook } from '../types/wishlist'
import type { Provider } from '..' import type { Provider } from '..'
export type UseWishlist< export type UseWishlist<
H extends SWRHook<any, any, any> = SWRHook< H extends SWRHook<GetWishlistHook<any>> = SWRHook<GetWishlistHook>
Wishlist | null,
{ includeProducts?: boolean },
{ customerId?: number; includeProducts: boolean },
{ isEmpty?: boolean }
>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<Wishlist | null, any> = SWRFetcher export const fetcher: HookFetcherFn<GetWishlistHook> = SWRFetcher
const fn = (provider: Provider) => provider.wishlist?.useWishlist! const fn = (provider: Provider) => provider.wishlist?.useWishlist!
const useWishlist: UseWishlist = (input) => { const useWishlist: UseWishlist = (...args) => {
const hook = useHook(fn) const hook = useHook(fn)
return useSWRHook({ fetcher, ...hook })(input) return useSWRHook({ fetcher, ...hook })(...args)
} }
export default useWishlist export default useWishlist