Updated Shopify Provider Structure (#340)

* Add codegen, update fragments & schemas

* Update checkout-create.ts

* Update checkout-create.ts

* Update README.md

* Update product mutations & queries

* Uptate customer fetch types

* Update schemas

* Start updates

* Moved Page, AllPages & Site Info

* Moved product, all products (paths)

* Add translations, update operations & fixes

* Update api endpoints, types & fixes

* Add api checkout endpoint

* Updates

* Fixes

* Update commerce.config.json

Co-authored-by: B <curciobelen@gmail.com>
This commit is contained in:
cond0r 2021-05-31 20:39:13 +03:00 committed by GitHub
parent 7f2a0d903a
commit 30174c597c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
127 changed files with 1954 additions and 1031 deletions

View File

@ -5,7 +5,7 @@ import Link from 'next/link'
import s from './CartItem.module.css'
import { Trash, Plus, Minus } from '@components/icons'
import { useUI } from '@components/ui/context'
import type { LineItem } from '@framework/types'
import type { LineItem } from '@commerce/types/cart'
import usePrice from '@framework/product/use-price'
import useUpdateItem from '@framework/cart/use-update-item'
import useRemoveItem from '@framework/cart/use-remove-item'

View File

@ -2,7 +2,7 @@ import { FC } from 'react'
import cn from 'classnames'
import Link from 'next/link'
import { useRouter } from 'next/router'
import type { Page } from '@framework/common/get-all-pages'
import type { Page } from '@commerce/types/page'
import getSlug from '@lib/get-slug'
import { Github, Vercel } from '@components/icons'
import { Logo, Container } from '@components/ui'

View File

@ -1,6 +1,6 @@
import { FC } from 'react'
import Link from 'next/link'
import type { Product } from '@commerce/types'
import type { Product } from '@commerce/types/product'
import { Grid } from '@components/ui'
import { ProductCard } from '@components/product'
import s from './HomeAllProductsGrid.module.css'

View File

@ -11,7 +11,7 @@ import CartSidebarView from '@components/cart/CartSidebarView'
import LoginView from '@components/auth/LoginView'
import { CommerceProvider } from '@framework'
import type { Page } from '@framework/common/get-all-pages'
import type { Page } from '@commerce/types/page'
const Loading = () => (
<div className="w-80 h-80 flex items-center text-center justify-center p-3">

View File

@ -1,7 +1,7 @@
import { FC } from 'react'
import Link from 'next/link'
import cn from 'classnames'
import type { LineItem } from '@framework/types'
import type { LineItem } from '@commerce/types/cart'
import useCart from '@framework/cart/use-cart'
import useCustomer from '@framework/customer/use-customer'
import { Avatar } from '@components/common'

View File

@ -1,7 +1,7 @@
import { FC } from 'react'
import cn from 'classnames'
import Link from 'next/link'
import type { Product } from '@commerce/types'
import type { Product } from '@commerce/types/product'
import s from './ProductCard.module.css'
import Image, { ImageProps } from 'next/image'
import WishlistButton from '@components/wishlist/WishlistButton'

View File

@ -5,7 +5,7 @@ import { FC, useEffect, useState } from 'react'
import s from './ProductView.module.css'
import { Swatch, ProductSlider } from '@components/product'
import { Button, Container, Text, useUI } from '@components/ui'
import type { Product } from '@commerce/types'
import type { Product } from '@commerce/types/product'
import usePrice from '@framework/product/use-price'
import { useAddItem } from '@framework/cart'
import { getVariant, SelectedOptions } from '../helpers'
@ -18,6 +18,8 @@ interface Props {
}
const ProductView: FC<Props> = ({ product }) => {
// TODO: fix this missing argument issue
/* @ts-ignore */
const addItem = useAddItem()
const { price } = usePrice({
amount: product.price.value,
@ -146,8 +148,11 @@ const ProductView: FC<Props> = ({ product }) => {
className={s.button}
onClick={addToCart}
loading={loading}
disabled={variant?.availableForSale === false}
>
Add to Cart
{variant?.availableForSale === false
? 'Not Available'
: 'Add To Cart'}
</Button>
</div>
</div>

View File

@ -1,4 +1,4 @@
import type { Product } from '@commerce/types'
import type { Product } from '@commerce/types/product'
export type SelectedOptions = Record<string, string | null>
export function getVariant(product: Product, opts: SelectedOptions) {

View File

@ -6,7 +6,7 @@ import useAddItem from '@framework/wishlist/use-add-item'
import useCustomer from '@framework/customer/use-customer'
import useWishlist from '@framework/wishlist/use-wishlist'
import useRemoveItem from '@framework/wishlist/use-remove-item'
import type { Product, ProductVariant } from '@commerce/types'
import type { Product, ProductVariant } from '@commerce/types/product'
type Props = {
productId: Product['id']

View File

@ -7,7 +7,7 @@ import { Trash } from '@components/icons'
import { Button, Text } from '@components/ui'
import { useUI } from '@components/ui/context'
import type { Product } from '@commerce/types'
import type { Product } from '@commerce/types/product'
import usePrice from '@framework/product/use-price'
import useAddItem from '@framework/cart/use-add-item'
import useRemoveItem from '@framework/wishlist/use-remove-item'
@ -18,14 +18,17 @@ interface Props {
const WishlistCard: FC<Props> = ({ product }) => {
const { price } = usePrice({
amount: product.prices?.price?.value,
baseAmount: product.prices?.retailPrice?.value,
currencyCode: product.prices?.price?.currencyCode!,
amount: product.price?.value,
baseAmount: product.price?.retailPrice,
currencyCode: product.price?.currencyCode!,
})
// @ts-ignore Wishlist is not always enabled
const removeItem = useRemoveItem({ wishlist: { includeProducts: true } })
const [loading, setLoading] = useState(false)
const [removing, setRemoving] = useState(false)
// TODO: fix this missing argument issue
/* @ts-ignore */
const addItem = useAddItem()
const { openSidebar } = useUI()

View File

@ -1,4 +1,4 @@
import { normalizeCart } from '@framework/lib/normalize'
import { normalizeCart } from '../../../lib/normalize'
import { parseCartItem } from '../../utils/parse-item'
import getCartCookie from '../../utils/get-cart-cookie'
import type { CartEndpoint } from '.'

View File

@ -1,7 +1,7 @@
import { normalizeCart } from '@framework/lib/normalize'
import { normalizeCart } from '../../../lib/normalize'
import { BigcommerceApiError } from '../../utils/errors'
import getCartCookie from '../../utils/get-cart-cookie'
import type { BigcommerceCart } from '../../../types'
import type { BigcommerceCart } from '../../../types/cart'
import type { CartEndpoint } from '.'
// Return current cart info

View File

@ -1,4 +1,4 @@
import { normalizeCart } from '@framework/lib/normalize'
import { normalizeCart } from '../../../lib/normalize'
import getCartCookie from '../../utils/get-cart-cookie'
import type { CartEndpoint } from '.'

View File

@ -1,4 +1,4 @@
import { normalizeCart } from '@framework/lib/normalize'
import { normalizeCart } from '../../../lib/normalize'
import { parseCartItem } from '../../utils/parse-item'
import getCartCookie from '../../utils/get-cart-cookie'
import type { CartEndpoint } from '.'

View File

@ -25,10 +25,10 @@ const getProducts: ProductsEndpoint['handlers']['getProducts'] = async ({
if (search) url.searchParams.set('keyword', search)
if (categoryId && Number.isInteger(Number(categoryId)))
url.searchParams.set('categories:in', categoryId)
url.searchParams.set('categories:in', String(categoryId))
if (brandId && Number.isInteger(Number(brandId)))
url.searchParams.set('brand_id', brandId)
url.searchParams.set('brand_id', String(brandId))
if (sort) {
const [_sort, direction] = sort.split('-')

View File

@ -32,12 +32,12 @@ export default function getAllProductPathsOperation({
config?: BigcommerceConfig
}): Promise<T['data']>
async function getAllProductPaths<
T extends GetAllProductPathsOperation
>(opts: {
async function getAllProductPaths<T extends GetAllProductPathsOperation>(
opts: {
variables?: T['variables']
config?: BigcommerceConfig
} & OperationOptions): Promise<T['data']>
} & OperationOptions
): Promise<T['data']>
async function getAllProductPaths<T extends GetAllProductPathsOperation>({
query = getAllProductPathsQuery,

View File

@ -5,6 +5,7 @@ import type {
import type { GetPageOperation, Page } from '../../types/page'
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
import type { BigcommerceConfig, Provider } from '..'
import { normalizePage } from '../../lib/normalize'
export default function getPageOperation({
commerce,
@ -44,7 +45,7 @@ export default function getPageOperation({
const page = firstPage as RecursiveRequired<typeof firstPage>
if (preview || page?.is_visible) {
return { page }
return { page: normalizePage(page as any) }
}
return {}
}

View File

@ -1,5 +1,5 @@
import type { ItemBody as WishlistItemBody } from '../wishlist'
import type { CartItemBody, OptionSelections } from '../../types'
import type { WishlistItemBody } from '../../types/wishlist'
import type { CartItemBody, OptionSelections } from '../../types/cart'
type BCWishlistItemBody = {
product_id: number

View File

@ -2,7 +2,7 @@ import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types'
import { CommerceError } from '@commerce/utils/errors'
import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item'
import type { AddItemHook } from '../types/cart'
import type { AddItemHook } from '@commerce/types/cart'
import useCart from './use-cart'
export default useAddItem as UseAddItem<typeof handler>

View File

@ -1,7 +1,7 @@
import { useMemo } from 'react'
import { SWRHook } from '@commerce/utils/types'
import useCart, { UseCart } from '@commerce/cart/use-cart'
import type { GetCartHook } from '../types/cart'
import type { GetCartHook } from '@commerce/types/cart'
export default useCart as UseCart<typeof handler>

View File

@ -5,11 +5,11 @@ import type {
} from '@commerce/utils/types'
import { ValidationError } from '@commerce/utils/errors'
import useRemoveItem, { UseRemoveItem } from '@commerce/cart/use-remove-item'
import type { Cart, LineItem, RemoveItemHook } from '../types/cart'
import type { Cart, LineItem, RemoveItemHook } from '@commerce/types/cart'
import useCart from './use-cart'
export type RemoveItemFn<T = any> = T extends LineItem
? (input?: RemoveItemActionInput<T>) => Promise<Cart | null>
? (input?: RemoveItemActionInput<T>) => Promise<Cart | null | undefined>
: (input: RemoveItemActionInput<T>) => Promise<Cart | null>
export type RemoveItemActionInput<T = any> = T extends LineItem

View File

@ -6,7 +6,7 @@ import type {
} from '@commerce/utils/types'
import { ValidationError } from '@commerce/utils/errors'
import useUpdateItem, { UseUpdateItem } from '@commerce/cart/use-update-item'
import type { LineItem, UpdateItemHook } from '../types/cart'
import type { LineItem, UpdateItemHook } from '@commerce/types/cart'
import { handler as removeItemHandler } from './use-remove-item'
import useCart from './use-cart'

View File

@ -1,6 +1,8 @@
import type { Product } from '@commerce/types'
import type { Cart, BigcommerceCart, LineItem } from '../types'
import type { Product } from '../types/product'
import type { Cart, BigcommerceCart, LineItem } from '../types/cart'
import type { Page } from '../types/page'
import update from './immutability'
import { definitions } from '../api/definitions/store-content'
function normalizeProductOption(productOption: any) {
const {
@ -69,6 +71,16 @@ export function normalizeProduct(productNode: any): Product {
})
}
export function normalizePage(page: definitions['page_Full']): Page {
return {
id: String(page.id),
name: page.name,
is_visible: page.is_visible,
sort_order: page.sort_order,
body: page.body,
}
}
export function normalizeCart(data: BigcommerceCart): Cart {
return {
id: data.id,

View File

@ -9,6 +9,7 @@ export type SearchProductsInput = {
categoryId?: number
brandId?: number
sort?: string
locale?: string
}
export const handler: SWRHook<SearchProductsHook> = {

View File

@ -1,9 +1,7 @@
import * as Core from '@commerce/types/page'
import { definitions } from '../api/definitions/store-content'
export * from '@commerce/types/page'
export type Page = definitions['page_Full']
export type Page = Core.Page
export type PageTypes = {
page: Page

View File

@ -148,6 +148,7 @@ export const createEndpoint = <API extends GetAPISchema<any, any>>(
export interface CommerceAPIConfig {
locale?: string
locales?: string[]
commerceUrl: string
apiToken: string
cartCookie: string

View File

@ -6,35 +6,44 @@ import {
useMemo,
useRef,
} from 'react'
import { Fetcher, SWRHook, MutationHook } from './utils/types'
import type { FetchCartInput } from './cart/use-cart'
import type { Cart, Wishlist, Customer, SearchProductsData } from './types'
import type {
Customer,
Wishlist,
Cart,
Product,
Signup,
Login,
Logout,
} from '@commerce/types'
import type { Fetcher, SWRHook, MutationHook } from './utils/types'
const Commerce = createContext<CommerceContextValue<any> | {}>({})
export type Provider = CommerceConfig & {
fetcher: Fetcher
cart?: {
useCart?: SWRHook<Cart | null, any, FetchCartInput>
useAddItem?: MutationHook<any, any, any>
useUpdateItem?: MutationHook<any, any, any>
useRemoveItem?: MutationHook<any, any, any>
useCart?: SWRHook<Cart.GetCartHook>
useAddItem?: MutationHook<Cart.AddItemHook>
useUpdateItem?: MutationHook<Cart.UpdateItemHook>
useRemoveItem?: MutationHook<Cart.RemoveItemHook>
}
wishlist?: {
useWishlist?: SWRHook<Wishlist | null, any, any>
useAddItem?: MutationHook<any, any, any>
useRemoveItem?: MutationHook<any, any, any>
useWishlist?: SWRHook<Wishlist.GetWishlistHook>
useAddItem?: MutationHook<Wishlist.AddItemHook>
useRemoveItem?: MutationHook<Wishlist.RemoveItemHook>
}
customer?: {
useCustomer?: SWRHook<Customer | null, any, any>
useCustomer?: SWRHook<Customer.CustomerHook>
}
products?: {
useSearch?: SWRHook<SearchProductsData, any, any>
useSearch?: SWRHook<Product.SearchProductsHook>
}
auth?: {
useSignup?: MutationHook<any, any, any>
useLogin?: MutationHook<any, any, any>
useLogout?: MutationHook<any, any, any>
useSignup?: MutationHook<Signup.SignupHook>
useLogin?: MutationHook<Login.LoginHook>
useLogout?: MutationHook<Logout.LogoutHook>
}
}

View File

@ -1,5 +1,14 @@
import type { Discount, Measurement, Image } from './common'
export type SelectedOption = {
// The option's id.
id?: string
// The product options name.
name: string
/// The product options value.
value: string
}
export type LineItem = {
id: string
variantId: string
@ -10,6 +19,7 @@ export type LineItem = {
// A human-friendly unique string automatically generated from the products name
path: string
variant: ProductVariant
options?: SelectedOption[]
}
export type ProductVariant = {
@ -86,7 +96,7 @@ export type CartItemBody = {
*/
export type CartTypes = {
cart: Cart
cart?: Cart
item: LineItem
itemBody: CartItemBody
}

View File

@ -1,5 +1,18 @@
// TODO: define this type
export type Page = any
export type Page = {
// ID of the Web page.
id: string
// Page name, as displayed on the storefront.
name: string
// Relative URL on the storefront for this page.
url?: string
// HTML or variable that populates this pages `<body>` element, in default/desktop view. Required in POST if page type is `raw`.
body: string
// If true, this page appears in the storefronts navigation menu.
is_visible?: boolean
// Order in which this page should display on the storefront. (Lower integers specify earlier display.)
sort_order?: number
}
export type PageTypes = {
page: Page

View File

@ -14,6 +14,8 @@ export type ProductPrice = {
}
export type ProductOption = {
__typename?: 'MultipleChoiceOption'
id: string
displayName: string
values: ProductOptionValues[]
}
@ -26,6 +28,7 @@ export type ProductOptionValues = {
export type ProductVariant = {
id: string | number
options: ProductOption[]
availableForSale?: boolean
}
export type Product = {
@ -44,9 +47,10 @@ export type Product = {
export type SearchProductsBody = {
search?: string
categoryId?: string
brandId?: string
categoryId?: string | number
brandId?: string | number
sort?: string
locale?: string
}
export type ProductTypes = {

View File

@ -2,7 +2,7 @@
export type Wishlist = any
export type WishlistItemBody = {
variantId: string
variantId: string | number
productId: string
}

View File

@ -121,3 +121,15 @@ const pages = await getAllPages({
config,
})
```
## Code generation
This provider makes use of GraphQL code generation. The [schema.graphql](./schema.graphql) and [schema.d.ts](./schema.d.ts) files contain the generated types & schema introspection results.
When developing the provider, changes to any GraphQL operations should be followed by re-generation of the types and schema files:
From the project root dir, run:
```sh
yarn generate:shopify
```

View File

@ -1 +0,0 @@
export default function () {}

View File

@ -1 +0,0 @@
export default function () {}

View File

@ -1 +0,0 @@
export default function () {}

View File

@ -1 +0,0 @@
export default function () {}

View File

@ -1 +0,0 @@
export default function () {}

View File

@ -1 +0,0 @@
export default function () {}

View File

@ -1 +0,0 @@
export default function () {}

View File

@ -1 +0,0 @@
export default function () {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -1,24 +1,16 @@
import isAllowedMethod from '../utils/is-allowed-method'
import createApiHandler, {
ShopifyApiHandler,
} from '../utils/create-api-handler'
import {
SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CHECKOUT_URL_COOKIE,
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
} from '../../const'
import { getConfig } from '..'
import associateCustomerWithCheckoutMutation from '../../utils/mutations/associate-customer-with-checkout'
const METHODS = ['GET']
const checkoutApi: ShopifyApiHandler<any> = async (req, res, config) => {
if (!isAllowedMethod(req, res, METHODS)) return
config = getConfig()
} from '../../../const'
import associateCustomerWithCheckoutMutation from '../../../utils/mutations/associate-customer-with-checkout'
import type { CheckoutEndpoint } from '.'
const checkout: CheckoutEndpoint['handlers']['checkout'] = async ({
req,
res,
config,
}) => {
const { cookies } = req
const checkoutUrl = cookies[SHOPIFY_CHECKOUT_URL_COOKIE]
const customerCookie = cookies[SHOPIFY_CUSTOMER_TOKEN_COOKIE]
@ -43,4 +35,4 @@ const checkoutApi: ShopifyApiHandler<any> = async (req, res, config) => {
}
}
export default createApiHandler(checkoutApi, {}, {})
export default checkout

View File

@ -0,0 +1,18 @@
import { GetAPISchema, createEndpoint } from '@commerce/api'
import checkoutEndpoint from '@commerce/api/endpoints/checkout'
import type { CheckoutSchema } from '../../../types/checkout'
import type { ShopifyAPI } from '../..'
import checkout from './checkout'
export type CheckoutAPI = GetAPISchema<ShopifyAPI, CheckoutSchema>
export type CheckoutEndpoint = CheckoutAPI['endpoint']
export const handlers: CheckoutEndpoint['handlers'] = { checkout }
const checkoutApi = createEndpoint<CheckoutAPI>({
handler: checkoutEndpoint,
handlers,
})
export default checkoutApi

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -0,0 +1 @@
export default function (_commerce: any) {}

View File

@ -1,12 +1,20 @@
import type { CommerceAPIConfig } from '@commerce/api'
import {
CommerceAPI,
CommerceAPIConfig,
getCommerceApi as commerceApi,
} from '@commerce/api'
import {
API_URL,
API_TOKEN,
SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
SHOPIFY_CHECKOUT_ID_COOKIE,
} from '../const'
import fetchGraphqlApi from './utils/fetch-graphql-api'
import * as operations from './operations'
if (!API_URL) {
throw new Error(
`The environment variable NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN is missing and it's required to access your store`
@ -18,44 +26,30 @@ if (!API_TOKEN) {
`The environment variable NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN is missing and it's required to access your store`
)
}
import fetchGraphqlApi from './utils/fetch-graphql-api'
export interface ShopifyConfig extends CommerceAPIConfig {}
export class Config {
private config: ShopifyConfig
const ONE_DAY = 60 * 60 * 24
constructor(config: ShopifyConfig) {
this.config = config
}
getConfig(userConfig: Partial<ShopifyConfig> = {}) {
return Object.entries(userConfig).reduce<ShopifyConfig>(
(cfg, [key, value]) => Object.assign(cfg, { [key]: value }),
{ ...this.config }
)
}
setConfig(newConfig: Partial<ShopifyConfig>) {
Object.assign(this.config, newConfig)
}
}
const config = new Config({
locale: 'en-US',
const config: ShopifyConfig = {
commerceUrl: API_URL,
apiToken: API_TOKEN!,
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
cartCookieMaxAge: 60 * 60 * 24 * 30,
fetch: fetchGraphqlApi,
apiToken: API_TOKEN,
customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE,
})
export function getConfig(userConfig?: Partial<ShopifyConfig>) {
return config.getConfig(userConfig)
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
cartCookieMaxAge: ONE_DAY * 30,
fetch: fetchGraphqlApi,
}
export function setConfig(newConfig: Partial<ShopifyConfig>) {
return config.setConfig(newConfig)
export const provider = {
config,
operations,
}
export type Provider = typeof provider
export type ShopifyAPI<P extends Provider = Provider> = CommerceAPI<P>
export function getCommerceApi<P extends Provider>(
customProvider: P = provider as any
): ShopifyAPI<P> {
return commerceApi(customProvider)
}

View File

@ -0,0 +1,67 @@
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
}

View File

@ -0,0 +1,55 @@
import type {
OperationContext,
OperationOptions,
} from '@commerce/api/operations'
import { GetAllProductPathsOperation } from '../../types/product'
import {
GetAllProductPathsQuery,
GetAllProductPathsQueryVariables,
ProductEdge,
} from '../../schema'
import type { ShopifyConfig, Provider } from '..'
import { getAllProductsQuery } from '../../utils'
export default function getAllProductPathsOperation({
commerce,
}: OperationContext<Provider>) {
async function getAllProductPaths<
T extends GetAllProductPathsOperation
>(opts?: {
variables?: T['variables']
config?: ShopifyConfig
}): Promise<T['data']>
async function getAllProductPaths<T extends GetAllProductPathsOperation>(
opts: {
variables?: T['variables']
config?: ShopifyConfig
} & OperationOptions
): Promise<T['data']>
async function getAllProductPaths<T extends GetAllProductPathsOperation>({
query = getAllProductsQuery,
config,
variables,
}: {
query?: string
config?: ShopifyConfig
variables?: T['variables']
} = {}): Promise<T['data']> {
config = commerce.getConfig(config)
const { data } = await config.fetch<
GetAllProductPathsQuery,
GetAllProductPathsQueryVariables
>(query, { variables })
return {
products: data.products.edges.map(({ node: { handle } }) => ({
path: `/${handle}`,
})),
}
}
return getAllProductPaths
}

View File

@ -0,0 +1,67 @@
import type {
OperationContext,
OperationOptions,
} from '@commerce/api/operations'
import { GetAllProductsOperation } from '../../types/product'
import {
GetAllProductsQuery,
GetAllProductsQueryVariables,
Product as ShopifyProduct,
} from '../../schema'
import type { ShopifyConfig, Provider } from '..'
import getAllProductsQuery from '../../utils/queries/get-all-products-query'
import { normalizeProduct } from '../../utils'
export default function getAllProductsOperation({
commerce,
}: OperationContext<Provider>) {
async function getAllProducts<T extends GetAllProductsOperation>(opts?: {
variables?: T['variables']
config?: Partial<ShopifyConfig>
preview?: boolean
}): Promise<T['data']>
async function getAllProducts<T extends GetAllProductsOperation>(
opts: {
variables?: T['variables']
config?: Partial<ShopifyConfig>
preview?: boolean
} & OperationOptions
): Promise<T['data']>
async function getAllProducts<T extends GetAllProductsOperation>({
query = getAllProductsQuery,
variables,
config,
}: {
query?: string
variables?: T['variables']
config?: Partial<ShopifyConfig>
preview?: boolean
} = {}): Promise<T['data']> {
const { fetch, locale } = commerce.getConfig(config)
const { data } = await fetch<
GetAllProductsQuery,
GetAllProductsQueryVariables
>(
query,
{ variables },
{
...(locale && {
headers: {
'Accept-Language': locale,
},
}),
}
)
return {
products: data.products.edges.map(({ node }) =>
normalizeProduct(node as ShopifyProduct)
),
}
}
return getAllProducts
}

View File

@ -0,0 +1,64 @@
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
}

View File

@ -0,0 +1,63 @@
import type {
OperationContext,
OperationOptions,
} from '@commerce/api/operations'
import { GetProductOperation } from '../../types/product'
import { normalizeProduct, getProductQuery } from '../../utils'
import type { ShopifyConfig, Provider } from '..'
import { GetProductBySlugQuery, Product as ShopifyProduct } from '../../schema'
export default function getProductOperation({
commerce,
}: OperationContext<Provider>) {
async function getProduct<T extends GetProductOperation>(opts: {
variables: T['variables']
config?: Partial<ShopifyConfig>
preview?: boolean
}): Promise<T['data']>
async function getProduct<T extends GetProductOperation>(
opts: {
variables: T['variables']
config?: Partial<ShopifyConfig>
preview?: boolean
} & OperationOptions
): Promise<T['data']>
async function getProduct<T extends GetProductOperation>({
query = getProductQuery,
variables,
config: cfg,
}: {
query?: string
variables: T['variables']
config?: Partial<ShopifyConfig>
preview?: boolean
}): Promise<T['data']> {
const { fetch, locale } = commerce.getConfig(cfg)
const {
data: { productByHandle },
} = await fetch<GetProductBySlugQuery>(
query,
{
variables,
},
{
...(locale && {
headers: {
'Accept-Language': locale,
},
}),
}
)
return {
...(productByHandle && {
product: normalizeProduct(productByHandle as ShopifyProduct),
}),
}
}
return getProduct
}

View File

@ -0,0 +1,62 @@
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
}

View File

@ -0,0 +1,7 @@
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'

View File

@ -0,0 +1,48 @@
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
}

View File

@ -1,58 +0,0 @@
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import { ShopifyConfig, getConfig } from '..'
export type ShopifyApiHandler<
T = any,
H extends ShopifyHandlers = {},
Options extends {} = {}
> = (
req: NextApiRequest,
res: NextApiResponse<ShopifyApiResponse<T>>,
config: ShopifyConfig,
handlers: H,
// Custom configs that may be used by a particular handler
options: Options
) => void | Promise<void>
export type ShopifyHandler<T = any, Body = null> = (options: {
req: NextApiRequest
res: NextApiResponse<ShopifyApiResponse<T>>
config: ShopifyConfig
body: Body
}) => void | Promise<void>
export type ShopifyHandlers<T = any> = {
[k: string]: ShopifyHandler<T, any>
}
export type ShopifyApiResponse<T> = {
data: T | null
errors?: { message: string; code?: string }[]
}
export default function createApiHandler<
T = any,
H extends ShopifyHandlers = {},
Options extends {} = {}
>(
handler: ShopifyApiHandler<T, H, Options>,
handlers: H,
defaultOptions: Options
) {
return function getApiHandler({
config,
operations,
options,
}: {
config?: ShopifyConfig
operations?: Partial<H>
options?: Options extends {} ? Partial<Options> : never
} = {}): NextApiHandler {
const ops = { ...operations, ...handlers }
const opts = { ...defaultOptions, ...options }
return function apiHandler(req, res) {
return handler(req, res, getConfig(config), ops, opts)
}
}
}

View File

@ -1,41 +0,0 @@
import { ProductEdge } from '../../schema'
import { ShopifyConfig } from '..'
const fetchAllProducts = async ({
config,
query,
variables,
acc = [],
cursor,
}: {
config: ShopifyConfig
query: string
acc?: ProductEdge[]
variables?: any
cursor?: string
}): Promise<ProductEdge[]> => {
const { data } = await config.fetch(query, {
variables: { ...variables, cursor },
})
const edges: ProductEdge[] = 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

View File

@ -1,28 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next'
export default function isAllowedMethod(
req: NextApiRequest,
res: NextApiResponse,
allowedMethods: string[]
) {
const methods = allowedMethods.includes('OPTIONS')
? allowedMethods
: [...allowedMethods, 'OPTIONS']
if (!req.method || !methods.includes(req.method)) {
res.status(405)
res.setHeader('Allow', methods.join(', '))
res.end()
return false
}
if (req.method === 'OPTIONS') {
res.status(200)
res.setHeader('Allow', methods.join(', '))
res.setHeader('Content-Length', '0')
res.end()
return false
}
return true
}

View File

@ -1,2 +0,0 @@
export type WishlistItem = { product: any; id: number }
export default function () {}

View File

@ -1,31 +1,22 @@
import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types'
import { CommerceError, ValidationError } from '@commerce/utils/errors'
import useCustomer from '../customer/use-customer'
import createCustomerAccessTokenMutation from '../utils/mutations/customer-access-token-create'
import {
CustomerAccessTokenCreateInput,
CustomerUserError,
Mutation,
MutationCheckoutCreateArgs,
} from '../schema'
import { CommerceError } from '@commerce/utils/errors'
import useLogin, { UseLogin } from '@commerce/auth/use-login'
import { setCustomerToken, throwUserErrors } from '../utils'
import type { LoginHook } from '../types/login'
import useCustomer from '../customer/use-customer'
import {
setCustomerToken,
throwUserErrors,
customerAccessTokenCreateMutation,
} from '../utils'
import { Mutation, MutationCustomerAccessTokenCreateArgs } from '../schema'
export default useLogin as UseLogin<typeof handler>
const getErrorMessage = ({ code, message }: CustomerUserError) => {
switch (code) {
case 'UNIDENTIFIED_CUSTOMER':
message = 'Cannot find an account that matches the provided credentials'
break
}
return message
}
export const handler: MutationHook<null, {}, CustomerAccessTokenCreateInput> = {
export const handler: MutationHook<LoginHook> = {
fetchOptions: {
query: createCustomerAccessTokenMutation,
query: customerAccessTokenCreateMutation,
},
async fetcher({ input: { email, password }, options, fetch }) {
if (!(email && password)) {
@ -37,7 +28,7 @@ export const handler: MutationHook<null, {}, CustomerAccessTokenCreateInput> = {
const { customerAccessTokenCreate } = await fetch<
Mutation,
MutationCheckoutCreateArgs
MutationCustomerAccessTokenCreateArgs
>({
...options,
variables: {

View File

@ -1,13 +1,14 @@
import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types'
import useLogout, { UseLogout } from '@commerce/auth/use-logout'
import type { LogoutHook } from '../types/logout'
import useCustomer from '../customer/use-customer'
import customerAccessTokenDeleteMutation from '../utils/mutations/customer-access-token-delete'
import { getCustomerToken, setCustomerToken } from '../utils/customer-token'
export default useLogout as UseLogout<typeof handler>
export const handler: MutationHook<null> = {
export const handler: MutationHook<LogoutHook> = {
fetchOptions: {
query: customerAccessTokenDeleteMutation,
},

View File

@ -1,25 +1,20 @@
import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types'
import { CommerceError, ValidationError } from '@commerce/utils/errors'
import { CommerceError } from '@commerce/utils/errors'
import useSignup, { UseSignup } from '@commerce/auth/use-signup'
import type { SignupHook } from '../types/signup'
import useCustomer from '../customer/use-customer'
import {
CustomerCreateInput,
Mutation,
MutationCustomerCreateArgs,
} from '../schema'
import { Mutation, MutationCustomerCreateArgs } from '../schema'
import { customerCreateMutation } from '../utils/mutations'
import { handleAutomaticLogin, throwUserErrors } from '../utils'
import {
handleAutomaticLogin,
throwUserErrors,
customerCreateMutation,
} from '../utils'
export default useSignup as UseSignup<typeof handler>
export const handler: MutationHook<
null,
{},
CustomerCreateInput,
CustomerCreateInput
> = {
export const handler: MutationHook<SignupHook> = {
fetchOptions: {
query: customerCreateMutation,
},

View File

@ -2,18 +2,19 @@ import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types'
import { CommerceError } from '@commerce/utils/errors'
import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item'
import type { AddItemHook } from '../types/cart'
import useCart from './use-cart'
import {
checkoutLineItemAddMutation,
getCheckoutId,
checkoutToCart,
} from '../utils'
import { Cart, CartItemBody } from '../types'
import { Mutation, MutationCheckoutLineItemsAddArgs } from '../schema'
export default useAddItem as UseAddItem<typeof handler>
export const handler: MutationHook<Cart, {}, CartItemBody> = {
export const handler: MutationHook<AddItemHook> = {
fetchOptions: {
query: checkoutLineItemAddMutation,
},

View File

@ -1,22 +1,20 @@
import { useMemo } from 'react'
import useCommerceCart, {
FetchCartInput,
UseCart,
} from '@commerce/cart/use-cart'
import useCommerceCart, { UseCart } from '@commerce/cart/use-cart'
import { Cart } from '../types'
import { SWRHook } from '@commerce/utils/types'
import { checkoutCreate, checkoutToCart } from '../utils'
import getCheckoutQuery from '../utils/queries/get-checkout-query'
import { GetCartHook } from '../types/cart'
import {
GetCheckoutQuery,
GetCheckoutQueryVariables,
CheckoutDetailsFragment,
} from '../schema'
export default useCommerceCart as UseCart<typeof handler>
export const handler: SWRHook<
Cart | null,
{},
FetchCartInput,
{ isEmpty?: boolean }
> = {
export const handler: SWRHook<GetCartHook> = {
fetchOptions: {
query: getCheckoutQuery,
},

View File

@ -3,31 +3,29 @@ import type {
MutationHookContext,
HookFetcherContext,
} from '@commerce/utils/types'
import { RemoveCartItemBody } from '@commerce/types'
import { ValidationError } from '@commerce/utils/errors'
import useRemoveItem, {
RemoveItemInput as RemoveItemInputBase,
UseRemoveItem,
} from '@commerce/cart/use-remove-item'
import useRemoveItem, { UseRemoveItem } from '@commerce/cart/use-remove-item'
import type { Cart, LineItem, RemoveItemHook } from '../types/cart'
import useCart from './use-cart'
export type RemoveItemFn<T = any> = T extends LineItem
? (input?: RemoveItemActionInput<T>) => Promise<Cart | null | undefined>
: (input: RemoveItemActionInput<T>) => Promise<Cart | null>
export type RemoveItemActionInput<T = any> = T extends LineItem
? Partial<RemoveItemHook['actionInput']>
: RemoveItemHook['actionInput']
export default useRemoveItem as UseRemoveItem<typeof handler>
import {
checkoutLineItemRemoveMutation,
getCheckoutId,
checkoutToCart,
} from '../utils'
import { Cart, LineItem } from '../types'
import { Mutation, MutationCheckoutLineItemsRemoveArgs } from '../schema'
export type RemoveItemFn<T = any> = T extends LineItem
? (input?: RemoveItemInput<T>) => Promise<Cart | null>
: (input: RemoveItemInput<T>) => Promise<Cart | null>
export type RemoveItemInput<T = any> = T extends LineItem
? Partial<RemoveItemInputBase>
: RemoveItemInputBase
export default useRemoveItem as UseRemoveItem<typeof handler>
export const handler = {
fetchOptions: {
query: checkoutLineItemRemoveMutation,
@ -36,16 +34,14 @@ export const handler = {
input: { itemId },
options,
fetch,
}: HookFetcherContext<RemoveCartItemBody>) {
}: HookFetcherContext<RemoveItemHook>) {
const data = await fetch<Mutation, MutationCheckoutLineItemsRemoveArgs>({
...options,
variables: { checkoutId: getCheckoutId(), lineItemIds: [itemId] },
})
return checkoutToCart(data.checkoutLineItemsRemove)
},
useHook: ({
fetch,
}: MutationHookContext<Cart | null, RemoveCartItemBody>) => <
useHook: ({ fetch }: MutationHookContext<RemoveItemHook>) => <
T extends LineItem | undefined = undefined
>(
ctx: { item?: T } = {}

View File

@ -5,21 +5,21 @@ import type {
MutationHookContext,
} from '@commerce/utils/types'
import { ValidationError } from '@commerce/utils/errors'
import useUpdateItem, {
UpdateItemInput as UpdateItemInputBase,
UseUpdateItem,
} from '@commerce/cart/use-update-item'
import useUpdateItem, { UseUpdateItem } from '@commerce/cart/use-update-item'
import useCart from './use-cart'
import { handler as removeItemHandler } from './use-remove-item'
import type { Cart, LineItem, UpdateCartItemBody } from '../types'
import { checkoutToCart } from '../utils'
import { getCheckoutId, checkoutLineItemUpdateMutation } from '../utils'
import type { UpdateItemHook, LineItem } from '../types/cart'
import {
getCheckoutId,
checkoutLineItemUpdateMutation,
checkoutToCart,
} from '../utils'
import { Mutation, MutationCheckoutLineItemsUpdateArgs } from '../schema'
export type UpdateItemInput<T = any> = T extends LineItem
? Partial<UpdateItemInputBase<LineItem>>
: UpdateItemInputBase<LineItem>
export type UpdateItemActionInput<T = any> = T extends LineItem
? Partial<UpdateItemHook['actionInput']>
: UpdateItemHook['actionInput']
export default useUpdateItem as UseUpdateItem<typeof handler>
@ -31,7 +31,7 @@ export const handler = {
input: { itemId, item },
options,
fetch,
}: HookFetcherContext<UpdateCartItemBody>) {
}: HookFetcherContext<UpdateItemHook>) {
if (Number.isInteger(item.quantity)) {
// Also allow the update hook to remove an item if the quantity is lower than 1
if (item.quantity! < 1) {
@ -64,9 +64,7 @@ export const handler = {
return checkoutToCart(checkoutLineItemsUpdate)
},
useHook: ({
fetch,
}: MutationHookContext<Cart | null, UpdateCartItemBody>) => <
useHook: ({ fetch }: MutationHookContext<UpdateItemHook>) => <
T extends LineItem | undefined = undefined
>(
ctx: {
@ -78,7 +76,7 @@ export const handler = {
const { mutate } = useCart() as any
return useCallback(
debounce(async (input: UpdateItemInput<T>) => {
debounce(async (input: UpdateItemActionInput<T>) => {
const itemId = input.id ?? item?.id
const productId = input.productId ?? item?.productId
const variantId = input.productId ?? item?.variantId

View File

@ -0,0 +1,32 @@
{
"schema": {
"https://${NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN}/api/2021-01/graphql.json": {
"headers": {
"X-Shopify-Storefront-Access-Token": "${NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN}"
}
}
},
"documents": [
{
"./framework/shopify/**/*.{ts,tsx}": {
"noRequire": true
}
}
],
"generates": {
"./framework/shopify/schema.d.ts": {
"plugins": ["typescript", "typescript-operations"],
"config": {
"scalars": {
"ID": "string"
}
}
},
"./framework/shopify/schema.graphql": {
"plugins": ["schema-ast"]
}
},
"hooks": {
"afterAllFileWrite": ["prettier --write"]
}
}

View File

@ -1,42 +0,0 @@
import { getConfig, ShopifyConfig } from '../api'
import { PageEdge } from '../schema'
import { getAllPagesQuery } from '../utils/queries'
type Variables = {
first?: number
}
type ReturnType = {
pages: Page[]
}
export type Page = {
id: string
name: string
url: string
sort_order?: number
body: string
}
const getAllPages = async (options?: {
variables?: Variables
config: ShopifyConfig
preview?: boolean
}): Promise<ReturnType> => {
let { config, variables = { first: 250 } } = options ?? {}
config = getConfig(config)
const { locale } = config
const { data } = await config.fetch(getAllPagesQuery, { variables })
const pages = data.pages?.edges?.map(
({ node: { title: name, handle, ...node } }: PageEdge) => ({
...node,
url: `/${locale}/${handle}`,
name,
})
)
return { pages }
}
export default getAllPages

View File

@ -1,37 +0,0 @@
import { getConfig, ShopifyConfig } from '../api'
import getPageQuery from '../utils/queries/get-page-query'
import { Page } from './get-all-pages'
type Variables = {
id: string
}
export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
const getPage = async (options: {
variables: Variables
config: ShopifyConfig
preview?: boolean
}): Promise<GetPageResult> => {
let { config, variables } = options ?? {}
config = getConfig(config)
const { locale } = config
const { data } = await config.fetch(getPageQuery, {
variables,
})
const page = data.node
return {
page: page
? {
...page,
name: page.title,
url: `/${locale}/${page.handle}`,
}
: null,
}
}
export default getPage

View File

@ -1,31 +0,0 @@
import getCategories, { Category } from '../utils/get-categories'
import getVendors, { Brands } from '../utils/get-vendors'
import { getConfig, ShopifyConfig } from '../api'
export type GetSiteInfoResult<
T extends { categories: any[]; brands: any[] } = {
categories: Category[]
brands: Brands
}
> = T
const getSiteInfo = async (options?: {
variables?: any
config: ShopifyConfig
preview?: boolean
}): Promise<GetSiteInfoResult> => {
let { config } = options ?? {}
config = getConfig(config)
const categories = await getCategories(config)
const brands = await getVendors(config)
return {
categories,
brands,
}
}
export default getSiteInfo

View File

@ -1,24 +0,0 @@
import { getConfig, ShopifyConfig } from '../api'
import getCustomerIdQuery from '../utils/queries/get-customer-id-query'
import Cookies from 'js-cookie'
async function getCustomerId({
customerToken: customerAccesToken,
config,
}: {
customerToken: string
config?: ShopifyConfig
}): Promise<number | undefined> {
config = getConfig(config)
const { data } = await config.fetch(getCustomerIdQuery, {
variables: {
customerAccesToken:
customerAccesToken || Cookies.get(config.customerCookie),
},
})
return data.customer?.id
}
export default getCustomerId

View File

@ -1,18 +1,19 @@
import useCustomer, { UseCustomer } from '@commerce/customer/use-customer'
import { Customer } from '@commerce/types'
import type { CustomerHook } from '../types/customer'
import { SWRHook } from '@commerce/utils/types'
import { getCustomerQuery, getCustomerToken } from '../utils'
import { GetCustomerQuery, GetCustomerQueryVariables } from '../schema'
export default useCustomer as UseCustomer<typeof handler>
export const handler: SWRHook<Customer | null> = {
export const handler: SWRHook<CustomerHook> = {
fetchOptions: {
query: getCustomerQuery,
},
async fetcher({ options, fetch }) {
const customerAccessToken = getCustomerToken()
if (customerAccessToken) {
const data = await fetch({
const data = await fetch<GetCustomerQuery, GetCustomerQueryVariables>({
...options,
variables: { customerAccessToken: getCustomerToken() },
})

View File

@ -8,13 +8,17 @@ const fetcher: Fetcher = async ({
variables,
query,
}) => {
const { locale, ...vars } = variables ?? {}
return handleFetchResponse(
await fetch(url, {
method,
body: JSON.stringify({ query, variables }),
body: JSON.stringify({ query, variables: vars }),
headers: {
'X-Shopify-Storefront-Access-Token': API_TOKEN!,
'Content-Type': 'application/json',
...(locale && {
'Accept-Language': locale,
}),
},
})
)

View File

@ -36,4 +36,4 @@ export function CommerceProvider({ children, ...config }: ShopifyProps) {
)
}
export const useCommerce = () => useCoreCommerce()
export const useCommerce = () => useCoreCommerce<ShopifyProvider>()

View File

@ -1,29 +0,0 @@
import { CollectionEdge } from '../schema'
import { getConfig, ShopifyConfig } from '../api'
import getAllCollectionsQuery from '../utils/queries/get-all-collections-query'
const getAllCollections = async (options?: {
variables?: any
config: ShopifyConfig
preview?: boolean
}) => {
let { config, variables = { first: 250 } } = options ?? {}
config = getConfig(config)
const { data } = await config.fetch(getAllCollectionsQuery, { variables })
const edges = data.collections?.edges ?? []
const categories = edges.map(
({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({
entityId,
name,
path: `/${handle}`,
})
)
return {
categories,
}
}
export default getAllCollections

View File

@ -1,41 +0,0 @@
import { getConfig, ShopifyConfig } from '../api'
import { ProductEdge } from '../schema'
import getAllProductsPathsQuery from '../utils/queries/get-all-products-paths-query'
type ProductPath = {
path: string
}
export type ProductPathNode = {
node: ProductPath
}
type ReturnType = {
products: ProductPathNode[]
}
const getAllProductPaths = async (options?: {
variables?: any
config?: ShopifyConfig
preview?: boolean
}): Promise<ReturnType> => {
let { config, variables = { first: 100, sortKey: 'BEST_SELLING' } } =
options ?? {}
config = getConfig(config)
const { data } = await config.fetch(getAllProductsPathsQuery, {
variables,
})
return {
products: data.products?.edges?.map(
({ node: { handle } }: ProductEdge) => ({
node: {
path: `/${handle}`,
},
})
),
}
}
export default getAllProductPaths

View File

@ -1,39 +0,0 @@
import { GraphQLFetcherResult } from '@commerce/api'
import { getConfig, ShopifyConfig } from '../api'
import { ProductEdge } from '../schema'
import { getAllProductsQuery } from '../utils/queries'
import { normalizeProduct } from '../utils/normalize'
import { Product } from '@commerce/types'
type Variables = {
first?: number
field?: string
}
type ReturnType = {
products: Product[]
}
const getAllProducts = async (options: {
variables?: Variables
config?: ShopifyConfig
preview?: boolean
}): Promise<ReturnType> => {
let { config, variables = { first: 250 } } = options ?? {}
config = getConfig(config)
const { data }: GraphQLFetcherResult = await config.fetch(
getAllProductsQuery,
{ variables }
)
const products = data.products?.edges?.map(({ node: p }: ProductEdge) =>
normalizeProduct(p)
)
return {
products,
}
}
export default getAllProducts

View File

@ -1,31 +0,0 @@
import { GraphQLFetcherResult } from '@commerce/api'
import { getConfig, ShopifyConfig } from '../api'
import { normalizeProduct, getProductQuery } from '../utils'
type Variables = {
slug: string
}
type ReturnType = {
product: any
}
const getProduct = async (options: {
variables: Variables
config: ShopifyConfig
preview?: boolean
}): Promise<ReturnType> => {
let { config, variables } = options ?? {}
config = getConfig(config)
const { data }: GraphQLFetcherResult = await config.fetch(getProductQuery, {
variables,
})
const { productByHandle } = data
return {
product: productByHandle ? normalizeProduct(productByHandle) : null,
}
}
export default getProduct

View File

@ -1,7 +1,14 @@
import { SWRHook } from '@commerce/utils/types'
import useSearch, { UseSearch } from '@commerce/product/use-search'
import { ProductEdge } from '../schema'
import {
CollectionEdge,
GetAllProductsQuery,
GetProductsFromCollectionQueryVariables,
Product as ShopifyProduct,
ProductEdge,
} from '../schema'
import {
getAllProductsQuery,
getCollectionProductsQuery,
@ -9,56 +16,59 @@ import {
normalizeProduct,
} from '../utils'
import { Product } from '@commerce/types'
export default useSearch as UseSearch<typeof handler>
import type { SearchProductsHook } from '../types/product'
export type SearchProductsInput = {
search?: string
categoryId?: string
brandId?: string
categoryId?: number
brandId?: number
sort?: string
locale?: string
}
export type SearchProductsData = {
products: Product[]
found: boolean
}
export default useSearch as UseSearch<typeof handler>
export const handler: SWRHook<
SearchProductsData,
SearchProductsInput,
SearchProductsInput
> = {
export const handler: SWRHook<SearchProductsHook> = {
fetchOptions: {
query: getAllProductsQuery,
},
async fetcher({ input, options, fetch }) {
const { categoryId, brandId } = input
const method = options?.method
const variables = getSearchVariables(input)
let products
const data = await fetch({
query: categoryId ? getCollectionProductsQuery : options.query,
method: options?.method,
variables: getSearchVariables(input),
})
let edges
// change the query to getCollectionProductsQuery when categoryId is set
if (categoryId) {
edges = data.node?.products?.edges ?? []
if (brandId) {
edges = edges.filter(
const data = await fetch<
CollectionEdge,
GetProductsFromCollectionQueryVariables
>({
query: getCollectionProductsQuery,
method,
variables,
})
// filter on client when brandId & categoryId are set since is not available on collection product query
products = brandId
? data.node.products.edges.filter(
({ node: { vendor } }: ProductEdge) =>
vendor.replace(/\s+/g, '-').toLowerCase() === brandId
)
}
: data.node.products.edges
} else {
edges = data.products?.edges ?? []
const data = await fetch<GetAllProductsQuery>({
query: options.query,
method,
variables,
})
products = data.products.edges
}
return {
products: edges.map(({ node }: ProductEdge) => normalizeProduct(node)),
found: !!edges.length,
products: products?.map(({ node }) =>
normalizeProduct(node as ShopifyProduct)
),
found: !!products?.length,
}
},
useHook: ({ useData }) => (input = {}) => {
@ -68,6 +78,7 @@ export const handler: SWRHook<
['categoryId', input.categoryId],
['brandId', input.brandId],
['sort', input.sort],
['locale', input.locale],
],
swrOptions: {
revalidateOnFocus: false,

View File

@ -37,7 +37,7 @@ export type ApiVersion = {
displayName: Scalars['String']
/** The unique identifier of an ApiVersion. All supported API versions have a date-based (YYYY-MM) or `unstable` handle. */
handle: Scalars['String']
/** Whether the version is supported by Shopify. */
/** Whether the version is actively supported by Shopify. Supported API versions are guaranteed to be stable. Unsupported API versions include unstable, release candidate, and end-of-life versions that are marked as unsupported. For more information, refer to [Versioning](https://shopify.dev/concepts/about-apis/versioning). */
supported: Scalars['Boolean']
}
@ -306,17 +306,17 @@ export enum BlogSortKeys {
/** Card brand, such as Visa or Mastercard, which can be used for payments. */
export enum CardBrand {
/** Visa */
/** Visa. */
Visa = 'VISA',
/** Mastercard */
/** Mastercard. */
Mastercard = 'MASTERCARD',
/** Discover */
/** Discover. */
Discover = 'DISCOVER',
/** American Express */
/** American Express. */
AmericanExpress = 'AMERICAN_EXPRESS',
/** Diners Club */
/** Diners Club. */
DinersClub = 'DINERS_CLUB',
/** JCB */
/** JCB. */
Jcb = 'JCB',
}
@ -1195,6 +1195,8 @@ export enum CountryCode {
Am = 'AM',
/** Aruba. */
Aw = 'AW',
/** Ascension Island. */
Ac = 'AC',
/** Australia. */
Au = 'AU',
/** Austria. */
@ -1613,6 +1615,8 @@ export enum CountryCode {
To = 'TO',
/** Trinidad & Tobago. */
Tt = 'TT',
/** Tristan da Cunha. */
Ta = 'TA',
/** Tunisia. */
Tn = 'TN',
/** Turkey. */
@ -1687,7 +1691,7 @@ export type CreditCard = {
export type CreditCardPaymentInput = {
/** The amount of the payment. */
amount: Scalars['Money']
/** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */
/** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. For more information, refer to [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests). */
idempotencyKey: Scalars['String']
/** The billing address for the payment. */
billingAddress: MailingAddressInput
@ -1704,7 +1708,7 @@ export type CreditCardPaymentInput = {
export type CreditCardPaymentInputV2 = {
/** The amount and currency of the payment. */
paymentAmount: MoneyInput
/** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */
/** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. For more information, refer to [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests). */
idempotencyKey: Scalars['String']
/** The billing address for the payment. */
billingAddress: MailingAddressInput
@ -1766,10 +1770,6 @@ export enum CurrencyCode {
Bhd = 'BHD',
/** Burundian Franc (BIF). */
Bif = 'BIF',
/** Belarusian Ruble (BYN). */
Byn = 'BYN',
/** Belarusian Ruble (BYR). */
Byr = 'BYR',
/** Belize Dollar (BZD). */
Bzd = 'BZD',
/** Bermudian Dollar (BMD). */
@ -1816,26 +1816,18 @@ export enum CurrencyCode {
Czk = 'CZK',
/** Danish Kroner (DKK). */
Dkk = 'DKK',
/** Djiboutian Franc (DJF). */
Djf = 'DJF',
/** Dominican Peso (DOP). */
Dop = 'DOP',
/** East Caribbean Dollar (XCD). */
Xcd = 'XCD',
/** Egyptian Pound (EGP). */
Egp = 'EGP',
/** Eritrean Nakfa (ERN). */
Ern = 'ERN',
/** Ethiopian Birr (ETB). */
Etb = 'ETB',
/** Falkland Islands Pounds (FKP). */
Fkp = 'FKP',
/** CFP Franc (XPF). */
Xpf = 'XPF',
/** Fijian Dollars (FJD). */
Fjd = 'FJD',
/** Gibraltar Pounds (GIP). */
Gip = 'GIP',
/** Gambian Dalasi (GMD). */
Gmd = 'GMD',
/** Ghanaian Cedi (GHS). */
@ -1846,8 +1838,6 @@ export enum CurrencyCode {
Gyd = 'GYD',
/** Georgian Lari (GEL). */
Gel = 'GEL',
/** Guinean Franc (GNF). */
Gnf = 'GNF',
/** Haitian Gourde (HTG). */
Htg = 'HTG',
/** Honduran Lempira (HNL). */
@ -1864,8 +1854,6 @@ export enum CurrencyCode {
Idr = 'IDR',
/** Israeli New Shekel (NIS). */
Ils = 'ILS',
/** Iranian Rial (IRR). */
Irr = 'IRR',
/** Iraqi Dinar (IQD). */
Iqd = 'IQD',
/** Jamaican Dollars (JMD). */
@ -1880,8 +1868,6 @@ export enum CurrencyCode {
Kzt = 'KZT',
/** Kenyan Shilling (KES). */
Kes = 'KES',
/** Kiribati Dollar (KID). */
Kid = 'KID',
/** Kuwaiti Dinar (KWD). */
Kwd = 'KWD',
/** Kyrgyzstani Som (KGS). */
@ -1896,8 +1882,6 @@ export enum CurrencyCode {
Lsl = 'LSL',
/** Liberian Dollar (LRD). */
Lrd = 'LRD',
/** Libyan Dinar (LYD). */
Lyd = 'LYD',
/** Lithuanian Litai (LTL). */
Ltl = 'LTL',
/** Malagasy Ariary (MGA). */
@ -1910,8 +1894,6 @@ export enum CurrencyCode {
Mwk = 'MWK',
/** Maldivian Rufiyaa (MVR). */
Mvr = 'MVR',
/** Mauritanian Ouguiya (MRU). */
Mru = 'MRU',
/** Mexican Pesos (MXN). */
Mxn = 'MXN',
/** Malaysian Ringgits (MYR). */
@ -1966,8 +1948,6 @@ export enum CurrencyCode {
Rwf = 'RWF',
/** Samoan Tala (WST). */
Wst = 'WST',
/** Saint Helena Pounds (SHP). */
Shp = 'SHP',
/** Saudi Riyal (SAR). */
Sar = 'SAR',
/** Sao Tome And Principe Dobra (STD). */
@ -1976,14 +1956,10 @@ export enum CurrencyCode {
Rsd = 'RSD',
/** Seychellois Rupee (SCR). */
Scr = 'SCR',
/** Sierra Leonean Leone (SLL). */
Sll = 'SLL',
/** Singapore Dollars (SGD). */
Sgd = 'SGD',
/** Sudanese Pound (SDG). */
Sdg = 'SDG',
/** Somali Shilling (SOS). */
Sos = 'SOS',
/** Syrian Pound (SYP). */
Syp = 'SYP',
/** South African Rand (ZAR). */
@ -2008,12 +1984,8 @@ export enum CurrencyCode {
Twd = 'TWD',
/** Thai baht (THB). */
Thb = 'THB',
/** Tajikistani Somoni (TJS). */
Tjs = 'TJS',
/** Tanzanian Shilling (TZS). */
Tzs = 'TZS',
/** Tongan Pa'anga (TOP). */
Top = 'TOP',
/** Trinidad and Tobago Dollars (TTD). */
Ttd = 'TTD',
/** Tunisian Dinar (TND). */
@ -2034,10 +2006,6 @@ export enum CurrencyCode {
Uzs = 'UZS',
/** Vanuatu Vatu (VUV). */
Vuv = 'VUV',
/** Venezuelan Bolivares (VEF). */
Vef = 'VEF',
/** Venezuelan Bolivares (VES). */
Ves = 'VES',
/** Vietnamese đồng (VND). */
Vnd = 'VND',
/** West African CFA franc (XOF). */
@ -2046,6 +2014,42 @@ export enum CurrencyCode {
Yer = 'YER',
/** Zambian Kwacha (ZMW). */
Zmw = 'ZMW',
/** Belarusian Ruble (BYN). */
Byn = 'BYN',
/** Belarusian Ruble (BYR). */
Byr = 'BYR',
/** Djiboutian Franc (DJF). */
Djf = 'DJF',
/** Eritrean Nakfa (ERN). */
Ern = 'ERN',
/** Falkland Islands Pounds (FKP). */
Fkp = 'FKP',
/** Gibraltar Pounds (GIP). */
Gip = 'GIP',
/** Guinean Franc (GNF). */
Gnf = 'GNF',
/** Iranian Rial (IRR). */
Irr = 'IRR',
/** Kiribati Dollar (KID). */
Kid = 'KID',
/** Libyan Dinar (LYD). */
Lyd = 'LYD',
/** Mauritanian Ouguiya (MRU). */
Mru = 'MRU',
/** Sierra Leonean Leone (SLL). */
Sll = 'SLL',
/** Saint Helena Pounds (SHP). */
Shp = 'SHP',
/** Somali Shilling (SOS). */
Sos = 'SOS',
/** Tajikistani Somoni (TJS). */
Tjs = 'TJS',
/** Tongan Pa'anga (TOP). */
Top = 'TOP',
/** Venezuelan Bolivares (VEF). */
Vef = 'VEF',
/** Venezuelan Bolivares (VES). */
Ves = 'VES',
}
/** A customer represents a customer account with the shop. Customer accounts store contact information for the customer, saving logged-in customers the trouble of having to provide it at every checkout. */
@ -3817,7 +3821,11 @@ export type Payment = Node & {
errorMessage?: Maybe<Scalars['String']>
/** Globally unique identifier. */
id: Scalars['ID']
/** A client-side generated token to identify a payment and perform idempotent operations. */
/**
* A client-side generated token to identify a payment and perform idempotent operations.
* For more information, refer to
* [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests).
*/
idempotencyKey?: Maybe<Scalars['String']>
/** The URL where the customer needs to be redirected so they can complete the 3D Secure payment flow. */
nextActionUrl?: Maybe<Scalars['URL']>
@ -4386,7 +4394,9 @@ export type QueryRoot = {
collections: CollectionConnection
/** Find a customer by its access token. */
customer?: Maybe<Customer>
/** Returns a specific node by ID. */
node?: Maybe<Node>
/** Returns the list of nodes with the given IDs. */
nodes: Array<Maybe<Node>>
/** Find a page by its handle. */
pageByHandle?: Maybe<Page>
@ -4768,7 +4778,7 @@ export type StringEdge = {
export type TokenizedPaymentInput = {
/** The amount of the payment. */
amount: Scalars['Money']
/** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */
/** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. For more information, refer to [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests). */
idempotencyKey: Scalars['String']
/** The billing address for the payment. */
billingAddress: MailingAddressInput
@ -4789,7 +4799,7 @@ export type TokenizedPaymentInput = {
export type TokenizedPaymentInputV2 = {
/** The amount and currency of the payment. */
paymentAmount: MoneyInput
/** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */
/** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. For more information, refer to [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests). */
idempotencyKey: Scalars['String']
/** The billing address for the payment. */
billingAddress: MailingAddressInput
@ -4810,7 +4820,7 @@ export type TokenizedPaymentInputV2 = {
export type TokenizedPaymentInputV3 = {
/** The amount and currency of the payment. */
paymentAmount: MoneyInput
/** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */
/** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. For more information, refer to [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests). */
idempotencyKey: Scalars['String']
/** The billing address for the payment. */
billingAddress: MailingAddressInput
@ -4847,18 +4857,32 @@ export type Transaction = {
test: Scalars['Boolean']
}
/** The different kinds of order transactions. */
export enum TransactionKind {
/** An authorization and capture performed together in a single step. */
Sale = 'SALE',
/** A transfer of the money that was reserved during the authorization stage. */
Capture = 'CAPTURE',
/**
* An amount reserved against the cardholder's funding source.
* Money does not change hands until the authorization is captured.
*/
Authorization = 'AUTHORIZATION',
/** An authorization for a payment taken with an EMV credit card reader. */
EmvAuthorization = 'EMV_AUTHORIZATION',
/** Money returned to the customer when they have paid too much. */
Change = 'CHANGE',
}
/** Transaction statuses describe the status of a transaction. */
export enum TransactionStatus {
/** The transaction is pending. */
Pending = 'PENDING',
/** The transaction succeeded. */
Success = 'SUCCESS',
/** The transaction failed. */
Failure = 'FAILURE',
/** There was an error while processing the transaction. */
Error = 'ERROR',
}
@ -4967,19 +4991,596 @@ export enum WeightUnit {
Ounces = 'OUNCES',
}
export type Unnamed_1_QueryVariables = Exact<{
export type AssociateCustomerWithCheckoutMutationVariables = Exact<{
checkoutId: Scalars['ID']
customerAccessToken: Scalars['String']
}>
export type AssociateCustomerWithCheckoutMutation = {
__typename?: 'Mutation'
} & {
checkoutCustomerAssociateV2?: Maybe<
{ __typename?: 'CheckoutCustomerAssociateV2Payload' } & {
checkout?: Maybe<{ __typename?: 'Checkout' } & Pick<Checkout, 'id'>>
checkoutUserErrors: Array<
{ __typename?: 'CheckoutUserError' } & Pick<
CheckoutUserError,
'code' | 'field' | 'message'
>
>
customer?: Maybe<{ __typename?: 'Customer' } & Pick<Customer, 'id'>>
}
>
}
export type CheckoutCreateMutationVariables = Exact<{
input?: Maybe<CheckoutCreateInput>
}>
export type CheckoutCreateMutation = { __typename?: 'Mutation' } & {
checkoutCreate?: Maybe<
{ __typename?: 'CheckoutCreatePayload' } & {
checkoutUserErrors: Array<
{ __typename?: 'CheckoutUserError' } & Pick<
CheckoutUserError,
'code' | 'field' | 'message'
>
>
checkout?: Maybe<{ __typename?: 'Checkout' } & CheckoutDetailsFragment>
}
>
}
export type CheckoutLineItemAddMutationVariables = Exact<{
checkoutId: Scalars['ID']
lineItems: Array<CheckoutLineItemInput> | CheckoutLineItemInput
}>
export type CheckoutLineItemAddMutation = { __typename?: 'Mutation' } & {
checkoutLineItemsAdd?: Maybe<
{ __typename?: 'CheckoutLineItemsAddPayload' } & {
checkoutUserErrors: Array<
{ __typename?: 'CheckoutUserError' } & Pick<
CheckoutUserError,
'code' | 'field' | 'message'
>
>
checkout?: Maybe<{ __typename?: 'Checkout' } & CheckoutDetailsFragment>
}
>
}
export type CheckoutLineItemRemoveMutationVariables = Exact<{
checkoutId: Scalars['ID']
lineItemIds: Array<Scalars['ID']> | Scalars['ID']
}>
export type CheckoutLineItemRemoveMutation = { __typename?: 'Mutation' } & {
checkoutLineItemsRemove?: Maybe<
{ __typename?: 'CheckoutLineItemsRemovePayload' } & {
checkoutUserErrors: Array<
{ __typename?: 'CheckoutUserError' } & Pick<
CheckoutUserError,
'code' | 'field' | 'message'
>
>
checkout?: Maybe<{ __typename?: 'Checkout' } & CheckoutDetailsFragment>
}
>
}
export type CheckoutLineItemUpdateMutationVariables = Exact<{
checkoutId: Scalars['ID']
lineItems: Array<CheckoutLineItemUpdateInput> | CheckoutLineItemUpdateInput
}>
export type CheckoutLineItemUpdateMutation = { __typename?: 'Mutation' } & {
checkoutLineItemsUpdate?: Maybe<
{ __typename?: 'CheckoutLineItemsUpdatePayload' } & {
checkoutUserErrors: Array<
{ __typename?: 'CheckoutUserError' } & Pick<
CheckoutUserError,
'code' | 'field' | 'message'
>
>
checkout?: Maybe<{ __typename?: 'Checkout' } & CheckoutDetailsFragment>
}
>
}
export type CustomerAccessTokenCreateMutationVariables = Exact<{
input: CustomerAccessTokenCreateInput
}>
export type CustomerAccessTokenCreateMutation = { __typename?: 'Mutation' } & {
customerAccessTokenCreate?: Maybe<
{ __typename?: 'CustomerAccessTokenCreatePayload' } & {
customerAccessToken?: Maybe<
{ __typename?: 'CustomerAccessToken' } & Pick<
CustomerAccessToken,
'accessToken' | 'expiresAt'
>
>
customerUserErrors: Array<
{ __typename?: 'CustomerUserError' } & Pick<
CustomerUserError,
'code' | 'field' | 'message'
>
>
}
>
}
export type CustomerAccessTokenDeleteMutationVariables = Exact<{
customerAccessToken: Scalars['String']
}>
export type CustomerAccessTokenDeleteMutation = { __typename?: 'Mutation' } & {
customerAccessTokenDelete?: Maybe<
{ __typename?: 'CustomerAccessTokenDeletePayload' } & Pick<
CustomerAccessTokenDeletePayload,
'deletedAccessToken' | 'deletedCustomerAccessTokenId'
> & {
userErrors: Array<
{ __typename?: 'UserError' } & Pick<UserError, 'field' | 'message'>
>
}
>
}
export type CustomerActivateByUrlMutationVariables = Exact<{
activationUrl: Scalars['URL']
password: Scalars['String']
}>
export type CustomerActivateByUrlMutation = { __typename?: 'Mutation' } & {
customerActivateByUrl?: Maybe<
{ __typename?: 'CustomerActivateByUrlPayload' } & {
customer?: Maybe<{ __typename?: 'Customer' } & Pick<Customer, 'id'>>
customerAccessToken?: Maybe<
{ __typename?: 'CustomerAccessToken' } & Pick<
CustomerAccessToken,
'accessToken' | 'expiresAt'
>
>
customerUserErrors: Array<
{ __typename?: 'CustomerUserError' } & Pick<
CustomerUserError,
'code' | 'field' | 'message'
>
>
}
>
}
export type CustomerActivateMutationVariables = Exact<{
id: Scalars['ID']
input: CustomerActivateInput
}>
export type CustomerActivateMutation = { __typename?: 'Mutation' } & {
customerActivate?: Maybe<
{ __typename?: 'CustomerActivatePayload' } & {
customer?: Maybe<{ __typename?: 'Customer' } & Pick<Customer, 'id'>>
customerAccessToken?: Maybe<
{ __typename?: 'CustomerAccessToken' } & Pick<
CustomerAccessToken,
'accessToken' | 'expiresAt'
>
>
customerUserErrors: Array<
{ __typename?: 'CustomerUserError' } & Pick<
CustomerUserError,
'code' | 'field' | 'message'
>
>
}
>
}
export type CustomerCreateMutationVariables = Exact<{
input: CustomerCreateInput
}>
export type CustomerCreateMutation = { __typename?: 'Mutation' } & {
customerCreate?: Maybe<
{ __typename?: 'CustomerCreatePayload' } & {
customerUserErrors: Array<
{ __typename?: 'CustomerUserError' } & Pick<
CustomerUserError,
'code' | 'field' | 'message'
>
>
customer?: Maybe<{ __typename?: 'Customer' } & Pick<Customer, 'id'>>
}
>
}
export type GetSiteCollectionsQueryVariables = Exact<{
first: Scalars['Int']
}>
export type Unnamed_1_Query = { __typename?: 'QueryRoot' } & {
export type GetSiteCollectionsQuery = { __typename?: 'QueryRoot' } & {
collections: { __typename?: 'CollectionConnection' } & {
edges: Array<
{ __typename?: 'CollectionEdge' } & {
node: { __typename?: 'Collection' } & Pick<
Collection,
'id' | 'title' | 'handle'
>
}
>
}
}
export type GetAllPagesQueryVariables = Exact<{
first?: Maybe<Scalars['Int']>
}>
export type GetAllPagesQuery = { __typename?: 'QueryRoot' } & {
pages: { __typename?: 'PageConnection' } & {
edges: Array<
{ __typename?: 'PageEdge' } & {
node: { __typename?: 'Page' } & Pick<
node: { __typename?: 'Page' } & Pick<Page, 'id' | 'title' | 'handle'>
}
>
}
}
export type GetAllProductVendorsQueryVariables = Exact<{
first?: Maybe<Scalars['Int']>
cursor?: Maybe<Scalars['String']>
}>
export type GetAllProductVendorsQuery = { __typename?: 'QueryRoot' } & {
products: { __typename?: 'ProductConnection' } & {
pageInfo: { __typename?: 'PageInfo' } & Pick<
PageInfo,
'hasNextPage' | 'hasPreviousPage'
>
edges: Array<
{ __typename?: 'ProductEdge' } & Pick<ProductEdge, 'cursor'> & {
node: { __typename?: 'Product' } & Pick<Product, 'vendor'>
}
>
}
}
export type GetAllProductPathsQueryVariables = Exact<{
first?: Maybe<Scalars['Int']>
cursor?: Maybe<Scalars['String']>
}>
export type GetAllProductPathsQuery = { __typename?: 'QueryRoot' } & {
products: { __typename?: 'ProductConnection' } & {
pageInfo: { __typename?: 'PageInfo' } & Pick<
PageInfo,
'hasNextPage' | 'hasPreviousPage'
>
edges: Array<
{ __typename?: 'ProductEdge' } & Pick<ProductEdge, 'cursor'> & {
node: { __typename?: 'Product' } & Pick<Product, 'handle'>
}
>
}
}
export type ProductConnectionFragment = { __typename?: 'ProductConnection' } & {
pageInfo: { __typename?: 'PageInfo' } & Pick<
PageInfo,
'hasNextPage' | 'hasPreviousPage'
>
edges: Array<
{ __typename?: 'ProductEdge' } & {
node: { __typename?: 'Product' } & Pick<
Product,
'id' | 'title' | 'vendor' | 'handle'
> & {
priceRange: { __typename?: 'ProductPriceRange' } & {
minVariantPrice: { __typename?: 'MoneyV2' } & Pick<
MoneyV2,
'amount' | 'currencyCode'
>
}
images: { __typename?: 'ImageConnection' } & {
pageInfo: { __typename?: 'PageInfo' } & Pick<
PageInfo,
'hasNextPage' | 'hasPreviousPage'
>
edges: Array<
{ __typename?: 'ImageEdge' } & {
node: { __typename?: 'Image' } & Pick<
Image,
'originalSrc' | 'altText' | 'width' | 'height'
>
}
>
}
}
}
>
}
export type GetAllProductsQueryVariables = Exact<{
first?: Maybe<Scalars['Int']>
query?: Maybe<Scalars['String']>
sortKey?: Maybe<ProductSortKeys>
reverse?: Maybe<Scalars['Boolean']>
}>
export type GetAllProductsQuery = { __typename?: 'QueryRoot' } & {
products: { __typename?: 'ProductConnection' } & ProductConnectionFragment
}
export type CheckoutDetailsFragment = { __typename?: 'Checkout' } & Pick<
Checkout,
'id' | 'webUrl' | 'completedAt' | 'createdAt' | 'taxesIncluded'
> & {
subtotalPriceV2: { __typename?: 'MoneyV2' } & Pick<
MoneyV2,
'amount' | 'currencyCode'
>
totalTaxV2: { __typename?: 'MoneyV2' } & Pick<
MoneyV2,
'amount' | 'currencyCode'
>
totalPriceV2: { __typename?: 'MoneyV2' } & Pick<
MoneyV2,
'amount' | 'currencyCode'
>
lineItems: { __typename?: 'CheckoutLineItemConnection' } & {
pageInfo: { __typename?: 'PageInfo' } & Pick<
PageInfo,
'hasNextPage' | 'hasPreviousPage'
>
edges: Array<
{ __typename?: 'CheckoutLineItemEdge' } & {
node: { __typename?: 'CheckoutLineItem' } & Pick<
CheckoutLineItem,
'id' | 'title' | 'quantity'
> & {
variant?: Maybe<
{ __typename?: 'ProductVariant' } & Pick<
ProductVariant,
'id' | 'sku' | 'title'
> & {
image?: Maybe<
{ __typename?: 'Image' } & Pick<
Image,
'originalSrc' | 'altText' | 'width' | 'height'
>
>
priceV2: { __typename?: 'MoneyV2' } & Pick<
MoneyV2,
'amount' | 'currencyCode'
>
compareAtPriceV2?: Maybe<
{ __typename?: 'MoneyV2' } & Pick<
MoneyV2,
'amount' | 'currencyCode'
>
>
product: { __typename?: 'Product' } & Pick<
Product,
'handle'
>
}
>
}
}
>
}
}
export type GetCheckoutQueryVariables = Exact<{
checkoutId: Scalars['ID']
}>
export type GetCheckoutQuery = { __typename?: 'QueryRoot' } & {
node?: Maybe<
| { __typename?: 'AppliedGiftCard' }
| { __typename?: 'Article' }
| { __typename?: 'Blog' }
| ({ __typename?: 'Checkout' } & CheckoutDetailsFragment)
| { __typename?: 'CheckoutLineItem' }
| { __typename?: 'Collection' }
| { __typename?: 'Comment' }
| { __typename?: 'ExternalVideo' }
| { __typename?: 'MailingAddress' }
| { __typename?: 'MediaImage' }
| { __typename?: 'Metafield' }
| { __typename?: 'Model3d' }
| { __typename?: 'Order' }
| { __typename?: 'Page' }
| { __typename?: 'Payment' }
| { __typename?: 'Product' }
| { __typename?: 'ProductOption' }
| { __typename?: 'ProductVariant' }
| { __typename?: 'ShopPolicy' }
| { __typename?: 'Video' }
>
}
export type GetProductsFromCollectionQueryVariables = Exact<{
categoryId: Scalars['ID']
first?: Maybe<Scalars['Int']>
sortKey?: Maybe<ProductCollectionSortKeys>
reverse?: Maybe<Scalars['Boolean']>
}>
export type GetProductsFromCollectionQuery = { __typename?: 'QueryRoot' } & {
node?: Maybe<
| ({ __typename?: 'AppliedGiftCard' } & Pick<AppliedGiftCard, 'id'>)
| ({ __typename?: 'Article' } & Pick<Article, 'id'>)
| ({ __typename?: 'Blog' } & Pick<Blog, 'id'>)
| ({ __typename?: 'Checkout' } & Pick<Checkout, 'id'>)
| ({ __typename?: 'CheckoutLineItem' } & Pick<CheckoutLineItem, 'id'>)
| ({ __typename?: 'Collection' } & Pick<Collection, 'id'> & {
products: {
__typename?: 'ProductConnection'
} & ProductConnectionFragment
})
| ({ __typename?: 'Comment' } & Pick<Comment, 'id'>)
| ({ __typename?: 'ExternalVideo' } & Pick<ExternalVideo, 'id'>)
| ({ __typename?: 'MailingAddress' } & Pick<MailingAddress, 'id'>)
| ({ __typename?: 'MediaImage' } & Pick<MediaImage, 'id'>)
| ({ __typename?: 'Metafield' } & Pick<Metafield, 'id'>)
| ({ __typename?: 'Model3d' } & Pick<Model3d, 'id'>)
| ({ __typename?: 'Order' } & Pick<Order, 'id'>)
| ({ __typename?: 'Page' } & Pick<Page, 'id'>)
| ({ __typename?: 'Payment' } & Pick<Payment, 'id'>)
| ({ __typename?: 'Product' } & Pick<Product, 'id'>)
| ({ __typename?: 'ProductOption' } & Pick<ProductOption, 'id'>)
| ({ __typename?: 'ProductVariant' } & Pick<ProductVariant, 'id'>)
| ({ __typename?: 'ShopPolicy' } & Pick<ShopPolicy, 'id'>)
| ({ __typename?: 'Video' } & Pick<Video, 'id'>)
>
}
export type GetCustomerIdQueryVariables = Exact<{
customerAccessToken: Scalars['String']
}>
export type GetCustomerIdQuery = { __typename?: 'QueryRoot' } & {
customer?: Maybe<{ __typename?: 'Customer' } & Pick<Customer, 'id'>>
}
export type GetCustomerQueryVariables = Exact<{
customerAccessToken: Scalars['String']
}>
export type GetCustomerQuery = { __typename?: 'QueryRoot' } & {
customer?: Maybe<
{ __typename?: 'Customer' } & Pick<
Customer,
| 'id'
| 'firstName'
| 'lastName'
| 'displayName'
| 'email'
| 'phone'
| 'tags'
| 'acceptsMarketing'
| 'createdAt'
>
>
}
export type GetPageQueryVariables = Exact<{
id: Scalars['ID']
}>
export type GetPageQuery = { __typename?: 'QueryRoot' } & {
node?: Maybe<
| ({ __typename?: 'AppliedGiftCard' } & Pick<AppliedGiftCard, 'id'>)
| ({ __typename?: 'Article' } & Pick<Article, 'id'>)
| ({ __typename?: 'Blog' } & Pick<Blog, 'id'>)
| ({ __typename?: 'Checkout' } & Pick<Checkout, 'id'>)
| ({ __typename?: 'CheckoutLineItem' } & Pick<CheckoutLineItem, 'id'>)
| ({ __typename?: 'Collection' } & Pick<Collection, 'id'>)
| ({ __typename?: 'Comment' } & Pick<Comment, 'id'>)
| ({ __typename?: 'ExternalVideo' } & Pick<ExternalVideo, 'id'>)
| ({ __typename?: 'MailingAddress' } & Pick<MailingAddress, 'id'>)
| ({ __typename?: 'MediaImage' } & Pick<MediaImage, 'id'>)
| ({ __typename?: 'Metafield' } & Pick<Metafield, 'id'>)
| ({ __typename?: 'Model3d' } & Pick<Model3d, 'id'>)
| ({ __typename?: 'Order' } & Pick<Order, 'id'>)
| ({ __typename?: 'Page' } & Pick<
Page,
'id' | 'title' | 'handle' | 'body' | 'bodySummary' | 'url'
'title' | 'handle' | 'body' | 'bodySummary' | 'id'
>)
| ({ __typename?: 'Payment' } & Pick<Payment, 'id'>)
| ({ __typename?: 'Product' } & Pick<Product, 'id'>)
| ({ __typename?: 'ProductOption' } & Pick<ProductOption, 'id'>)
| ({ __typename?: 'ProductVariant' } & Pick<ProductVariant, 'id'>)
| ({ __typename?: 'ShopPolicy' } & Pick<ShopPolicy, 'id'>)
| ({ __typename?: 'Video' } & Pick<Video, 'id'>)
>
}
export type GetProductBySlugQueryVariables = Exact<{
slug: Scalars['String']
}>
export type GetProductBySlugQuery = { __typename?: 'QueryRoot' } & {
productByHandle?: Maybe<
{ __typename?: 'Product' } & Pick<
Product,
| 'id'
| 'handle'
| 'title'
| 'productType'
| 'vendor'
| 'description'
| 'descriptionHtml'
> & {
options: Array<
{ __typename?: 'ProductOption' } & Pick<
ProductOption,
'id' | 'name' | 'values'
>
>
priceRange: { __typename?: 'ProductPriceRange' } & {
maxVariantPrice: { __typename?: 'MoneyV2' } & Pick<
MoneyV2,
'amount' | 'currencyCode'
>
minVariantPrice: { __typename?: 'MoneyV2' } & Pick<
MoneyV2,
'amount' | 'currencyCode'
>
}
variants: { __typename?: 'ProductVariantConnection' } & {
pageInfo: { __typename?: 'PageInfo' } & Pick<
PageInfo,
'hasNextPage' | 'hasPreviousPage'
>
edges: Array<
{ __typename?: 'ProductVariantEdge' } & {
node: { __typename?: 'ProductVariant' } & Pick<
ProductVariant,
'id' | 'title' | 'sku'
> & {
selectedOptions: Array<
{ __typename?: 'SelectedOption' } & Pick<
SelectedOption,
'name' | 'value'
>
>
priceV2: { __typename?: 'MoneyV2' } & Pick<
MoneyV2,
'amount' | 'currencyCode'
>
compareAtPriceV2?: Maybe<
{ __typename?: 'MoneyV2' } & Pick<
MoneyV2,
'amount' | 'currencyCode'
>
>
}
}
>
}
images: { __typename?: 'ImageConnection' } & {
pageInfo: { __typename?: 'PageInfo' } & Pick<
PageInfo,
'hasNextPage' | 'hasPreviousPage'
>
edges: Array<
{ __typename?: 'ImageEdge' } & {
node: { __typename?: 'Image' } & Pick<
Image,
'originalSrc' | 'altText' | 'width' | 'height'
>
}
>
}
}
>
}
export type GetSiteInfoQueryVariables = Exact<{ [key: string]: never }>
export type GetSiteInfoQuery = { __typename?: 'QueryRoot' } & {
shop: { __typename?: 'Shop' } & Pick<Shop, 'name'>
}

View File

@ -13,6 +13,16 @@ directive @accessRestricted(
reason: String = null
) on FIELD_DEFINITION | OBJECT
"""
Contextualize data.
"""
directive @inContext(
"""
The country code for context.
"""
country: CountryCode!
) on QUERY | MUTATION
"""
A version of the API.
"""
@ -28,7 +38,7 @@ type ApiVersion {
handle: String!
"""
Whether the version is supported by Shopify.
Whether the version is actively supported by Shopify. Supported API versions are guaranteed to be stable. Unsupported API versions include unstable, release candidate, and end-of-life versions that are marked as unsupported. For more information, refer to [Versioning](https://shopify.dev/concepts/about-apis/versioning).
"""
supported: Boolean!
}
@ -547,32 +557,32 @@ Card brand, such as Visa or Mastercard, which can be used for payments.
"""
enum CardBrand {
"""
Visa
Visa.
"""
VISA
"""
Mastercard
Mastercard.
"""
MASTERCARD
"""
Discover
Discover.
"""
DISCOVER
"""
American Express
American Express.
"""
AMERICAN_EXPRESS
"""
Diners Club
Diners Club.
"""
DINERS_CLUB
"""
JCB
JCB.
"""
JCB
}
@ -2142,6 +2152,11 @@ enum CountryCode {
"""
AW
"""
Ascension Island.
"""
AC
"""
Australia.
"""
@ -3187,6 +3202,11 @@ enum CountryCode {
"""
TT
"""
Tristan da Cunha.
"""
TA
"""
Tunisia.
"""
@ -3354,7 +3374,7 @@ input CreditCardPaymentInput {
amount: Money!
"""
A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one.
A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. For more information, refer to [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests).
"""
idempotencyKey: String!
@ -3385,7 +3405,7 @@ input CreditCardPaymentInputV2 {
paymentAmount: MoneyInput!
"""
A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one.
A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. For more information, refer to [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests).
"""
idempotencyKey: String!
@ -3529,16 +3549,6 @@ enum CurrencyCode {
"""
BIF
"""
Belarusian Ruble (BYN).
"""
BYN
"""
Belarusian Ruble (BYR).
"""
BYR
"""
Belize Dollar (BZD).
"""
@ -3654,11 +3664,6 @@ enum CurrencyCode {
"""
DKK
"""
Djiboutian Franc (DJF).
"""
DJF
"""
Dominican Peso (DOP).
"""
@ -3674,21 +3679,11 @@ enum CurrencyCode {
"""
EGP
"""
Eritrean Nakfa (ERN).
"""
ERN
"""
Ethiopian Birr (ETB).
"""
ETB
"""
Falkland Islands Pounds (FKP).
"""
FKP
"""
CFP Franc (XPF).
"""
@ -3699,11 +3694,6 @@ enum CurrencyCode {
"""
FJD
"""
Gibraltar Pounds (GIP).
"""
GIP
"""
Gambian Dalasi (GMD).
"""
@ -3729,11 +3719,6 @@ enum CurrencyCode {
"""
GEL
"""
Guinean Franc (GNF).
"""
GNF
"""
Haitian Gourde (HTG).
"""
@ -3774,11 +3759,6 @@ enum CurrencyCode {
"""
ILS
"""
Iranian Rial (IRR).
"""
IRR
"""
Iraqi Dinar (IQD).
"""
@ -3814,11 +3794,6 @@ enum CurrencyCode {
"""
KES
"""
Kiribati Dollar (KID).
"""
KID
"""
Kuwaiti Dinar (KWD).
"""
@ -3854,11 +3829,6 @@ enum CurrencyCode {
"""
LRD
"""
Libyan Dinar (LYD).
"""
LYD
"""
Lithuanian Litai (LTL).
"""
@ -3889,11 +3859,6 @@ enum CurrencyCode {
"""
MVR
"""
Mauritanian Ouguiya (MRU).
"""
MRU
"""
Mexican Pesos (MXN).
"""
@ -4029,11 +3994,6 @@ enum CurrencyCode {
"""
WST
"""
Saint Helena Pounds (SHP).
"""
SHP
"""
Saudi Riyal (SAR).
"""
@ -4054,11 +4014,6 @@ enum CurrencyCode {
"""
SCR
"""
Sierra Leonean Leone (SLL).
"""
SLL
"""
Singapore Dollars (SGD).
"""
@ -4069,11 +4024,6 @@ enum CurrencyCode {
"""
SDG
"""
Somali Shilling (SOS).
"""
SOS
"""
Syrian Pound (SYP).
"""
@ -4134,21 +4084,11 @@ enum CurrencyCode {
"""
THB
"""
Tajikistani Somoni (TJS).
"""
TJS
"""
Tanzanian Shilling (TZS).
"""
TZS
"""
Tongan Pa'anga (TOP).
"""
TOP
"""
Trinidad and Tobago Dollars (TTD).
"""
@ -4199,16 +4139,6 @@ enum CurrencyCode {
"""
VUV
"""
Venezuelan Bolivares (VEF).
"""
VEF
"""
Venezuelan Bolivares (VES).
"""
VES
"""
Vietnamese đồng (VND).
"""
@ -4228,6 +4158,96 @@ enum CurrencyCode {
Zambian Kwacha (ZMW).
"""
ZMW
"""
Belarusian Ruble (BYN).
"""
BYN
"""
Belarusian Ruble (BYR).
"""
BYR
"""
Djiboutian Franc (DJF).
"""
DJF
"""
Eritrean Nakfa (ERN).
"""
ERN
"""
Falkland Islands Pounds (FKP).
"""
FKP
"""
Gibraltar Pounds (GIP).
"""
GIP
"""
Guinean Franc (GNF).
"""
GNF
"""
Iranian Rial (IRR).
"""
IRR
"""
Kiribati Dollar (KID).
"""
KID
"""
Libyan Dinar (LYD).
"""
LYD
"""
Mauritanian Ouguiya (MRU).
"""
MRU
"""
Sierra Leonean Leone (SLL).
"""
SLL
"""
Saint Helena Pounds (SHP).
"""
SHP
"""
Somali Shilling (SOS).
"""
SOS
"""
Tajikistani Somoni (TJS).
"""
TJS
"""
Tongan Pa'anga (TOP).
"""
TOP
"""
Venezuelan Bolivares (VEF).
"""
VEF
"""
Venezuelan Bolivares (VES).
"""
VES
}
"""
@ -7355,6 +7375,8 @@ type Payment implements Node {
"""
A client-side generated token to identify a payment and perform idempotent operations.
For more information, refer to
[Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests).
"""
idempotencyKey: String
@ -8589,12 +8611,20 @@ type QueryRoot {
"""
customerAccessToken: String!
): Customer
"""
Returns a specific node by ID.
"""
node(
"""
The ID of the Node to return.
"""
id: ID!
): Node
"""
Returns the list of nodes with the given IDs.
"""
nodes(
"""
The IDs of the Nodes to return.
@ -9246,7 +9276,7 @@ input TokenizedPaymentInput {
amount: Money!
"""
A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one.
A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. For more information, refer to [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests).
"""
idempotencyKey: String!
@ -9287,7 +9317,7 @@ input TokenizedPaymentInputV2 {
paymentAmount: MoneyInput!
"""
A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one.
A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. For more information, refer to [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests).
"""
idempotencyKey: String!
@ -9328,7 +9358,7 @@ input TokenizedPaymentInputV3 {
paymentAmount: MoneyInput!
"""
A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one.
A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. For more information, refer to [Idempotent requests](https://shopify.dev/concepts/about-apis/idempotent-requests).
"""
idempotencyKey: String!
@ -9393,18 +9423,59 @@ type Transaction {
test: Boolean!
}
"""
The different kinds of order transactions.
"""
enum TransactionKind {
"""
An authorization and capture performed together in a single step.
"""
SALE
"""
A transfer of the money that was reserved during the authorization stage.
"""
CAPTURE
"""
An amount reserved against the cardholder's funding source.
Money does not change hands until the authorization is captured.
"""
AUTHORIZATION
"""
An authorization for a payment taken with an EMV credit card reader.
"""
EMV_AUTHORIZATION
"""
Money returned to the customer when they have paid too much.
"""
CHANGE
}
"""
Transaction statuses describe the status of a transaction.
"""
enum TransactionStatus {
"""
The transaction is pending.
"""
PENDING
"""
The transaction succeeded.
"""
SUCCESS
"""
The transaction failed.
"""
FAILURE
"""
There was an error while processing the transaction.
"""
ERROR
}

View File

@ -1,43 +0,0 @@
import * as Core from '@commerce/types'
import { CheckoutLineItem } from './schema'
export type ShopifyCheckout = {
id: string
webUrl: string
lineItems: CheckoutLineItem[]
}
export type Cart = Core.Cart & {
lineItems: LineItem[]
}
export interface LineItem extends Core.LineItem {
options?: any[]
}
/**
* Cart mutations
*/
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 GetCartHandlerBody = Core.GetCartHandlerBody
export type AddCartItemBody = Core.AddCartItemBody<CartItemBody>
export type AddCartItemHandlerBody = Core.AddCartItemHandlerBody<CartItemBody>
export type UpdateCartItemBody = Core.UpdateCartItemBody<CartItemBody>
export type UpdateCartItemHandlerBody = Core.UpdateCartItemHandlerBody<CartItemBody>
export type RemoveCartItemBody = Core.RemoveCartItemBody
export type RemoveCartItemHandlerBody = Core.RemoveCartItemHandlerBody

View File

@ -0,0 +1,32 @@
import * as Core from '@commerce/types/cart'
export * from '@commerce/types/cart'
export type ShopifyCart = {}
/**
* 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']

View File

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

View File

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

View File

@ -0,0 +1,5 @@
import * as Core from '@commerce/types/customer'
export * from '@commerce/types/customer'
export type CustomerSchema = Core.CustomerSchema

View File

@ -0,0 +1,25 @@
import * as Cart 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

@ -0,0 +1,8 @@
import * as Core from '@commerce/types/login'
import type { CustomerAccessTokenCreateInput } from '../schema'
export * from '@commerce/types/login'
export type LoginOperation = Core.LoginOperation & {
variables: CustomerAccessTokenCreateInput
}

View File

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

View File

@ -0,0 +1,11 @@
import * as Core from '@commerce/types/page'
export * from '@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>

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
import { Cart } from '../types'
import type { Cart } from '../types/cart'
import { CommerceError } from '@commerce/utils/errors'
import {
@ -27,12 +27,6 @@ export type CheckoutPayload =
| CheckoutQuery
const checkoutToCart = (checkoutPayload?: Maybe<CheckoutPayload>): Cart => {
if (!checkoutPayload) {
throw new CommerceError({
message: 'Missing checkout payload from response',
})
}
const checkout = checkoutPayload?.checkout
throwUserErrors(checkoutPayload?.checkoutUserErrors)

View File

@ -1,5 +1,8 @@
import {
GetAllProductVendorsQuery,
GetAllProductVendorsQueryVariables,
} from '../schema'
import { ShopifyConfig } from '../api'
import fetchAllProducts from '../api/utils/fetch-all-products'
import getAllProductVendors from './queries/get-all-product-vendors-query'
export type Brand = {
@ -14,16 +17,17 @@ export type BrandEdge = {
export type Brands = BrandEdge[]
const getVendors = async (config: ShopifyConfig): Promise<BrandEdge[]> => {
const vendors = await fetchAllProducts({
config,
query: getAllProductVendors,
const getBrands = async (config: ShopifyConfig): Promise<BrandEdge[]> => {
const { data } = await config.fetch<
GetAllProductVendorsQuery,
GetAllProductVendorsQueryVariables
>(getAllProductVendors, {
variables: {
first: 250,
},
})
let vendorsStrings = vendors.map(({ node: { vendor } }) => vendor)
let vendorsStrings = data.products.edges.map(({ node: { vendor } }) => vendor)
return [...new Set(vendorsStrings)].map((v) => {
const id = v.replace(/\s+/g, '-').toLowerCase()
@ -37,4 +41,4 @@ const getVendors = async (config: ShopifyConfig): Promise<BrandEdge[]> => {
})
}
export default getVendors
export default getBrands

View File

@ -8,12 +8,25 @@ export type Category = {
path: string
}
const getCategories = async (config: ShopifyConfig): Promise<Category[]> => {
const { data } = await config.fetch(getSiteCollectionsQuery, {
const getCategories = async ({
fetch,
locale,
}: ShopifyConfig): Promise<Category[]> => {
const { data } = await fetch(
getSiteCollectionsQuery,
{
variables: {
first: 250,
},
})
},
{
...(locale && {
headers: {
'Accept-Language': locale,
},
}),
}
)
return (
data.collections?.edges?.map(

Some files were not shown because too many files have changed in this diff Show More