mirror of
https://github.com/vercel/commerce.git
synced 2025-05-18 07:26:59 +00:00
Working local
This commit is contained in:
parent
23b69ec442
commit
6de60ce29c
@ -72,9 +72,8 @@ export type APIProvider = {
|
|||||||
operations: APIOperations<any>
|
operations: APIOperations<any>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommerceAPI<
|
export type CommerceAPI<P extends APIProvider = APIProvider> =
|
||||||
P extends APIProvider = APIProvider
|
CommerceAPICore<P> & AllOperations<P>
|
||||||
> = CommerceAPICore<P> & AllOperations<P>
|
|
||||||
|
|
||||||
export class CommerceAPICore<P extends APIProvider = APIProvider> {
|
export class CommerceAPICore<P extends APIProvider = APIProvider> {
|
||||||
constructor(readonly provider: P) {}
|
constructor(readonly provider: P) {}
|
||||||
@ -134,17 +133,17 @@ export function getEndpoint<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createEndpoint = <API extends GetAPISchema<any, any>>(
|
export const createEndpoint =
|
||||||
endpoint: API['endpoint']
|
<API extends GetAPISchema<any, any>>(endpoint: API['endpoint']) =>
|
||||||
) => <P extends APIProvider>(
|
<P extends APIProvider>(
|
||||||
commerce: CommerceAPI<P>,
|
commerce: CommerceAPI<P>,
|
||||||
context?: Partial<API['endpoint']> & {
|
context?: Partial<API['endpoint']> & {
|
||||||
config?: P['config']
|
config?: P['config']
|
||||||
options?: API['schema']['endpoint']['options']
|
options?: API['schema']['endpoint']['options']
|
||||||
}
|
}
|
||||||
): NextApiHandler => {
|
): NextApiHandler => {
|
||||||
return getEndpoint(commerce, { ...endpoint, ...context })
|
return getEndpoint(commerce, { ...endpoint, ...context })
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommerceAPIConfig {
|
export interface CommerceAPIConfig {
|
||||||
locale?: string
|
locale?: string
|
||||||
|
@ -69,14 +69,6 @@ function withCommerceConfig(nextConfig = {}) {
|
|||||||
}, exclude)
|
}, exclude)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.COMMERCE_PROVIDER == 'local') {
|
|
||||||
tsconfig.exclude = tsconfig.exclude.concat(
|
|
||||||
'components/cart',
|
|
||||||
'components/auth',
|
|
||||||
'components/wishlist'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
tsconfigPath,
|
tsconfigPath,
|
||||||
prettier.format(JSON.stringify(tsconfig), { parser: 'json' })
|
prettier.format(JSON.stringify(tsconfig), { parser: 'json' })
|
||||||
|
@ -1 +0,0 @@
|
|||||||
COMMERCE_PROVIDER=local
|
|
@ -1 +0,0 @@
|
|||||||
## Local Provider
|
|
@ -1,32 +0,0 @@
|
|||||||
import {
|
|
||||||
CommerceAPI,
|
|
||||||
CommerceAPIConfig,
|
|
||||||
getCommerceApi as commerceApi,
|
|
||||||
} from '@commerce/api'
|
|
||||||
|
|
||||||
export interface LocalConfig extends CommerceAPIConfig {}
|
|
||||||
import * as operations from './operations'
|
|
||||||
import fetchGraphqlApi from './utils/fetch-graphql-api'
|
|
||||||
|
|
||||||
const config: LocalConfig = {
|
|
||||||
commerceUrl: '',
|
|
||||||
apiToken: '',
|
|
||||||
customerCookie: '',
|
|
||||||
cartCookie: '',
|
|
||||||
cartCookieMaxAge: 16000000,
|
|
||||||
fetch: fetchGraphqlApi,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const provider = {
|
|
||||||
config,
|
|
||||||
operations,
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Provider = typeof provider
|
|
||||||
export type LocalAPI<P extends Provider = Provider> = CommerceAPI<P>
|
|
||||||
|
|
||||||
export function getCommerceApi<P extends Provider>(
|
|
||||||
customProvider: P = provider as any
|
|
||||||
): LocalAPI<P> {
|
|
||||||
return commerceApi(customProvider)
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
import type {
|
|
||||||
OperationContext,
|
|
||||||
OperationOptions,
|
|
||||||
} from '@commerce/api/operations'
|
|
||||||
import {
|
|
||||||
GetAllPagesQuery,
|
|
||||||
GetAllPagesQueryVariables,
|
|
||||||
PageEdge,
|
|
||||||
} from '../../schema'
|
|
||||||
import { normalizePages } from '../../utils'
|
|
||||||
import type { ShopifyConfig, Provider } from '..'
|
|
||||||
import type { GetAllPagesOperation, Page } from '../../types/page'
|
|
||||||
import getAllPagesQuery from '../../utils/queries/get-all-pages-query'
|
|
||||||
|
|
||||||
export default function getAllPagesOperation({
|
|
||||||
commerce,
|
|
||||||
}: OperationContext<Provider>) {
|
|
||||||
async function getAllPages<T extends GetAllPagesOperation>(opts?: {
|
|
||||||
config?: Partial<ShopifyConfig>
|
|
||||||
preview?: boolean
|
|
||||||
}): Promise<T['data']>
|
|
||||||
|
|
||||||
async function getAllPages<T extends GetAllPagesOperation>(
|
|
||||||
opts: {
|
|
||||||
config?: Partial<ShopifyConfig>
|
|
||||||
preview?: boolean
|
|
||||||
} & OperationOptions
|
|
||||||
): Promise<T['data']>
|
|
||||||
|
|
||||||
async function getAllPages<T extends GetAllPagesOperation>({
|
|
||||||
query = getAllPagesQuery,
|
|
||||||
config,
|
|
||||||
variables,
|
|
||||||
}: {
|
|
||||||
url?: string
|
|
||||||
config?: Partial<ShopifyConfig>
|
|
||||||
variables?: GetAllPagesQueryVariables
|
|
||||||
preview?: boolean
|
|
||||||
query?: string
|
|
||||||
} = {}): Promise<T['data']> {
|
|
||||||
const { fetch, locale, locales = ['en-US'] } = commerce.getConfig(config)
|
|
||||||
|
|
||||||
const { data } = await fetch<GetAllPagesQuery, GetAllPagesQueryVariables>(
|
|
||||||
query,
|
|
||||||
{
|
|
||||||
variables,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
...(locale && {
|
|
||||||
headers: {
|
|
||||||
'Accept-Language': locale,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
|
||||||
pages: locales.reduce<Page[]>(
|
|
||||||
(arr, locale) =>
|
|
||||||
arr.concat(normalizePages(data.pages.edges as PageEdge[], locale)),
|
|
||||||
[]
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getAllPages
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
import type { LocalConfig, Provider } from '..'
|
|
||||||
import type { OperationContext } from '@commerce/api/operations'
|
|
||||||
import { GetAllProductPathsOperation } from '../../types/product'
|
|
||||||
|
|
||||||
export default function getAllProductPathsOperation({
|
|
||||||
commerce,
|
|
||||||
}: OperationContext<Provider>) {
|
|
||||||
async function getAllProductPaths<T extends GetAllProductPathsOperation>({
|
|
||||||
query,
|
|
||||||
config,
|
|
||||||
variables,
|
|
||||||
}: {
|
|
||||||
query?: string
|
|
||||||
config?: LocalConfig
|
|
||||||
variables?: T['variables']
|
|
||||||
} = {}): Promise<T['data']> {
|
|
||||||
return {
|
|
||||||
products: [
|
|
||||||
{
|
|
||||||
path: `/hank`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getAllProductPaths
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
import type { Provider } from '..'
|
|
||||||
import type { Product } from '@commerce/types/product'
|
|
||||||
import type { OperationContext } from '@commerce/api/operations'
|
|
||||||
|
|
||||||
export default function getAllProductsOperation({}: OperationContext<Provider>) {
|
|
||||||
async function getAllProducts(): Promise<{ products: Product[] }> {
|
|
||||||
const product = {
|
|
||||||
id: 'Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjA=',
|
|
||||||
name: 'New Short Sleeve T-Shirt',
|
|
||||||
description: '',
|
|
||||||
vendor: 'Next.js',
|
|
||||||
path: '/new-short-sleeve-t-shirt',
|
|
||||||
slug: 'new-short-sleeve-t-shirt',
|
|
||||||
price: { value: 25, currencyCode: 'USD' },
|
|
||||||
images: [
|
|
||||||
{
|
|
||||||
url: '/assets/t-shirt-0.png',
|
|
||||||
altText: null,
|
|
||||||
width: 1000,
|
|
||||||
height: 1000,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
variants: [],
|
|
||||||
options: [],
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
products: [product],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getAllProducts
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
import type {
|
|
||||||
OperationContext,
|
|
||||||
OperationOptions,
|
|
||||||
} from '@commerce/api/operations'
|
|
||||||
import { normalizePage } from '../../utils'
|
|
||||||
import type { ShopifyConfig, Provider } from '..'
|
|
||||||
import {
|
|
||||||
GetPageQuery,
|
|
||||||
GetPageQueryVariables,
|
|
||||||
Page as ShopifyPage,
|
|
||||||
} from '../../schema'
|
|
||||||
import { GetPageOperation } from '../../types/page'
|
|
||||||
import getPageQuery from '../../utils/queries/get-page-query'
|
|
||||||
|
|
||||||
export default function getPageOperation({
|
|
||||||
commerce,
|
|
||||||
}: OperationContext<Provider>) {
|
|
||||||
async function getPage<T extends GetPageOperation>(opts: {
|
|
||||||
variables: T['variables']
|
|
||||||
config?: Partial<ShopifyConfig>
|
|
||||||
preview?: boolean
|
|
||||||
}): Promise<T['data']>
|
|
||||||
|
|
||||||
async function getPage<T extends GetPageOperation>(
|
|
||||||
opts: {
|
|
||||||
variables: T['variables']
|
|
||||||
config?: Partial<ShopifyConfig>
|
|
||||||
preview?: boolean
|
|
||||||
} & OperationOptions
|
|
||||||
): Promise<T['data']>
|
|
||||||
|
|
||||||
async function getPage<T extends GetPageOperation>({
|
|
||||||
query = getPageQuery,
|
|
||||||
variables,
|
|
||||||
config,
|
|
||||||
}: {
|
|
||||||
query?: string
|
|
||||||
variables: T['variables']
|
|
||||||
config?: Partial<ShopifyConfig>
|
|
||||||
preview?: boolean
|
|
||||||
}): Promise<T['data']> {
|
|
||||||
const { fetch, locale = 'en-US' } = commerce.getConfig(config)
|
|
||||||
|
|
||||||
const {
|
|
||||||
data: { node: page },
|
|
||||||
} = await fetch<GetPageQuery, GetPageQueryVariables>(
|
|
||||||
query,
|
|
||||||
{
|
|
||||||
variables,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
...(locale && {
|
|
||||||
headers: {
|
|
||||||
'Accept-Language': locale,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return page ? { page: normalizePage(page as ShopifyPage, locale) } : {}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getPage
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import type { Product } from '@commerce/types/product'
|
|
||||||
|
|
||||||
export default function getProductOperation() {
|
|
||||||
async function getProduct(): Promise<Product | {} | any> {
|
|
||||||
return {
|
|
||||||
product: [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getProduct
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
import type {
|
|
||||||
OperationContext,
|
|
||||||
OperationOptions,
|
|
||||||
} from '@commerce/api/operations'
|
|
||||||
import { GetSiteInfoQueryVariables } from '../../schema'
|
|
||||||
import type { ShopifyConfig, Provider } from '..'
|
|
||||||
import { GetSiteInfoOperation } from '../../types/site'
|
|
||||||
|
|
||||||
import { getCategories, getBrands, getSiteInfoQuery } from '../../utils'
|
|
||||||
|
|
||||||
export default function getSiteInfoOperation({
|
|
||||||
commerce,
|
|
||||||
}: OperationContext<Provider>) {
|
|
||||||
async function getSiteInfo<T extends GetSiteInfoOperation>(opts?: {
|
|
||||||
config?: Partial<ShopifyConfig>
|
|
||||||
preview?: boolean
|
|
||||||
}): Promise<T['data']>
|
|
||||||
|
|
||||||
async function getSiteInfo<T extends GetSiteInfoOperation>(
|
|
||||||
opts: {
|
|
||||||
config?: Partial<ShopifyConfig>
|
|
||||||
preview?: boolean
|
|
||||||
} & OperationOptions
|
|
||||||
): Promise<T['data']>
|
|
||||||
|
|
||||||
async function getSiteInfo<T extends GetSiteInfoOperation>({
|
|
||||||
query = getSiteInfoQuery,
|
|
||||||
config,
|
|
||||||
variables,
|
|
||||||
}: {
|
|
||||||
query?: string
|
|
||||||
config?: Partial<ShopifyConfig>
|
|
||||||
preview?: boolean
|
|
||||||
variables?: GetSiteInfoQueryVariables
|
|
||||||
} = {}): Promise<T['data']> {
|
|
||||||
const cfg = commerce.getConfig(config)
|
|
||||||
|
|
||||||
const categories = await getCategories(cfg)
|
|
||||||
const brands = await getBrands(cfg)
|
|
||||||
/*
|
|
||||||
const { fetch, locale } = cfg
|
|
||||||
const { data } = await fetch<GetSiteInfoQuery, GetSiteInfoQueryVariables>(
|
|
||||||
query,
|
|
||||||
{ variables },
|
|
||||||
{
|
|
||||||
...(locale && {
|
|
||||||
headers: {
|
|
||||||
'Accept-Language': locale,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
|
|
||||||
return {
|
|
||||||
categories,
|
|
||||||
brands,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getSiteInfo
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
export { default as getAllPages } from './get-all-pages'
|
|
||||||
export { default as getPage } from './get-page'
|
|
||||||
export { default as getAllProducts } from './get-all-products'
|
|
||||||
export { default as getAllProductPaths } from './get-all-product-paths'
|
|
||||||
export { default as getProduct } from './get-product'
|
|
||||||
export { default as getSiteInfo } from './get-site-info'
|
|
||||||
export { default as login } from './login'
|
|
@ -1,48 +0,0 @@
|
|||||||
import type { ServerResponse } from 'http'
|
|
||||||
import type { OperationContext } from '@commerce/api/operations'
|
|
||||||
import type { LoginOperation } from '../../types/login'
|
|
||||||
import type { ShopifyConfig, Provider } from '..'
|
|
||||||
import {
|
|
||||||
customerAccessTokenCreateMutation,
|
|
||||||
setCustomerToken,
|
|
||||||
throwUserErrors,
|
|
||||||
} from '../../utils'
|
|
||||||
import { CustomerAccessTokenCreateMutation } from '../../schema'
|
|
||||||
|
|
||||||
export default function loginOperation({
|
|
||||||
commerce,
|
|
||||||
}: OperationContext<Provider>) {
|
|
||||||
async function login<T extends LoginOperation>({
|
|
||||||
query = customerAccessTokenCreateMutation,
|
|
||||||
variables,
|
|
||||||
config,
|
|
||||||
}: {
|
|
||||||
query?: string
|
|
||||||
variables: T['variables']
|
|
||||||
res: ServerResponse
|
|
||||||
config?: ShopifyConfig
|
|
||||||
}): Promise<T['data']> {
|
|
||||||
config = commerce.getConfig(config)
|
|
||||||
|
|
||||||
const {
|
|
||||||
data: { customerAccessTokenCreate },
|
|
||||||
} = await config.fetch<CustomerAccessTokenCreateMutation>(query, {
|
|
||||||
variables,
|
|
||||||
})
|
|
||||||
|
|
||||||
throwUserErrors(customerAccessTokenCreate?.customerUserErrors)
|
|
||||||
|
|
||||||
const customerAccessToken = customerAccessTokenCreate?.customerAccessToken
|
|
||||||
const accessToken = customerAccessToken?.accessToken
|
|
||||||
|
|
||||||
if (accessToken) {
|
|
||||||
setCustomerToken(accessToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
result: customerAccessToken?.accessToken,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return login
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
import type { GraphQLFetcher } from '@commerce/api'
|
|
||||||
import fetch from './fetch'
|
|
||||||
|
|
||||||
import { API_URL, API_TOKEN } from '../../const'
|
|
||||||
import { getError } from '../../utils/handle-fetch-response'
|
|
||||||
|
|
||||||
const fetchGraphqlApi: GraphQLFetcher = async (
|
|
||||||
query: string,
|
|
||||||
{ variables } = {},
|
|
||||||
fetchOptions
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const res = await fetch(API_URL, {
|
|
||||||
...fetchOptions,
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'X-Shopify-Storefront-Access-Token': API_TOKEN!,
|
|
||||||
...fetchOptions?.headers,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query,
|
|
||||||
variables,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
const { data, errors, status } = await res.json()
|
|
||||||
|
|
||||||
if (errors) {
|
|
||||||
throw getError(errors, status)
|
|
||||||
}
|
|
||||||
|
|
||||||
return { data, res }
|
|
||||||
} catch (err) {
|
|
||||||
throw getError(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
message: `${err} \n Most likely related to an unexpected output. e.g the store might be protected with password or not available.`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
500
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default fetchGraphqlApi
|
|
@ -1,2 +0,0 @@
|
|||||||
import zeitFetch from '@vercel/fetch'
|
|
||||||
export default zeitFetch()
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"provider": "local",
|
|
||||||
"features": {
|
|
||||||
"cart": false,
|
|
||||||
"customer": false,
|
|
||||||
"wishlist": false
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjA=",
|
|
||||||
"name": "New Short Sleeve T-Shirt",
|
|
||||||
"vendor": "Next.js",
|
|
||||||
"path": "/new-short-sleeve-t-shirt",
|
|
||||||
"slug": "new-short-sleeve-t-shirt",
|
|
||||||
"price": { "value": 25, "currencyCode": "USD" },
|
|
||||||
"images": [
|
|
||||||
{
|
|
||||||
"url": "https://cdn.shopify.com/s/files/1/0434/0285/4564/products/short-sleeve-t-shirt-0.png?v=1622902418",
|
|
||||||
"altText": null,
|
|
||||||
"width": 1000,
|
|
||||||
"height": 1000
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"variants": [],
|
|
||||||
"options": []
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import {
|
|
||||||
CommerceConfig,
|
|
||||||
CommerceProvider as CoreCommerceProvider,
|
|
||||||
useCommerce as useCoreCommerce,
|
|
||||||
} from '@commerce'
|
|
||||||
|
|
||||||
import { localProvider } from './provider'
|
|
||||||
import type { LocalProvider } from './provider'
|
|
||||||
|
|
||||||
export { localProvider }
|
|
||||||
export type { LocalProvider }
|
|
||||||
|
|
||||||
export const localConfig: CommerceConfig = {
|
|
||||||
locale: 'en-us',
|
|
||||||
cartCookie: '',
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CommerceProvider({
|
|
||||||
children,
|
|
||||||
...config
|
|
||||||
}: {
|
|
||||||
children?: React.ReactNode
|
|
||||||
locale: string
|
|
||||||
} & Partial<CommerceConfig>) {
|
|
||||||
return (
|
|
||||||
<CoreCommerceProvider
|
|
||||||
provider={localProvider}
|
|
||||||
config={{ ...localConfig, ...config }}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</CoreCommerceProvider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useCommerce = () => useCoreCommerce<LocalProvider>()
|
|
@ -1,5 +0,0 @@
|
|||||||
const commerce = require('./commerce.config.json')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
commerce,
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
import { useMemo } from 'react'
|
|
||||||
import { useCommerce } from '..'
|
|
||||||
|
|
||||||
export function formatPrice({
|
|
||||||
amount,
|
|
||||||
currencyCode,
|
|
||||||
locale,
|
|
||||||
}: {
|
|
||||||
amount: number
|
|
||||||
currencyCode: string
|
|
||||||
locale: string
|
|
||||||
}) {
|
|
||||||
const formatCurrency = new Intl.NumberFormat(locale, {
|
|
||||||
style: 'currency',
|
|
||||||
currency: currencyCode,
|
|
||||||
})
|
|
||||||
|
|
||||||
return formatCurrency.format(amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatVariantPrice({
|
|
||||||
amount,
|
|
||||||
baseAmount,
|
|
||||||
currencyCode,
|
|
||||||
locale,
|
|
||||||
}: {
|
|
||||||
baseAmount: number
|
|
||||||
amount: number
|
|
||||||
currencyCode: string
|
|
||||||
locale: string
|
|
||||||
}) {
|
|
||||||
const hasDiscount = baseAmount > amount
|
|
||||||
const formatDiscount = new Intl.NumberFormat(locale, { style: 'percent' })
|
|
||||||
const discount = hasDiscount
|
|
||||||
? formatDiscount.format((baseAmount - amount) / baseAmount)
|
|
||||||
: null
|
|
||||||
|
|
||||||
const price = formatPrice({ amount, currencyCode, locale })
|
|
||||||
const basePrice = hasDiscount
|
|
||||||
? formatPrice({ amount: baseAmount, currencyCode, locale })
|
|
||||||
: null
|
|
||||||
|
|
||||||
return { price, basePrice, discount }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function usePrice(
|
|
||||||
data?: {
|
|
||||||
amount: number
|
|
||||||
baseAmount?: number
|
|
||||||
currencyCode: string
|
|
||||||
} | null
|
|
||||||
) {
|
|
||||||
const { amount, baseAmount, currencyCode } = data ?? {}
|
|
||||||
const { locale } = useCommerce()
|
|
||||||
const value = useMemo(() => {
|
|
||||||
if (typeof amount !== 'number' || !currencyCode) return ''
|
|
||||||
|
|
||||||
return baseAmount
|
|
||||||
? formatVariantPrice({ amount, baseAmount, currencyCode, locale })
|
|
||||||
: formatPrice({ amount, currencyCode, locale })
|
|
||||||
}, [amount, baseAmount, currencyCode])
|
|
||||||
|
|
||||||
return typeof value === 'string' ? { price: value } : value
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
import { useHook, useSWRHook } from '../utils/use-hook'
|
|
||||||
import { SWRFetcher } from '../utils/default-fetcher'
|
|
||||||
import type { HookFetcherFn, SWRHook } from '../utils/types'
|
|
||||||
import type { SearchProductsHook } from '../types/product'
|
|
||||||
import type { Provider } from '..'
|
|
||||||
|
|
||||||
export type UseSearch<
|
|
||||||
H extends SWRHook<SearchProductsHook<any>> = SWRHook<SearchProductsHook>
|
|
||||||
> = ReturnType<H['useHook']>
|
|
||||||
|
|
||||||
export const fetcher: HookFetcherFn<SearchProductsHook> = SWRFetcher
|
|
||||||
|
|
||||||
const fn = (provider: Provider) => provider.products?.useSearch!
|
|
||||||
|
|
||||||
const useSearch: UseSearch = (input) => {
|
|
||||||
const hook = useHook(fn)
|
|
||||||
return useSWRHook({ fetcher, ...hook })(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useSearch
|
|
@ -1,11 +0,0 @@
|
|||||||
export const localProvider = {
|
|
||||||
locale: 'en-us',
|
|
||||||
cartCookie: '',
|
|
||||||
fetcher: () => {},
|
|
||||||
cart: {},
|
|
||||||
customer: {},
|
|
||||||
products: {},
|
|
||||||
auth: {},
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LocalProvider = typeof localProvider
|
|
5586
framework/local-old/schema.d.ts
vendored
5586
framework/local-old/schema.d.ts
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
import type { APIProvider, CommerceAPIConfig } from '@commerce/api'
|
import type { APIProvider, CommerceAPIConfig } from '@commerce/api'
|
||||||
import { CommerceAPI, getCommerceApi as commerceApi } from '@commerce/api'
|
import { CommerceAPI, getCommerceApi as commerceApi } from '@commerce/api'
|
||||||
import fetchGraphqlApi from './utils/fetch-graphql-api'
|
import fetcher from './utils/fetch-local'
|
||||||
|
|
||||||
import getAllPages from './operations/get-all-pages'
|
import getAllPages from './operations/get-all-pages'
|
||||||
import getPage from './operations/get-page'
|
import getPage from './operations/get-page'
|
||||||
@ -11,15 +11,13 @@ import getAllProducts from './operations/get-all-products'
|
|||||||
import getProduct from './operations/get-product'
|
import getProduct from './operations/get-product'
|
||||||
|
|
||||||
export interface LocalConfig extends CommerceAPIConfig {}
|
export interface LocalConfig extends CommerceAPIConfig {}
|
||||||
|
|
||||||
const ONE_DAY = 60 * 60 * 24
|
|
||||||
const config: LocalConfig = {
|
const config: LocalConfig = {
|
||||||
commerceUrl: '',
|
commerceUrl: '',
|
||||||
apiToken: '',
|
apiToken: '',
|
||||||
cartCookie: '',
|
cartCookie: '',
|
||||||
customerCookie: '',
|
customerCookie: '',
|
||||||
cartCookieMaxAge: ONE_DAY * 30,
|
cartCookieMaxAge: 2592000,
|
||||||
fetch: fetchGraphqlApi,
|
fetch: fetcher,
|
||||||
}
|
}
|
||||||
|
|
||||||
const operations = {
|
const operations = {
|
||||||
|
@ -1,16 +1,25 @@
|
|||||||
import { Product } from '@commerce/types/product'
|
import { Product } from '@commerce/types/product'
|
||||||
|
import { GetAllProductsOperation } from '@commerce/types/product'
|
||||||
import type { OperationContext } from '@commerce/api/operations'
|
import type { OperationContext } from '@commerce/api/operations'
|
||||||
import type { Provider } from '../index'
|
import type { LocalConfig, Provider } from '../index'
|
||||||
|
import data from '../../data.json'
|
||||||
export type ProductVariables = { first?: number }
|
|
||||||
|
|
||||||
export default function getAllProductsOperation({
|
export default function getAllProductsOperation({
|
||||||
commerce,
|
commerce,
|
||||||
}: OperationContext<Provider>) {
|
}: OperationContext<Provider>) {
|
||||||
async function getAllProducts(): Promise<{ products: Product[] | any[] }> {
|
async function getAllProducts<T extends GetAllProductsOperation>({
|
||||||
|
query = '',
|
||||||
|
variables,
|
||||||
|
config,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: Partial<LocalConfig>
|
||||||
|
preview?: boolean
|
||||||
|
} = {}): Promise<{ products: Product[] | any[] }> {
|
||||||
|
console.log(data.products[0])
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
products: [],
|
products: data.products,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return getAllProducts
|
return getAllProducts
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { FetcherError } from '@commerce/utils/errors'
|
import { FetcherError } from '@commerce/utils/errors'
|
||||||
import type { GraphQLFetcher } from '@commerce/api'
|
import type { GraphQLFetcher } from '@commerce/api'
|
||||||
import { getCommerceApi } from '../'
|
import { getCommerceApi } from '../index'
|
||||||
import fetch from './fetch'
|
import fetch from './fetch'
|
||||||
|
|
||||||
const fetchGraphqlApi: GraphQLFetcher = async (
|
const fetchGraphqlApi: GraphQLFetcher = async (
|
||||||
@ -25,7 +25,7 @@ const fetchGraphqlApi: GraphQLFetcher = async (
|
|||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
if (json.errors) {
|
if (json.errors) {
|
||||||
throw new FetcherError({
|
throw new FetcherError({
|
||||||
errors: json.errors ?? [{ message: 'Failed to fetch' }],
|
errors: json.errors ?? [{ message: 'Failed to fetch for API' }],
|
||||||
status: res.status,
|
status: res.status,
|
||||||
})
|
})
|
||||||
}
|
}
|
@ -9,8 +9,44 @@
|
|||||||
"price": { "value": 25, "currencyCode": "USD" },
|
"price": { "value": 25, "currencyCode": "USD" },
|
||||||
"images": [
|
"images": [
|
||||||
{
|
{
|
||||||
"url": "/assets/drop-shirt-0",
|
"url": "/assets/drop-shirt-0.png",
|
||||||
"altText": null,
|
"altText": "Shirt",
|
||||||
|
"width": 1000,
|
||||||
|
"height": 1000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variants": [],
|
||||||
|
"options": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjA=",
|
||||||
|
"name": "New Short Sleeve T-Shirt",
|
||||||
|
"vendor": "Next.js",
|
||||||
|
"path": "/new-short-sleeve-t-shirt",
|
||||||
|
"slug": "new-short-sleeve-t-shirt",
|
||||||
|
"price": { "value": 25, "currencyCode": "USD" },
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"url": "/assets/drop-shirt-0.png",
|
||||||
|
"altText": "Shirt",
|
||||||
|
"width": 1000,
|
||||||
|
"height": 1000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variants": [],
|
||||||
|
"options": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzU0NDczMjUwMjQ0MjA=",
|
||||||
|
"name": "New Short Sleeve T-Shirt",
|
||||||
|
"vendor": "Next.js",
|
||||||
|
"path": "/new-short-sleeve-t-shirt",
|
||||||
|
"slug": "new-short-sleeve-t-shirt",
|
||||||
|
"price": { "value": 25, "currencyCode": "USD" },
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"url": "/assets/drop-shirt-0.png",
|
||||||
|
"altText": "Shirt",
|
||||||
"width": 1000,
|
"width": 1000,
|
||||||
"height": 1000
|
"height": 1000
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,8 @@
|
|||||||
import { Fetcher } from '@commerce/utils/types'
|
import { Fetcher } from '@commerce/utils/types'
|
||||||
|
|
||||||
const shopApiUrl = '/data.json'
|
export const fetcher: Fetcher = async () => {
|
||||||
|
console.log('FETCHER')
|
||||||
export const fetcher: Fetcher = async ({
|
const res = await fetch('./data.json')
|
||||||
url,
|
|
||||||
method = 'GET',
|
|
||||||
variables,
|
|
||||||
query,
|
|
||||||
body: bodyObj,
|
|
||||||
}) => {
|
|
||||||
const res = await fetch(shopApiUrl)
|
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const { data } = await res.json()
|
const { data } = await res.json()
|
||||||
return data
|
return data
|
||||||
|
@ -1,13 +1,2 @@
|
|||||||
import { useCallback } from 'react'
|
export * from '@commerce/product/use-price'
|
||||||
|
export { default } from '@commerce/product/use-price'
|
||||||
export function emptyHook() {
|
|
||||||
const useEmptyHook = async (options = {}) => {
|
|
||||||
return useCallback(async function () {
|
|
||||||
return Promise.resolve()
|
|
||||||
}, [])
|
|
||||||
}
|
|
||||||
|
|
||||||
return useEmptyHook
|
|
||||||
}
|
|
||||||
|
|
||||||
export default emptyHook
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Provider } from '@commerce'
|
import { fetcher } from './fetcher'
|
||||||
import { handler as useCart } from './cart/use-cart'
|
import { handler as useCart } from './cart/use-cart'
|
||||||
import { handler as useAddItem } from './cart/use-add-item'
|
import { handler as useAddItem } from './cart/use-add-item'
|
||||||
import { handler as useUpdateItem } from './cart/use-update-item'
|
import { handler as useUpdateItem } from './cart/use-update-item'
|
||||||
@ -8,11 +8,9 @@ import { handler as useSearch } from './product/use-search'
|
|||||||
import { handler as useLogin } from './auth/use-login'
|
import { handler as useLogin } from './auth/use-login'
|
||||||
import { handler as useLogout } from './auth/use-logout'
|
import { handler as useLogout } from './auth/use-logout'
|
||||||
import { handler as useSignup } from './auth/use-signup'
|
import { handler as useSignup } from './auth/use-signup'
|
||||||
import { fetcher } from './fetcher'
|
|
||||||
|
|
||||||
export type Provider = typeof localProvider
|
export type Provider = typeof localProvider
|
||||||
|
export const localProvider = {
|
||||||
export const localProvider: Provider = {
|
|
||||||
locale: 'en-us',
|
locale: 'en-us',
|
||||||
cartCookie: 'session',
|
cartCookie: 'session',
|
||||||
fetcher: fetcher,
|
fetcher: fetcher,
|
||||||
|
11033
package-lock.json
generated
Normal file
11033
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,7 @@
|
|||||||
"dot-object": "^2.1.4",
|
"dot-object": "^2.1.4",
|
||||||
"email-validator": "^2.0.4",
|
"email-validator": "^2.0.4",
|
||||||
"immutability-helper": "^3.1.1",
|
"immutability-helper": "^3.1.1",
|
||||||
|
"isomorphic-unfetch": "^3.1.0",
|
||||||
"js-cookie": "^2.2.1",
|
"js-cookie": "^2.2.1",
|
||||||
"keen-slider": "^5.4.1",
|
"keen-slider": "^5.4.1",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
|
@ -27,27 +27,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
|
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
|
||||||
"exclude": [
|
"exclude": ["node_modules", "framework/swell", "framework/vendure"]
|
||||||
"node_modules",
|
|
||||||
"framework/swell",
|
|
||||||
"framework/vendure",
|
|
||||||
"components/cart",
|
|
||||||
"components/auth",
|
|
||||||
"components/wishlist",
|
|
||||||
"components/cart",
|
|
||||||
"components/auth",
|
|
||||||
"components/wishlist",
|
|
||||||
"components/cart",
|
|
||||||
"components/auth",
|
|
||||||
"components/wishlist",
|
|
||||||
"components/cart",
|
|
||||||
"components/auth",
|
|
||||||
"components/wishlist",
|
|
||||||
"components/cart",
|
|
||||||
"components/auth",
|
|
||||||
"components/wishlist",
|
|
||||||
"components/cart",
|
|
||||||
"components/auth",
|
|
||||||
"components/wishlist"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
13
yarn.lock
13
yarn.lock
@ -3804,6 +3804,14 @@ isomorphic-form-data@2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
form-data "^2.3.2"
|
form-data "^2.3.2"
|
||||||
|
|
||||||
|
isomorphic-unfetch@^3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f"
|
||||||
|
integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==
|
||||||
|
dependencies:
|
||||||
|
node-fetch "^2.6.1"
|
||||||
|
unfetch "^4.2.0"
|
||||||
|
|
||||||
isomorphic-ws@4.0.1:
|
isomorphic-ws@4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc"
|
resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc"
|
||||||
@ -6648,6 +6656,11 @@ unc-path-regex@^0.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
|
resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
|
||||||
integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo=
|
integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo=
|
||||||
|
|
||||||
|
unfetch@^4.2.0:
|
||||||
|
version "4.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be"
|
||||||
|
integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==
|
||||||
|
|
||||||
uniq@^1.0.1:
|
uniq@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
|
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user