mirror of
https://github.com/vercel/commerce.git
synced 2025-05-17 15:06:59 +00:00
Change variant image/price & metafields progress
This commit is contained in:
parent
d4858910e4
commit
a56c84375b
@ -1,4 +1,4 @@
|
||||
import { SEO } from './common'
|
||||
import type { SEO } from './common'
|
||||
|
||||
export type ProductImage = {
|
||||
url: string
|
||||
@ -31,12 +31,17 @@ export type ProductVariant = {
|
||||
id: string | number
|
||||
options: ProductOption[]
|
||||
availableForSale?: boolean
|
||||
// Product variant price
|
||||
price?: ProductPrice
|
||||
// Product variant image
|
||||
image?: ProductImage
|
||||
}
|
||||
|
||||
export type ProductMetafield = {
|
||||
key: string
|
||||
value: string
|
||||
description?: string
|
||||
type?: string
|
||||
}
|
||||
|
||||
export type Product = {
|
||||
id: string
|
||||
name: string
|
||||
@ -51,6 +56,7 @@ export type Product = {
|
||||
options: ProductOption[]
|
||||
vendor?: string
|
||||
seo?: SEO
|
||||
metafields?: ProductMetafield[]
|
||||
}
|
||||
|
||||
export type SearchProductsBody = {
|
||||
@ -102,5 +108,5 @@ export type GetAllProductsOperation<T extends ProductTypes = ProductTypes> = {
|
||||
|
||||
export type GetProductOperation<T extends ProductTypes = ProductTypes> = {
|
||||
data: { product?: T['product'] }
|
||||
variables: { path: string; slug?: never } | { path?: never; slug: string }
|
||||
variables: { slug?: string; path?: string; withMetafields?: boolean }
|
||||
}
|
||||
|
813
packages/shopify/schema.d.ts
vendored
813
packages/shopify/schema.d.ts
vendored
@ -1737,7 +1737,7 @@ export type Country = {
|
||||
|
||||
/**
|
||||
* The code designating a country/region, which generally follows ISO 3166-1 alpha-2 guidelines.
|
||||
* If a territory doesn't have a country code value in the `CountryCode` enum, it might be considered a subdivision
|
||||
* If a territory doesn't have a country code value in the `CountryCode` enum, then it might be considered a subdivision
|
||||
* of another country. For example, the territories associated with Spain are represented by the country code `ES`,
|
||||
* and the territories associated with the United States of America are represented by the country code `US`.
|
||||
*
|
||||
@ -5317,7 +5317,7 @@ export type Payment = Node & {
|
||||
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']>
|
||||
/** Whether or not the payment is still processing asynchronously. */
|
||||
/** Whether the payment is still processing asynchronously. */
|
||||
ready: Scalars['Boolean']
|
||||
/** A flag to indicate if the payment is to be done in test mode for gateways that support it. */
|
||||
test: Scalars['Boolean']
|
||||
@ -6458,7 +6458,7 @@ export type ShopPolicyWithDefault = {
|
||||
*/
|
||||
export type StoreAvailability = {
|
||||
__typename?: 'StoreAvailability'
|
||||
/** Whether or not this product variant is in-stock at this location. */
|
||||
/** Whether the product variant is in-stock at this location. */
|
||||
available: Scalars['Boolean']
|
||||
/** The location where this product variant is stocked at. */
|
||||
location: Location
|
||||
@ -6759,24 +6759,195 @@ export enum WeightUnit {
|
||||
Pounds = 'POUNDS',
|
||||
}
|
||||
|
||||
export type AssociateCustomerWithCheckoutMutationVariables = Exact<{
|
||||
checkoutId: Scalars['ID']
|
||||
customerAccessToken: Scalars['String']
|
||||
}>
|
||||
export type GetSiteInfoQueryVariables = Exact<{ [key: string]: never }>
|
||||
|
||||
export type AssociateCustomerWithCheckoutMutation = {
|
||||
__typename?: 'Mutation'
|
||||
checkoutCustomerAssociateV2?: {
|
||||
__typename?: 'CheckoutCustomerAssociateV2Payload'
|
||||
checkout?: { __typename?: 'Checkout'; id: string } | null
|
||||
checkoutUserErrors: Array<{
|
||||
__typename?: 'CheckoutUserError'
|
||||
code?: CheckoutErrorCode | null
|
||||
field?: Array<string> | null
|
||||
message: string
|
||||
export type GetSiteInfoQuery = {
|
||||
__typename?: 'QueryRoot'
|
||||
shop: { __typename?: 'Shop'; name: string }
|
||||
}
|
||||
|
||||
export type CartDetailsFragment = {
|
||||
__typename?: 'Cart'
|
||||
id: string
|
||||
checkoutUrl: any
|
||||
createdAt: any
|
||||
updatedAt: any
|
||||
lines: {
|
||||
__typename?: 'CartLineConnection'
|
||||
edges: Array<{
|
||||
__typename?: 'CartLineEdge'
|
||||
node: {
|
||||
__typename?: 'CartLine'
|
||||
id: string
|
||||
quantity: number
|
||||
merchandise: {
|
||||
__typename?: 'ProductVariant'
|
||||
id: string
|
||||
sku?: string | null
|
||||
title: string
|
||||
selectedOptions: Array<{
|
||||
__typename?: 'SelectedOption'
|
||||
name: string
|
||||
value: string
|
||||
}>
|
||||
image?: {
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
altText?: string | null
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
} | null
|
||||
priceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
compareAtPriceV2?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
product: { __typename?: 'Product'; title: string; handle: string }
|
||||
}
|
||||
}
|
||||
}>
|
||||
}
|
||||
attributes: Array<{
|
||||
__typename?: 'Attribute'
|
||||
key: string
|
||||
value?: string | null
|
||||
}>
|
||||
buyerIdentity: {
|
||||
__typename?: 'CartBuyerIdentity'
|
||||
email?: string | null
|
||||
customer?: { __typename?: 'Customer'; id: string } | null
|
||||
}
|
||||
estimatedCost: {
|
||||
__typename?: 'CartEstimatedCost'
|
||||
totalAmount: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
subtotalAmount: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
totalTaxAmount?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
totalDutyAmount?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
}
|
||||
}
|
||||
|
||||
export type UserErrorsFragment = {
|
||||
__typename?: 'CartUserError'
|
||||
code?: CartErrorCode | null
|
||||
field?: Array<string> | null
|
||||
message: string
|
||||
}
|
||||
|
||||
export type CustomerUserErrorsFragment = {
|
||||
__typename?: 'CustomerUserError'
|
||||
code?: CustomerErrorCode | null
|
||||
field?: Array<string> | null
|
||||
message: string
|
||||
}
|
||||
|
||||
export type CustomerAccessTokenFragment = {
|
||||
__typename?: 'CustomerAccessToken'
|
||||
accessToken: string
|
||||
expiresAt: any
|
||||
}
|
||||
|
||||
type Media_ExternalVideo_Fragment = {
|
||||
__typename?: 'ExternalVideo'
|
||||
mediaContentType: MediaContentType
|
||||
alt?: string | null
|
||||
previewImage?: { __typename?: 'Image'; url: any } | null
|
||||
}
|
||||
|
||||
type Media_MediaImage_Fragment = {
|
||||
__typename?: 'MediaImage'
|
||||
id: string
|
||||
mediaContentType: MediaContentType
|
||||
alt?: string | null
|
||||
image?: {
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
} | null
|
||||
previewImage?: { __typename?: 'Image'; url: any } | null
|
||||
}
|
||||
|
||||
type Media_Model3d_Fragment = {
|
||||
__typename?: 'Model3d'
|
||||
mediaContentType: MediaContentType
|
||||
alt?: string | null
|
||||
previewImage?: { __typename?: 'Image'; url: any } | null
|
||||
}
|
||||
|
||||
type Media_Video_Fragment = {
|
||||
__typename?: 'Video'
|
||||
mediaContentType: MediaContentType
|
||||
alt?: string | null
|
||||
previewImage?: { __typename?: 'Image'; url: any } | null
|
||||
}
|
||||
|
||||
export type MediaFragment =
|
||||
| Media_ExternalVideo_Fragment
|
||||
| Media_MediaImage_Fragment
|
||||
| Media_Model3d_Fragment
|
||||
| Media_Video_Fragment
|
||||
|
||||
export type ProductCardFragment = {
|
||||
__typename?: 'Product'
|
||||
id: string
|
||||
handle: string
|
||||
availableForSale: boolean
|
||||
title: string
|
||||
productType: string
|
||||
vendor: string
|
||||
variants: {
|
||||
__typename?: 'ProductVariantConnection'
|
||||
nodes: Array<{
|
||||
__typename?: 'ProductVariant'
|
||||
id: string
|
||||
title: string
|
||||
requiresShipping: boolean
|
||||
availableForSale: boolean
|
||||
selectedOptions: Array<{
|
||||
__typename?: 'SelectedOption'
|
||||
name: string
|
||||
value: string
|
||||
}>
|
||||
image?: {
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
altText?: string | null
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
} | null
|
||||
priceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
compareAtPriceV2?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export type CartCreateMutationVariables = Exact<{
|
||||
@ -7170,6 +7341,54 @@ export type CartLinesUpdateMutation = {
|
||||
} | null
|
||||
}
|
||||
|
||||
export type CustomerActivateMutationVariables = Exact<{
|
||||
id: Scalars['ID']
|
||||
input: CustomerActivateInput
|
||||
}>
|
||||
|
||||
export type CustomerActivateMutation = {
|
||||
__typename?: 'Mutation'
|
||||
customerActivate?: {
|
||||
__typename?: 'CustomerActivatePayload'
|
||||
customer?: { __typename?: 'Customer'; id: string } | null
|
||||
customerAccessToken?: {
|
||||
__typename?: 'CustomerAccessToken'
|
||||
accessToken: string
|
||||
expiresAt: any
|
||||
} | null
|
||||
customerUserErrors: Array<{
|
||||
__typename?: 'CustomerUserError'
|
||||
code?: CustomerErrorCode | null
|
||||
field?: Array<string> | null
|
||||
message: string
|
||||
}>
|
||||
} | null
|
||||
}
|
||||
|
||||
export type CustomerActivateByUrlMutationVariables = Exact<{
|
||||
activationUrl: Scalars['URL']
|
||||
password: Scalars['String']
|
||||
}>
|
||||
|
||||
export type CustomerActivateByUrlMutation = {
|
||||
__typename?: 'Mutation'
|
||||
customerActivateByUrl?: {
|
||||
__typename?: 'CustomerActivateByUrlPayload'
|
||||
customer?: { __typename?: 'Customer'; id: string } | null
|
||||
customerAccessToken?: {
|
||||
__typename?: 'CustomerAccessToken'
|
||||
accessToken: string
|
||||
expiresAt: any
|
||||
} | null
|
||||
customerUserErrors: Array<{
|
||||
__typename?: 'CustomerUserError'
|
||||
code?: CustomerErrorCode | null
|
||||
field?: Array<string> | null
|
||||
message: string
|
||||
}>
|
||||
} | null
|
||||
}
|
||||
|
||||
export type CustomerAccessTokenCreateMutationVariables = Exact<{
|
||||
input: CustomerAccessTokenCreateInput
|
||||
}>
|
||||
@ -7210,54 +7429,6 @@ export type CustomerAccessTokenDeleteMutation = {
|
||||
} | null
|
||||
}
|
||||
|
||||
export type CustomerActivateByUrlMutationVariables = Exact<{
|
||||
activationUrl: Scalars['URL']
|
||||
password: Scalars['String']
|
||||
}>
|
||||
|
||||
export type CustomerActivateByUrlMutation = {
|
||||
__typename?: 'Mutation'
|
||||
customerActivateByUrl?: {
|
||||
__typename?: 'CustomerActivateByUrlPayload'
|
||||
customer?: { __typename?: 'Customer'; id: string } | null
|
||||
customerAccessToken?: {
|
||||
__typename?: 'CustomerAccessToken'
|
||||
accessToken: string
|
||||
expiresAt: any
|
||||
} | null
|
||||
customerUserErrors: Array<{
|
||||
__typename?: 'CustomerUserError'
|
||||
code?: CustomerErrorCode | null
|
||||
field?: Array<string> | null
|
||||
message: string
|
||||
}>
|
||||
} | null
|
||||
}
|
||||
|
||||
export type CustomerActivateMutationVariables = Exact<{
|
||||
id: Scalars['ID']
|
||||
input: CustomerActivateInput
|
||||
}>
|
||||
|
||||
export type CustomerActivateMutation = {
|
||||
__typename?: 'Mutation'
|
||||
customerActivate?: {
|
||||
__typename?: 'CustomerActivatePayload'
|
||||
customer?: { __typename?: 'Customer'; id: string } | null
|
||||
customerAccessToken?: {
|
||||
__typename?: 'CustomerAccessToken'
|
||||
accessToken: string
|
||||
expiresAt: any
|
||||
} | null
|
||||
customerUserErrors: Array<{
|
||||
__typename?: 'CustomerUserError'
|
||||
code?: CustomerErrorCode | null
|
||||
field?: Array<string> | null
|
||||
message: string
|
||||
}>
|
||||
} | null
|
||||
}
|
||||
|
||||
export type CustomerCreateMutationVariables = Exact<{
|
||||
input: CustomerCreateInput
|
||||
}>
|
||||
@ -7355,51 +7526,6 @@ export type GetAllProductPathsQuery = {
|
||||
}
|
||||
}
|
||||
|
||||
export type ProductConnectionFragment = {
|
||||
__typename?: 'ProductConnection'
|
||||
pageInfo: {
|
||||
__typename?: 'PageInfo'
|
||||
hasNextPage: boolean
|
||||
hasPreviousPage: boolean
|
||||
}
|
||||
edges: Array<{
|
||||
__typename?: 'ProductEdge'
|
||||
node: {
|
||||
__typename?: 'Product'
|
||||
id: string
|
||||
title: string
|
||||
vendor: string
|
||||
handle: string
|
||||
priceRange: {
|
||||
__typename?: 'ProductPriceRange'
|
||||
minVariantPrice: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
}
|
||||
images: {
|
||||
__typename?: 'ImageConnection'
|
||||
pageInfo: {
|
||||
__typename?: 'PageInfo'
|
||||
hasNextPage: boolean
|
||||
hasPreviousPage: boolean
|
||||
}
|
||||
edges: Array<{
|
||||
__typename?: 'ImageEdge'
|
||||
node: {
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
altText?: string | null
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
}
|
||||
}>
|
||||
}
|
||||
}
|
||||
}>
|
||||
}
|
||||
|
||||
export type GetAllProductsQueryVariables = Exact<{
|
||||
first?: InputMaybe<Scalars['Int']>
|
||||
query?: InputMaybe<Scalars['String']>
|
||||
@ -7421,33 +7547,41 @@ export type GetAllProductsQuery = {
|
||||
node: {
|
||||
__typename?: 'Product'
|
||||
id: string
|
||||
title: string
|
||||
vendor: string
|
||||
handle: string
|
||||
priceRange: {
|
||||
__typename?: 'ProductPriceRange'
|
||||
minVariantPrice: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
}
|
||||
images: {
|
||||
__typename?: 'ImageConnection'
|
||||
pageInfo: {
|
||||
__typename?: 'PageInfo'
|
||||
hasNextPage: boolean
|
||||
hasPreviousPage: boolean
|
||||
}
|
||||
edges: Array<{
|
||||
__typename?: 'ImageEdge'
|
||||
node: {
|
||||
availableForSale: boolean
|
||||
title: string
|
||||
productType: string
|
||||
vendor: string
|
||||
variants: {
|
||||
__typename?: 'ProductVariantConnection'
|
||||
nodes: Array<{
|
||||
__typename?: 'ProductVariant'
|
||||
id: string
|
||||
title: string
|
||||
requiresShipping: boolean
|
||||
availableForSale: boolean
|
||||
selectedOptions: Array<{
|
||||
__typename?: 'SelectedOption'
|
||||
name: string
|
||||
value: string
|
||||
}>
|
||||
image?: {
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
altText?: string | null
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
} | null
|
||||
priceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
compareAtPriceV2?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
}>
|
||||
}
|
||||
}
|
||||
@ -7455,87 +7589,6 @@ export type GetAllProductsQuery = {
|
||||
}
|
||||
}
|
||||
|
||||
export type CartDetailsFragment = {
|
||||
__typename?: 'Cart'
|
||||
id: string
|
||||
checkoutUrl: any
|
||||
createdAt: any
|
||||
updatedAt: any
|
||||
lines: {
|
||||
__typename?: 'CartLineConnection'
|
||||
edges: Array<{
|
||||
__typename?: 'CartLineEdge'
|
||||
node: {
|
||||
__typename?: 'CartLine'
|
||||
id: string
|
||||
quantity: number
|
||||
merchandise: {
|
||||
__typename?: 'ProductVariant'
|
||||
id: string
|
||||
sku?: string | null
|
||||
title: string
|
||||
selectedOptions: Array<{
|
||||
__typename?: 'SelectedOption'
|
||||
name: string
|
||||
value: string
|
||||
}>
|
||||
image?: {
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
altText?: string | null
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
} | null
|
||||
priceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
compareAtPriceV2?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
product: { __typename?: 'Product'; title: string; handle: string }
|
||||
}
|
||||
}
|
||||
}>
|
||||
}
|
||||
attributes: Array<{
|
||||
__typename?: 'Attribute'
|
||||
key: string
|
||||
value?: string | null
|
||||
}>
|
||||
buyerIdentity: {
|
||||
__typename?: 'CartBuyerIdentity'
|
||||
email?: string | null
|
||||
customer?: { __typename?: 'Customer'; id: string } | null
|
||||
}
|
||||
estimatedCost: {
|
||||
__typename?: 'CartEstimatedCost'
|
||||
totalAmount: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
subtotalAmount: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
totalTaxAmount?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
totalDutyAmount?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
}
|
||||
}
|
||||
|
||||
export type GetCartQueryVariables = Exact<{
|
||||
cartId: Scalars['ID']
|
||||
}>
|
||||
@ -7624,181 +7677,6 @@ export type GetCartQuery = {
|
||||
} | null
|
||||
}
|
||||
|
||||
export type CheckoutDetailsFragment = {
|
||||
__typename?: 'Checkout'
|
||||
id: string
|
||||
webUrl: any
|
||||
completedAt?: any | null
|
||||
createdAt: any
|
||||
taxesIncluded: boolean
|
||||
subtotalPriceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
totalTaxV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
totalPriceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
lineItems: {
|
||||
__typename?: 'CheckoutLineItemConnection'
|
||||
pageInfo: {
|
||||
__typename?: 'PageInfo'
|
||||
hasNextPage: boolean
|
||||
hasPreviousPage: boolean
|
||||
}
|
||||
edges: Array<{
|
||||
__typename?: 'CheckoutLineItemEdge'
|
||||
node: {
|
||||
__typename?: 'CheckoutLineItem'
|
||||
id: string
|
||||
title: string
|
||||
quantity: number
|
||||
variant?: {
|
||||
__typename?: 'ProductVariant'
|
||||
id: string
|
||||
sku?: string | null
|
||||
title: string
|
||||
selectedOptions: Array<{
|
||||
__typename?: 'SelectedOption'
|
||||
name: string
|
||||
value: string
|
||||
}>
|
||||
image?: {
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
altText?: string | null
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
} | null
|
||||
priceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
compareAtPriceV2?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
product: { __typename?: 'Product'; handle: string }
|
||||
} | null
|
||||
}
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export type GetCheckoutQueryVariables = Exact<{
|
||||
checkoutId: Scalars['ID']
|
||||
}>
|
||||
|
||||
export type GetCheckoutQuery = {
|
||||
__typename?: 'QueryRoot'
|
||||
node?:
|
||||
| { __typename?: 'AppliedGiftCard' }
|
||||
| { __typename?: 'Article' }
|
||||
| { __typename?: 'Blog' }
|
||||
| { __typename?: 'Cart' }
|
||||
| { __typename?: 'CartLine' }
|
||||
| {
|
||||
__typename?: 'Checkout'
|
||||
id: string
|
||||
webUrl: any
|
||||
completedAt?: any | null
|
||||
createdAt: any
|
||||
taxesIncluded: boolean
|
||||
subtotalPriceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
totalTaxV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
totalPriceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
lineItems: {
|
||||
__typename?: 'CheckoutLineItemConnection'
|
||||
pageInfo: {
|
||||
__typename?: 'PageInfo'
|
||||
hasNextPage: boolean
|
||||
hasPreviousPage: boolean
|
||||
}
|
||||
edges: Array<{
|
||||
__typename?: 'CheckoutLineItemEdge'
|
||||
node: {
|
||||
__typename?: 'CheckoutLineItem'
|
||||
id: string
|
||||
title: string
|
||||
quantity: number
|
||||
variant?: {
|
||||
__typename?: 'ProductVariant'
|
||||
id: string
|
||||
sku?: string | null
|
||||
title: string
|
||||
selectedOptions: Array<{
|
||||
__typename?: 'SelectedOption'
|
||||
name: string
|
||||
value: string
|
||||
}>
|
||||
image?: {
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
altText?: string | null
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
} | null
|
||||
priceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
compareAtPriceV2?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
product: { __typename?: 'Product'; handle: string }
|
||||
} | null
|
||||
}
|
||||
}>
|
||||
}
|
||||
}
|
||||
| { __typename?: 'CheckoutLineItem' }
|
||||
| { __typename?: 'Collection' }
|
||||
| { __typename?: 'Comment' }
|
||||
| { __typename?: 'ExternalVideo' }
|
||||
| { __typename?: 'GenericFile' }
|
||||
| { __typename?: 'Location' }
|
||||
| { __typename?: 'MailingAddress' }
|
||||
| { __typename?: 'MediaImage' }
|
||||
| { __typename?: 'Menu' }
|
||||
| { __typename?: 'MenuItem' }
|
||||
| { __typename?: 'Metafield' }
|
||||
| { __typename?: 'Model3d' }
|
||||
| { __typename?: 'Order' }
|
||||
| { __typename?: 'Page' }
|
||||
| { __typename?: 'Payment' }
|
||||
| { __typename?: 'Product' }
|
||||
| { __typename?: 'ProductOption' }
|
||||
| { __typename?: 'ProductVariant' }
|
||||
| { __typename?: 'Shop' }
|
||||
| { __typename?: 'ShopPolicy' }
|
||||
| { __typename?: 'Video' }
|
||||
| null
|
||||
}
|
||||
|
||||
export type GetProductsFromCollectionQueryVariables = Exact<{
|
||||
categoryId: Scalars['ID']
|
||||
first?: InputMaybe<Scalars['Int']>
|
||||
@ -7825,39 +7703,49 @@ export type GetProductsFromCollectionQuery = {
|
||||
__typename?: 'PageInfo'
|
||||
hasNextPage: boolean
|
||||
hasPreviousPage: boolean
|
||||
startCursor?: string | null
|
||||
endCursor?: string | null
|
||||
}
|
||||
edges: Array<{
|
||||
__typename?: 'ProductEdge'
|
||||
node: {
|
||||
__typename?: 'Product'
|
||||
id: string
|
||||
title: string
|
||||
vendor: string
|
||||
handle: string
|
||||
priceRange: {
|
||||
__typename?: 'ProductPriceRange'
|
||||
minVariantPrice: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
}
|
||||
images: {
|
||||
__typename?: 'ImageConnection'
|
||||
pageInfo: {
|
||||
__typename?: 'PageInfo'
|
||||
hasNextPage: boolean
|
||||
hasPreviousPage: boolean
|
||||
}
|
||||
edges: Array<{
|
||||
__typename?: 'ImageEdge'
|
||||
node: {
|
||||
availableForSale: boolean
|
||||
title: string
|
||||
productType: string
|
||||
vendor: string
|
||||
variants: {
|
||||
__typename?: 'ProductVariantConnection'
|
||||
nodes: Array<{
|
||||
__typename?: 'ProductVariant'
|
||||
id: string
|
||||
title: string
|
||||
requiresShipping: boolean
|
||||
availableForSale: boolean
|
||||
selectedOptions: Array<{
|
||||
__typename?: 'SelectedOption'
|
||||
name: string
|
||||
value: string
|
||||
}>
|
||||
image?: {
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
altText?: string | null
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
} | null
|
||||
priceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
compareAtPriceV2?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
}>
|
||||
}
|
||||
}
|
||||
@ -7961,6 +7849,7 @@ export type GetPageQuery = {
|
||||
|
||||
export type GetProductBySlugQueryVariables = Exact<{
|
||||
slug: Scalars['String']
|
||||
withMetafields?: InputMaybe<Scalars['Boolean']>
|
||||
}>
|
||||
|
||||
export type GetProductBySlugQuery = {
|
||||
@ -7981,77 +7870,65 @@ export type GetProductBySlugQuery = {
|
||||
name: string
|
||||
values: Array<string>
|
||||
}>
|
||||
priceRange: {
|
||||
__typename?: 'ProductPriceRange'
|
||||
maxVariantPrice: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
minVariantPrice: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
seo: {
|
||||
__typename?: 'SEO'
|
||||
description?: string | null
|
||||
title?: string | null
|
||||
}
|
||||
variants: {
|
||||
__typename?: 'ProductVariantConnection'
|
||||
pageInfo: {
|
||||
__typename?: 'PageInfo'
|
||||
hasNextPage: boolean
|
||||
hasPreviousPage: boolean
|
||||
}
|
||||
edges: Array<{
|
||||
__typename?: 'ProductVariantEdge'
|
||||
node: {
|
||||
__typename?: 'ProductVariant'
|
||||
id: string
|
||||
title: string
|
||||
sku?: string | null
|
||||
availableForSale: boolean
|
||||
requiresShipping: boolean
|
||||
selectedOptions: Array<{
|
||||
__typename?: 'SelectedOption'
|
||||
name: string
|
||||
value: string
|
||||
}>
|
||||
priceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
compareAtPriceV2?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
nodes: Array<{
|
||||
__typename?: 'ProductVariant'
|
||||
id: string
|
||||
title: string
|
||||
sku?: string | null
|
||||
availableForSale: boolean
|
||||
requiresShipping: boolean
|
||||
image?: {
|
||||
__typename?: 'Image'
|
||||
id?: string | null
|
||||
altText?: string | null
|
||||
url: any
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
} | null
|
||||
selectedOptions: Array<{
|
||||
__typename?: 'SelectedOption'
|
||||
name: string
|
||||
value: string
|
||||
}>
|
||||
priceV2: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
}
|
||||
compareAtPriceV2?: {
|
||||
__typename?: 'MoneyV2'
|
||||
amount: any
|
||||
currencyCode: CurrencyCode
|
||||
} | null
|
||||
}>
|
||||
}
|
||||
metafields?: {
|
||||
__typename?: 'MetafieldConnection'
|
||||
nodes: Array<{
|
||||
__typename?: 'Metafield'
|
||||
key: string
|
||||
value: string
|
||||
namespace: string
|
||||
description?: string | null
|
||||
type: string
|
||||
}>
|
||||
}
|
||||
images: {
|
||||
__typename?: 'ImageConnection'
|
||||
pageInfo: {
|
||||
__typename?: 'PageInfo'
|
||||
hasNextPage: boolean
|
||||
hasPreviousPage: boolean
|
||||
}
|
||||
edges: Array<{
|
||||
__typename?: 'ImageEdge'
|
||||
node: {
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
altText?: string | null
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
}
|
||||
nodes: Array<{
|
||||
__typename?: 'Image'
|
||||
url: any
|
||||
altText?: string | null
|
||||
width?: number | null
|
||||
height?: number | null
|
||||
}>
|
||||
}
|
||||
} | null
|
||||
}
|
||||
|
||||
export type GetSiteInfoQueryVariables = Exact<{ [key: string]: never }>
|
||||
|
||||
export type GetSiteInfoQuery = {
|
||||
__typename?: 'QueryRoot'
|
||||
shop: { __typename?: 'Shop'; name: string }
|
||||
}
|
||||
|
@ -2948,7 +2948,7 @@ type Country {
|
||||
unitSystem: UnitSystem!
|
||||
}
|
||||
|
||||
"The code designating a country/region, which generally follows ISO 3166-1 alpha-2 guidelines.\nIf a territory doesn't have a country code value in the `CountryCode` enum, it might be considered a subdivision\nof another country. For example, the territories associated with Spain are represented by the country code `ES`,\nand the territories associated with the United States of America are represented by the country code `US`.\n"
|
||||
"The code designating a country/region, which generally follows ISO 3166-1 alpha-2 guidelines.\nIf a territory doesn't have a country code value in the `CountryCode` enum, then it might be considered a subdivision\nof another country. For example, the territories associated with Spain are represented by the country code `ES`,\nand the territories associated with the United States of America are represented by the country code `US`.\n"
|
||||
enum CountryCode {
|
||||
"""
|
||||
Ascension Island.
|
||||
@ -9638,7 +9638,7 @@ type Payment implements Node {
|
||||
nextActionUrl: URL
|
||||
|
||||
"""
|
||||
Whether or not the payment is still processing asynchronously.
|
||||
Whether the payment is still processing asynchronously.
|
||||
"""
|
||||
ready: Boolean!
|
||||
|
||||
@ -11598,7 +11598,7 @@ type ShopPolicyWithDefault {
|
||||
"The availability of a product variant at a particular location.\nLocal pick-up must be enabled in the store's shipping settings, otherwise this will return an empty result.\n"
|
||||
type StoreAvailability {
|
||||
"""
|
||||
Whether or not this product variant is in-stock at this location.
|
||||
Whether the product variant is in-stock at this location.
|
||||
"""
|
||||
available: Boolean!
|
||||
|
||||
|
@ -5,8 +5,10 @@ import type {
|
||||
import { GetProductOperation } from '../../types/product'
|
||||
import { normalizeProduct, getProductQuery } from '../../utils'
|
||||
import type { ShopifyConfig, Provider } from '..'
|
||||
|
||||
import {
|
||||
GetProductBySlugQuery,
|
||||
GetProductBySlugQueryVariables,
|
||||
Product as ShopifyProduct,
|
||||
} from '../../../schema'
|
||||
|
||||
@ -38,10 +40,12 @@ export default function getProductOperation({
|
||||
preview?: boolean
|
||||
}): Promise<T['data']> {
|
||||
const { fetch, locale } = commerce.getConfig(cfg)
|
||||
|
||||
const {
|
||||
data: { productByHandle },
|
||||
} = await fetch<GetProductBySlugQuery>(
|
||||
} = await fetch<
|
||||
GetProductBySlugQuery,
|
||||
Partial<GetProductBySlugQueryVariables>
|
||||
>(
|
||||
query,
|
||||
{
|
||||
variables,
|
||||
|
@ -5,9 +5,7 @@ import type {
|
||||
import { GetSiteInfoQueryVariables } from '../../../schema'
|
||||
import type { ShopifyConfig, Provider } from '..'
|
||||
import { GetSiteInfoOperation } from '../../types/site'
|
||||
|
||||
import { getBrands } from '../utils/get-brands'
|
||||
import { getCategories } from '../utils/get-categories'
|
||||
import { getBrands, getCategories } from '../../utils'
|
||||
|
||||
export const getSiteInfoQuery = /* GraphQL */ `
|
||||
query getSiteInfo {
|
||||
|
@ -6,7 +6,7 @@ import getProduct from './get-product'
|
||||
import getSiteInfo from './get-site-info'
|
||||
import login from './login'
|
||||
|
||||
export default {
|
||||
const operations = {
|
||||
getAllPages,
|
||||
getPage,
|
||||
getAllProducts,
|
||||
@ -15,3 +15,5 @@ export default {
|
||||
getSiteInfo,
|
||||
login,
|
||||
}
|
||||
|
||||
export default operations
|
||||
|
@ -2,6 +2,7 @@
|
||||
"provider": "shopify",
|
||||
"features": {
|
||||
"wishlist": false,
|
||||
"customerAuth": true
|
||||
"customerAuth": true,
|
||||
"metafields": true
|
||||
}
|
||||
}
|
||||
|
@ -1 +1,51 @@
|
||||
import * as Core from '@vercel/commerce/types/product'
|
||||
|
||||
export * from '@vercel/commerce/types/product'
|
||||
|
||||
type LiteralUnion<T extends string> = T | Omit<T, T>
|
||||
|
||||
export type MetaieldTypes =
|
||||
| 'integer'
|
||||
| 'boolean'
|
||||
| 'color'
|
||||
| 'json'
|
||||
| 'date'
|
||||
| 'file_reference'
|
||||
| 'date_time'
|
||||
| 'dimension'
|
||||
| 'multi_line_text_field'
|
||||
| 'number_decimal'
|
||||
| 'number_integer'
|
||||
| 'page_reference'
|
||||
| 'product_reference'
|
||||
| 'rating'
|
||||
| 'single_line_text_field'
|
||||
| 'url'
|
||||
| 'variant_reference'
|
||||
| 'volume'
|
||||
| 'weight'
|
||||
| 'list.color'
|
||||
| 'list.date'
|
||||
| 'list.date_time'
|
||||
| 'list.dimension'
|
||||
| 'list.file_reference'
|
||||
| 'list.number_integer'
|
||||
| 'list.number_decimal'
|
||||
| 'list.page_reference'
|
||||
| 'list.product_reference'
|
||||
| 'list.rating'
|
||||
| 'list.single_line_text_field'
|
||||
| 'list.url'
|
||||
| 'list.variant_reference'
|
||||
| 'list.volume'
|
||||
| 'list.weight'
|
||||
|
||||
export type MetafieldType = LiteralUnion<MetaieldTypes>
|
||||
|
||||
export type ProductMetafield = Core.ProductMetafield & {
|
||||
type?: MetafieldType
|
||||
}
|
||||
|
||||
export type Product = Core.Product & {
|
||||
metafields?: ProductMetafield[]
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ export const cartDetailsFragment = /* GraphQL */ `
|
||||
`
|
||||
|
||||
export const userErrorsFragment = /* GraphQL */ `
|
||||
fragment userErrors on UserError {
|
||||
fragment userErrors on CartUserError {
|
||||
code
|
||||
field
|
||||
message
|
||||
|
@ -1,5 +1,5 @@
|
||||
export const customerUserErrorsFragment = /* GraphQL */ `
|
||||
fragment customerUserErrors on CustomerUserErrors {
|
||||
fragment customerUserErrors on CustomerUserError {
|
||||
code
|
||||
field
|
||||
message
|
||||
@ -8,8 +8,7 @@ export const customerUserErrorsFragment = /* GraphQL */ `
|
||||
|
||||
export const customerAccessTokenFragment = /* GraphQL */ `
|
||||
fragment customerAccessToken on CustomerAccessToken {
|
||||
code
|
||||
field
|
||||
message
|
||||
accessToken
|
||||
expiresAt
|
||||
}
|
||||
`
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { ShopifyConfig } from '..'
|
||||
import { ShopifyConfig } from '../api'
|
||||
|
||||
import {
|
||||
GetAllProductVendorsQuery,
|
||||
GetAllProductVendorsQueryVariables,
|
||||
} from '../../../schema'
|
||||
} from '../../schema'
|
||||
|
||||
import { getAllProductVendors } from '../../utils/queries'
|
||||
import { getAllProductVendors } from './queries'
|
||||
|
||||
export type Brand = {
|
||||
entityId: string
|
@ -1,7 +1,8 @@
|
||||
import { ShopifyConfig } from '..'
|
||||
import type { Category } from '../../types/site'
|
||||
import { CollectionEdge } from '../../../schema'
|
||||
import { normalizeCategory, getSiteCollectionsQuery } from '../../utils'
|
||||
import { ShopifyConfig } from '../api'
|
||||
import type { Category } from '../types/site'
|
||||
import { CollectionEdge } from '../../schema'
|
||||
import { normalizeCategory } from '../utils/normalize'
|
||||
import { getSiteCollectionsQuery } from './queries'
|
||||
|
||||
export const getCategories = async ({
|
||||
fetch,
|
@ -1,8 +1,9 @@
|
||||
import { FetcherError } from '@vercel/commerce/utils/errors'
|
||||
|
||||
export function getError(err: any[] | string | null, status: number) {
|
||||
console.log(JSON.stringify(err, null, 2))
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
console.log(JSON.stringify(err, null, 2))
|
||||
}
|
||||
const errors = Array.isArray(err)
|
||||
? err
|
||||
: [{ message: err || 'Failed to fetch Shopify API' }]
|
||||
|
@ -3,6 +3,8 @@ export { handleFetchResponse } from './handle-fetch-response'
|
||||
export { cartCreate } from './cart-create'
|
||||
export { handleLogin, handleAutomaticLogin } from './handle-login'
|
||||
export { handleAccountActivation } from './handle-account-activation'
|
||||
export { getCategories } from './get-categories'
|
||||
export { getBrands } from './get-brands'
|
||||
|
||||
export * from './helpers'
|
||||
export * from './queries'
|
||||
|
@ -9,8 +9,12 @@ export const customerActivateMutation = /* GraphQL */ `
|
||||
customer {
|
||||
id
|
||||
}
|
||||
...customerAccessToken
|
||||
...customerUserErrors
|
||||
customerAccessToken {
|
||||
...customerAccessToken
|
||||
}
|
||||
customerUserErrors {
|
||||
...customerUserErrors
|
||||
}
|
||||
}
|
||||
}
|
||||
${customerUserErrorsFragment}
|
||||
@ -22,8 +26,12 @@ export const customerActivateByUrlMutation = /* GraphQL */ `
|
||||
customer {
|
||||
id
|
||||
}
|
||||
...customerAccessToken
|
||||
...customerUserErrors
|
||||
customerAccessToken {
|
||||
...customerAccessToken
|
||||
}
|
||||
customerUserErrors {
|
||||
...customerUserErrors
|
||||
}
|
||||
}
|
||||
}
|
||||
${customerUserErrorsFragment}
|
||||
@ -33,8 +41,12 @@ export const customerActivateByUrlMutation = /* GraphQL */ `
|
||||
export const customerAccessTokenCreateMutation = /* GraphQL */ `
|
||||
mutation customerAccessTokenCreate($input: CustomerAccessTokenCreateInput!) {
|
||||
customerAccessTokenCreate(input: $input) {
|
||||
...customerAccessToken
|
||||
...customerUserErrors
|
||||
customerAccessToken {
|
||||
...customerAccessToken
|
||||
}
|
||||
customerUserErrors {
|
||||
...customerUserErrors
|
||||
}
|
||||
}
|
||||
}
|
||||
${customerUserErrorsFragment}
|
||||
@ -46,16 +58,20 @@ export const customerAccessTokenDeleteMutation = /* GraphQL */ `
|
||||
customerAccessTokenDelete(customerAccessToken: $customerAccessToken) {
|
||||
deletedAccessToken
|
||||
deletedCustomerAccessTokenId
|
||||
...customerUserErrors
|
||||
userErrors {
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
${customerUserErrorsFragment}
|
||||
`
|
||||
|
||||
export const customerCreateMutation = /* GraphQL */ `
|
||||
mutation customerCreate($input: CustomerCreateInput!) {
|
||||
customerCreate(input: $input) {
|
||||
...customerUserErrors
|
||||
customerUserErrors {
|
||||
...customerUserErrors
|
||||
}
|
||||
customer {
|
||||
id
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
PageEdge,
|
||||
Collection,
|
||||
CartDetailsFragment,
|
||||
MetafieldConnection,
|
||||
} from '../../schema'
|
||||
import { colorMap } from './colors'
|
||||
import { CommerceError } from '@vercel/commerce/utils/errors'
|
||||
@ -114,7 +115,6 @@ export function normalizeProduct({
|
||||
...rest
|
||||
}: ShopifyProduct): Product {
|
||||
const variant = variants?.nodes?.[0]
|
||||
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
@ -132,11 +132,13 @@ export function normalizeProduct({
|
||||
.filter((o) => o.name !== 'Title') // By default Shopify adds a 'Title' name when there's only one option. We don't need it. https://community.shopify.com/c/Shopify-APIs-SDKs/Adding-new-product-variant-is-automatically-adding-quot-Default/td-p/358095
|
||||
.map((o) => normalizeProductOption(o))
|
||||
: [],
|
||||
metafields: metafields?.nodes?.map((m) => m) || [],
|
||||
...(description && { description }),
|
||||
...(descriptionHtml && { descriptionHtml }),
|
||||
...rest,
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeLineItem({
|
||||
node: { id, merchandise: variant, quantity },
|
||||
}: {
|
||||
|
@ -1,5 +1,5 @@
|
||||
export const getProductQuery = /* GraphQL */ `
|
||||
query getProductBySlug($slug: String!) {
|
||||
query getProductBySlug($slug: String!, $withMetafields: Boolean = false) {
|
||||
productByHandle(handle: $slug) {
|
||||
id
|
||||
handle
|
||||
@ -46,7 +46,16 @@ export const getProductQuery = /* GraphQL */ `
|
||||
}
|
||||
}
|
||||
}
|
||||
images(first: 15) {
|
||||
metafields(first: 25) @include(if: $withMetafields) {
|
||||
nodes {
|
||||
key
|
||||
value
|
||||
namespace
|
||||
description
|
||||
type
|
||||
}
|
||||
}
|
||||
images(first: 25) {
|
||||
nodes {
|
||||
url
|
||||
altText
|
||||
@ -55,15 +64,5 @@ export const getProductQuery = /* GraphQL */ `
|
||||
}
|
||||
}
|
||||
}
|
||||
shop {
|
||||
shippingPolicy {
|
||||
body
|
||||
handle
|
||||
}
|
||||
refundPolicy {
|
||||
body
|
||||
handle
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
@ -4,6 +4,7 @@
|
||||
"search": true,
|
||||
"wishlist": false,
|
||||
"customerAuth": false,
|
||||
"customCheckout": false
|
||||
"customCheckout": false,
|
||||
"metafields": false
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,15 @@ const Head: VFC = () => {
|
||||
content="width=device-width, initial-scale=1"
|
||||
/>
|
||||
<link rel="manifest" href="/site.webmanifest" key="site-manifest" />
|
||||
{process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN && (
|
||||
<link
|
||||
rel="preconnect"
|
||||
href={`https://${process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN.replace(
|
||||
/(^\w+:|^)\/\//,
|
||||
''
|
||||
)}`}
|
||||
/>
|
||||
)}
|
||||
</SEO>
|
||||
)
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import { WishlistButton } from '@components/wishlist'
|
||||
import ProductSidebar from '../ProductSidebar'
|
||||
import ProductTag from '../ProductTag'
|
||||
|
||||
import { useProduct } from '../product-context'
|
||||
import { useProduct } from '../context'
|
||||
|
||||
import s from './ProductDetails.module.css'
|
||||
import ProductSlider from '../ProductSlider'
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { memo } from 'react'
|
||||
import { Swatch } from '@components/product'
|
||||
import { useProduct } from '../product-context'
|
||||
import { useProduct } from '../context'
|
||||
|
||||
const ProductOptions: React.FC = () => {
|
||||
const { product, selectedOptions, setSelectedOptions } = useProduct()
|
||||
|
@ -4,8 +4,7 @@ import { FC, useState } from 'react'
|
||||
import { ProductOptions } from '@components/product'
|
||||
import { Button, Text, Rating, Collapse, useUI } from '@components/ui'
|
||||
|
||||
import { useProduct } from '../product-context'
|
||||
|
||||
import { useProduct } from '../context'
|
||||
interface ProductSidebarProps {
|
||||
className?: string
|
||||
}
|
||||
@ -60,6 +59,23 @@ const ProductSidebar: FC<ProductSidebarProps> = ({ className }) => {
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
{process.env.COMMERCE_METAFIELDS_ENABLED &&
|
||||
product.metafields &&
|
||||
product.metafields?.length > 0 && (
|
||||
<Collapse title="Metafields">
|
||||
<ul className="flex flex-col space-y-2 divide-y divide-dashed">
|
||||
{product.metafields.map((m) => (
|
||||
<li
|
||||
className="flex space-x-2 justify-start items-center text-sm pt-2"
|
||||
key={m.key}
|
||||
>
|
||||
<span className="font-bold capitalize">{m.key}</span>:
|
||||
<span>{m.value}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Collapse>
|
||||
)}
|
||||
<Collapse title="Care">
|
||||
This is a limited edition production run. Printing starts when the
|
||||
drop ends.
|
||||
|
@ -10,7 +10,7 @@ import cn from 'clsx'
|
||||
import { a } from '@react-spring/web'
|
||||
import s from './ProductSlider.module.css'
|
||||
import ProductSliderControl from '../ProductSliderControl'
|
||||
import { useProduct } from '../product-context'
|
||||
import { useProduct } from '../context'
|
||||
|
||||
interface ProductSliderProps {
|
||||
children: React.ReactNode[]
|
||||
@ -21,7 +21,7 @@ const ProductSlider: React.FC<ProductSliderProps> = ({
|
||||
children,
|
||||
className = '',
|
||||
}) => {
|
||||
const { imageIndex, resetImageIndex } = useProduct()
|
||||
const { imageIndex, setImageIndex } = useProduct()
|
||||
const [currentSlide, setCurrentSlide] = useState(imageIndex ?? 0)
|
||||
const [isMounted, setIsMounted] = useState(false)
|
||||
const sliderContainerRef = useRef<HTMLDivElement>(null)
|
||||
@ -30,10 +30,10 @@ const ProductSlider: React.FC<ProductSliderProps> = ({
|
||||
const [ref, slider] = useKeenSlider<HTMLDivElement>({
|
||||
loop: true,
|
||||
slides: { perView: 1 },
|
||||
created: () => setIsMounted(true),
|
||||
dragStarted: () => {
|
||||
resetImageIndex()
|
||||
setImageIndex(null)
|
||||
},
|
||||
created: () => setIsMounted(true),
|
||||
slideChanged(s) {
|
||||
const slideNumber = s.track.details.rel
|
||||
setCurrentSlide(slideNumber)
|
||||
@ -79,22 +79,22 @@ const ProductSlider: React.FC<ProductSliderProps> = ({
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (imageIndex && imageIndex !== currentSlide) {
|
||||
slider.current?.moveToIdx(imageIndex, undefined, {
|
||||
if (imageIndex !== null) {
|
||||
slider.current?.moveToIdx(imageIndex, false, {
|
||||
duration: 0,
|
||||
})
|
||||
}
|
||||
}, [imageIndex, currentSlide, slider])
|
||||
}, [imageIndex, slider])
|
||||
|
||||
const onPrev = React.useCallback(() => {
|
||||
resetImageIndex()
|
||||
setImageIndex(null)
|
||||
slider.current?.prev()
|
||||
}, [resetImageIndex, slider])
|
||||
}, [setImageIndex, slider])
|
||||
|
||||
const onNext = React.useCallback(() => {
|
||||
resetImageIndex()
|
||||
setImageIndex(null)
|
||||
slider.current?.next()
|
||||
}, [resetImageIndex, slider])
|
||||
}, [setImageIndex, slider])
|
||||
|
||||
return (
|
||||
<div className={cn(s.root, className)} ref={sliderContainerRef}>
|
||||
@ -133,7 +133,7 @@ const ProductSlider: React.FC<ProductSliderProps> = ({
|
||||
}),
|
||||
id: `thumb-${idx}`,
|
||||
onClick: () => {
|
||||
resetImageIndex()
|
||||
setImageIndex(null)
|
||||
slider.current?.moveToIdx(idx)
|
||||
},
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ import type { Product } from '@commerce/types/product'
|
||||
|
||||
import { ProductCard } from '@components/product'
|
||||
import { Container, Text } from '@components/ui'
|
||||
import { ProductProvider } from '../product-context'
|
||||
import { ProductProvider } from '../context'
|
||||
import ProductDetails from '../ProductDetails/ProductDetails'
|
||||
import { SEO } from '@components/common'
|
||||
|
||||
|
@ -6,24 +6,18 @@ import {
|
||||
SelectedOptions,
|
||||
} from './helpers'
|
||||
|
||||
import React, {
|
||||
FC,
|
||||
ReactNode,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import React, { FC, useMemo, useState, ReactNode, useEffect } from 'react'
|
||||
|
||||
import usePrice from '@framework/product/use-price'
|
||||
|
||||
export interface ProductContextValue {
|
||||
product: Product
|
||||
imageIndex: number | null
|
||||
setImageIndex: React.Dispatch<React.SetStateAction<number | null>>
|
||||
price: string
|
||||
variant: ProductVariant
|
||||
selectedOptions: SelectedOptions
|
||||
setSelectedOptions: React.Dispatch<React.SetStateAction<SelectedOptions>>
|
||||
resetImageIndex: () => void
|
||||
}
|
||||
|
||||
export const ProductContext = React.createContext<ProductContextValue | null>(
|
||||
@ -43,12 +37,16 @@ export const ProductProvider: FC<ProductProviderProps> = ({
|
||||
}) => {
|
||||
const [selectedOptions, setSelectedOptions] = useState<SelectedOptions>({})
|
||||
const [imageIndex, setImageIndex] = useState<number | null>(null)
|
||||
const resetImageIndex = useCallback(() => setImageIndex(null), [])
|
||||
|
||||
const variant = useMemo(() => {
|
||||
const v = getProductVariant(product, selectedOptions)
|
||||
return v || product.variants[0]
|
||||
}, [product, selectedOptions])
|
||||
useEffect(
|
||||
() => selectDefaultOptionFromProduct(product, setSelectedOptions),
|
||||
[product]
|
||||
)
|
||||
|
||||
const variant = useMemo(
|
||||
() => getProductVariant(product, selectedOptions) || product.variants[0],
|
||||
[product, selectedOptions]
|
||||
)
|
||||
|
||||
const { price } = usePrice({
|
||||
amount: variant?.price?.value || product.price.value,
|
||||
@ -57,32 +55,29 @@ export const ProductProvider: FC<ProductProviderProps> = ({
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
selectDefaultOptionFromProduct(product, setSelectedOptions)
|
||||
}, [product])
|
||||
|
||||
useEffect(() => {
|
||||
const idx = product.images.findIndex(
|
||||
(image: ProductImage) => image.url === variant?.image?.url
|
||||
)
|
||||
if (idx) {
|
||||
const idx = product.images.findIndex((image: ProductImage) => {
|
||||
return image.url === variant?.image?.url
|
||||
})
|
||||
if (idx !== -1) {
|
||||
setImageIndex(idx)
|
||||
}
|
||||
}, [variant, product])
|
||||
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
price,
|
||||
product,
|
||||
variant,
|
||||
imageIndex,
|
||||
setImageIndex,
|
||||
selectedOptions,
|
||||
setSelectedOptions,
|
||||
}),
|
||||
[price, product, variant, imageIndex, selectedOptions]
|
||||
)
|
||||
|
||||
return (
|
||||
<ProductContext.Provider
|
||||
value={{
|
||||
price,
|
||||
product,
|
||||
variant,
|
||||
imageIndex,
|
||||
resetImageIndex,
|
||||
selectedOptions,
|
||||
setSelectedOptions,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ProductContext.Provider>
|
||||
<ProductContext.Provider value={value}>{children}</ProductContext.Provider>
|
||||
)
|
||||
}
|
||||
|
@ -18,7 +18,10 @@ export async function getStaticProps({
|
||||
const pagesPromise = commerce.getAllPages({ config, preview })
|
||||
const siteInfoPromise = commerce.getSiteInfo({ config, preview })
|
||||
const productPromise = commerce.getProduct({
|
||||
variables: { slug: params!.slug },
|
||||
variables: {
|
||||
slug: params!.slug,
|
||||
withMetafields: Boolean(process.env.COMMERCE_METAFIELDS_ENABLED),
|
||||
},
|
||||
config,
|
||||
preview,
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user