This commit is contained in:
cond0r 2023-01-31 09:11:58 +02:00
parent d1d9e8c434
commit 5ceb134d33
33 changed files with 1664 additions and 914 deletions

View File

@ -1,6 +1,6 @@
{
"schema": {
"https://${NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN}/api/2022-07/graphql.json": {
"https://${NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN}/api/2023-01/graphql.json": {
"headers": {
"X-Shopify-Storefront-Access-Token": "${NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN}"
}

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ directive @accessRestricted(
) on FIELD_DEFINITION | OBJECT
"""
Contextualizes data based on the additional information provided by the directive. For example, you can use the `@inContext(country: CA)` directive to [query a product's price](https://shopify.dev/api/examples/international-pricing#query-product-prices) in a storefront within the context of Canada.
Contextualizes data based on the additional information provided by the directive. For example, you can use the `@inContext(country: CA)` directive to [query a product's price](https://shopify.dev/custom-storefronts/internationalization/international-pricing) in a storefront within the context of Canada.
"""
directive @inContext(
"""
@ -58,22 +58,22 @@ type AppliedGiftCard implements Node {
"""
The amount that was taken from the gift card by applying it.
"""
amountUsed: Money! @deprecated(reason: "Use `amountUsedV2` instead.")
amountUsed: MoneyV2!
"""
The amount that was taken from the gift card by applying it.
"""
amountUsedV2: MoneyV2!
amountUsedV2: MoneyV2! @deprecated(reason: "Use `amountUsed` instead.")
"""
The amount left on the gift card.
"""
balance: Money! @deprecated(reason: "Use `balanceV2` instead.")
balance: MoneyV2!
"""
The amount left on the gift card.
"""
balanceV2: MoneyV2!
balanceV2: MoneyV2! @deprecated(reason: "Use `balance` instead.")
"""
A globally-unique identifier.
@ -560,6 +560,65 @@ enum BlogSortKeys {
TITLE
}
"The store's branding configuration.\n"
type Brand {
"""
The colors of the store's brand.
"""
colors: BrandColors!
"""
The store's cover image.
"""
coverImage: MediaImage
"""
The store's default logo.
"""
logo: MediaImage
"""
The store's short description.
"""
shortDescription: String
"""
The store's slogan.
"""
slogan: String
"""
The store's preferred logo for square UI elements.
"""
squareLogo: MediaImage
}
"A group of related colors for the shop's brand.\n"
type BrandColorGroup {
"""
The background color.
"""
background: Color
"""
The foreground color.
"""
foreground: Color
}
"The colors of the shop's brand.\n"
type BrandColors {
"""
The shop's primary brand colors.
"""
primary: [BrandColorGroup!]!
"""
The shop's secondary brand colors.
"""
secondary: [BrandColorGroup!]!
}
"""
Card brand, such as Visa or Mastercard, which can be used for payments.
"""
@ -595,9 +654,7 @@ enum CardBrand {
VISA
}
"""
A cart represents the merchandise that a buyer intends to purchase, and the estimated cost associated with the cart. To learn how to interact with a cart during a customer's session, refer to [Manage a cart with the Storefront API](https://shopify.dev/api/examples/cart).
"""
"A cart represents the merchandise that a buyer intends to purchase,\nand the estimated cost associated with the cart. Learn how to\n[interact with a cart](https://shopify.dev/custom-storefronts/internationalization/international-pricing)\nduring a customer's session.\n"
type Cart implements Node {
"""
An attribute associated with the cart.
@ -625,7 +682,7 @@ type Cart implements Node {
checkoutUrl: URL!
"""
The estimated costs that the buyer will pay at checkout. The costs are subject to change and changes will be reflected at checkout. The `cost` field uses the `buyerIdentity` field to determine [international pricing](https://shopify.dev/api/examples/international-pricing#create-a-cart).
The estimated costs that the buyer will pay at checkout. The costs are subject to change and changes will be reflected at checkout. The `cost` field uses the `buyerIdentity` field to determine [international pricing](https://shopify.dev/custom-storefronts/internationalization/international-pricing).
"""
cost: CartCost!
@ -634,9 +691,7 @@ type Cart implements Node {
"""
createdAt: DateTime!
"""
The delivery groups available for the cart, based on the default address of the logged-in customer.
"""
"The delivery groups available for the cart, based on the buyer identity default\ndelivery address preference or the default address of the logged-in customer.\n"
deliveryGroups(
"""
Returns the elements that come after the specified cursor.
@ -672,9 +727,7 @@ type Cart implements Node {
"The case-insensitive discount codes that the customer added at checkout.\n"
discountCodes: [CartDiscountCode!]!
"""
The estimated costs that the buyer will pay at checkout. The estimated costs are subject to change and changes will be reflected at checkout. The `estimatedCost` field uses the `buyerIdentity` field to determine [international pricing](https://shopify.dev/api/examples/international-pricing#create-a-cart).
"""
"The estimated costs that the buyer will pay at checkout.\nThe estimated costs are subject to change and changes will be reflected at checkout.\nThe `estimatedCost` field uses the `buyerIdentity` field to determine\n[international pricing](https://shopify.dev/custom-storefronts/internationalization/international-pricing).\n"
estimatedCost: CartEstimatedCost! @deprecated(reason: "Use `cost` instead.")
"""
@ -772,6 +825,9 @@ type CartBuyerIdentity {
"""
customer: Customer
"An ordered set of delivery addresses tied to the buyer that is interacting with the cart.\nThe rank of the preferences is determined by the order of the addresses in the array. Preferences\ncan be used to populate relevant fields in the checkout flow.\n"
deliveryAddressPreferences: [DeliveryAddress!]!
"""
The email address of the buyer that is interacting with the cart.
"""
@ -783,7 +839,7 @@ type CartBuyerIdentity {
phone: String
}
"Specifies the input fields to update the buyer information associated with a cart.\nBuyer identity is used to determine\n[international pricing](https://shopify.dev/api/examples/international-pricing#create-a-checkout)\nand should match the customer's shipping address.\n"
"Specifies the input fields to update the buyer information associated with a cart.\nBuyer identity is used to determine\n[international pricing](https://shopify.dev/custom-storefronts/internationalization/international-pricing)\nand should match the customer's shipping address.\n"
input CartBuyerIdentityInput {
"""
The country where the buyer is located.
@ -795,6 +851,9 @@ input CartBuyerIdentityInput {
"""
customerAccessToken: String
"An ordered set of delivery addresses tied to the buyer that is interacting with the cart.\nThe rank of the preferences is determined by the order of the addresses in the array. Preferences\ncan be used to populate relevant fields in the checkout flow.\n"
deliveryAddressPreferences: [DeliveryAddressInput!]
"""
The email address of the buyer that is interacting with the cart.
"""
@ -836,7 +895,7 @@ type CartCodeDiscountAllocation implements CartDiscountAllocation {
discountedAmount: MoneyV2!
}
"The costs that the buyer will pay at checkout.\nIt uses [`CartBuyerIdentity`](https://shopify.dev/api/storefront/reference/cart/cartbuyeridentity) to determine\n[international pricing](https://shopify.dev/api/examples/international-pricing#create-a-cart).\n"
"The costs that the buyer will pay at checkout.\nThe cart cost uses [`CartBuyerIdentity`](https://shopify.dev/api/storefront/reference/cart/cartbuyeridentity) to determine\n[international pricing](https://shopify.dev/custom-storefronts/internationalization/international-pricing).\n"
type CartCost {
"""
The estimated amount, before taxes and discounts, for the customer to pay at checkout. The checkout charge amount doesn't include any deferred payments that'll be paid at a later date. If the cart has no deferred payments, then the checkout charge amount is equivalent to `subtotalAmount`.
@ -962,6 +1021,11 @@ type CartDeliveryGroup {
The ID for the delivery group.
"""
id: ID!
"""
The selected delivery option for the delivery group.
"""
selectedDeliveryOption: CartDeliveryOption
}
"An auto-generated type for paginating through multiple CartDeliveryGroups.\n"
@ -1019,6 +1083,11 @@ type CartDeliveryOption {
"""
estimatedCost: MoneyV2!
"""
The unique identifier of the delivery option.
"""
handle: String!
"""
The title of the delivery option.
"""
@ -1095,7 +1164,7 @@ enum CartErrorCode {
MISSING_NOTE
}
"The estimated costs that the buyer will pay at checkout.\nIt uses [`CartBuyerIdentity`](https://shopify.dev/api/storefront/reference/cart/cartbuyeridentity) to determine\n[international pricing](https://shopify.dev/api/examples/international-pricing#create-a-cart).\n"
"The estimated costs that the buyer will pay at checkout.\nThe estimated cost uses\n[`CartBuyerIdentity`](https://shopify.dev/api/storefront/reference/cart/cartbuyeridentity)\nto determine\n[international pricing](https://shopify.dev/custom-storefronts/internationalization/international-pricing).\n"
type CartEstimatedCost {
"""
The estimated amount, before taxes and discounts, for the customer to pay at checkout. The checkout charge amount doesn't include any deferred payments that'll be paid at a later date. If the cart has no deferred payments, then the checkout charge amount is equivalent to`subtotal_amount`.
@ -1132,9 +1201,7 @@ input CartInput {
"""
attributes: [AttributeInput!]
"""
The customer associated with the cart. Used to determine [international pricing](https://shopify.dev/api/examples/international-pricing#create-a-checkout). Buyer identity should match the customer's shipping address.
"""
"The customer associated with the cart. Used to determine [international pricing]\n(https://shopify.dev/custom-storefronts/internationalization/international-pricing).\nBuyer identity should match the customer's shipping address.\n"
buyerIdentity: CartBuyerIdentityInput
"The case-insensitive discount codes that the customer added at checkout.\n"
@ -1403,6 +1470,34 @@ type CartNoteUpdatePayload {
userErrors: [CartUserError!]!
}
"The input fields for updating the selected delivery options for a delivery group.\n"
input CartSelectedDeliveryOptionInput {
"""
The ID of the cart delivery group.
"""
deliveryGroupId: ID!
"""
The handle of the selected delivery option.
"""
deliveryOptionHandle: String!
}
"""
Return type for `cartSelectedDeliveryOptionsUpdate` mutation.
"""
type CartSelectedDeliveryOptionsUpdatePayload {
"""
The updated cart.
"""
cart: Cart
"""
The list of errors that occurred from executing the mutation.
"""
userErrors: [CartUserError!]!
}
"""
Represents an error that happens during execution of a cart mutation.
"""
@ -1551,14 +1646,14 @@ type Checkout implements Node {
orderStatusUrl: URL
"""
The amount left to be paid. This is equal to the cost of the line items, taxes and shipping minus discounts and gift cards.
The amount left to be paid. This is equal to the cost of the line items, taxes, and shipping, minus discounts and gift cards.
"""
paymentDue: Money! @deprecated(reason: "Use `paymentDueV2` instead.")
paymentDue: MoneyV2!
"""
The amount left to be paid. This is equal to the cost of the line items, duties, taxes, and shipping, minus discounts and gift cards.
"""
paymentDueV2: MoneyV2!
paymentDueV2: MoneyV2! @deprecated(reason: "Use `paymentDue` instead.")
"Whether or not the Checkout is ready and can be completed. Checkouts may\nhave asynchronous operations that can take time to finish. If you want\nto complete a checkout or ensure all the fields are populated and up to\ndate, polling is required until the value is true.\n"
ready: Boolean!
@ -1582,14 +1677,14 @@ type Checkout implements Node {
shippingLine: ShippingRate
"""
Price of the checkout before shipping and taxes.
The price at checkout before shipping and taxes.
"""
subtotalPrice: Money! @deprecated(reason: "Use `subtotalPriceV2` instead.")
subtotalPrice: MoneyV2!
"""
The price at checkout before duties, shipping, and taxes.
"""
subtotalPriceV2: MoneyV2!
subtotalPriceV2: MoneyV2! @deprecated(reason: "Use `subtotalPrice` instead.")
"""
Whether the checkout is tax exempt.
@ -1607,24 +1702,24 @@ type Checkout implements Node {
totalDuties: MoneyV2
"""
The sum of all the prices of all the items in the checkout, taxes and discounts included.
The sum of all the prices of all the items in the checkout, including taxes and duties.
"""
totalPrice: Money! @deprecated(reason: "Use `totalPriceV2` instead.")
totalPrice: MoneyV2!
"""
The sum of all the prices of all the items in the checkout, including duties, taxes, and discounts.
The sum of all the prices of all the items in the checkout, including taxes and duties.
"""
totalPriceV2: MoneyV2!
totalPriceV2: MoneyV2! @deprecated(reason: "Use `totalPrice` instead.")
"""
The sum of all the taxes applied to the line items and shipping lines in the checkout.
"""
totalTax: Money! @deprecated(reason: "Use `totalTaxV2` instead.")
totalTax: MoneyV2!
"""
The sum of all the taxes applied to the line items and shipping lines in the checkout.
"""
totalTaxV2: MoneyV2!
totalTaxV2: MoneyV2! @deprecated(reason: "Use `totalTax` instead.")
"""
The date and time when the checkout was last updated.
@ -1975,6 +2070,11 @@ enum CheckoutErrorCode {
"""
DISCOUNT_ALREADY_APPLIED
"""
Discount code isn't working right now. Please contact us for help.
"""
DISCOUNT_CODE_APPLICATION_FAILED
"""
Discount disabled.
"""
@ -2634,6 +2734,9 @@ enum CollectionSortKeys {
UPDATED_AT
}
"A string containing a hexadecimal representation of a color.\n\nFor example, \"#6A8D48\".\n"
scalar Color
"""
A comment on an article.
"""
@ -5010,6 +5113,11 @@ type Customer implements HasMetafields {
identifiers: [HasMetafieldsIdentifier!]!
): [Metafield]!
"""
The number of orders that the customer has made at the store in their lifetime.
"""
numberOfOrders: UnsignedInt64!
"""
The orders associated with the customer.
"""
@ -5608,6 +5716,19 @@ scalar DateTime
"A signed decimal number, which supports arbitrary precision and is serialized as a string.\n\nExample values: `\"29.99\"`, `\"29.999\"`.\n"
scalar Decimal
"""
A delivery address of the buyer that is interacting with the cart.
"""
union DeliveryAddress = MailingAddress
"The input fields for delivery address preferences.\n"
input DeliveryAddressInput {
"""
A delivery address preference of a buyer that is interacting with the cart.
"""
deliveryAddress: MailingAddressInput
}
"""
List of different delivery method types.
"""
@ -5924,7 +6045,7 @@ type Filter {
values: [FilterValue!]!
}
"The type of data that the filter group represents.\n\nFor more information, refer to [Filter products in a collection with the Storefront API]\n(https://shopify.dev/api/examples/filter-products).\n"
"The type of data that the filter group represents.\n\nFor more information, refer to [Filter products in a collection with the Storefront API]\n(https://shopify.dev/custom-storefronts/products-collections/filter-products).\n"
enum FilterType {
"""
A boolean value.
@ -6124,7 +6245,7 @@ input GeoCoordinateInput {
longitude: Float!
}
"A string containing HTML code. Refer to the [HTML spec](https://html.spec.whatwg.org/#elements-3) for a\ncomplete list of HTML elements.\n\nExample value: `\"<p>Grey cotton knit sweater.</p>\"`.\n"
"A string containing HTML code. Refer to the [HTML spec](https://html.spec.whatwg.org/#elements-3) for a\ncomplete list of HTML elements.\n\nExample value: `\"<p>Grey cotton knit sweater.</p>\"`\n"
scalar HTML
"""
@ -7673,6 +7794,31 @@ type Metafield implements Node {
"""
reference: MetafieldReference
"""
A list of reference objects if the metafield's type is a resource reference list.
"""
references(
"""
Returns the elements that come after the specified cursor.
"""
after: String
"""
Returns the elements that come before the specified cursor.
"""
before: String
"""
Returns up to the first `n` elements from the list.
"""
first: Int
"""
Returns up to the last `n` elements from the list.
"""
last: Int
): MetafieldReferenceConnection
"The type name of the metafield.\nSee the list of [supported types](https://shopify.dev/apps/metafields/definitions/types).\n"
type: String!
@ -7721,13 +7867,178 @@ union MetafieldParentResource =
"Returns the resource which is being referred to by a metafield.\n"
union MetafieldReference =
GenericFile
Collection
| GenericFile
| MediaImage
| Metaobject
| Page
| Product
| ProductVariant
| Video
"An auto-generated type for paginating through multiple MetafieldReferences.\n"
type MetafieldReferenceConnection {
"""
A list of edges.
"""
edges: [MetafieldReferenceEdge!]!
"""
A list of the nodes contained in MetafieldReferenceEdge.
"""
nodes: [MetafieldReference!]!
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!
}
"An auto-generated type which holds one MetafieldReference and a cursor during pagination.\n"
type MetafieldReferenceEdge {
"""
A cursor for use in pagination.
"""
cursor: String!
"""
The item at the end of MetafieldReferenceEdge.
"""
node: MetafieldReference!
}
"""
An instance of a user-defined model based on a MetaobjectDefinition.
"""
type Metaobject implements Node {
"""
Accesses a field of the object by key.
"""
field(
"""
The key of the field.
"""
key: String!
): MetaobjectField
"All object fields with defined values.\nOmitted object keys can be assumed null, and no guarantees are made about field order.\n"
fields: [MetaobjectField!]!
"""
The unique handle of the metaobject. Useful as a custom ID.
"""
handle: String!
"""
A globally-unique identifier.
"""
id: ID!
"""
The type of the metaobject. Defines the namespace of its associated metafields.
"""
type: String!
"""
The date and time when the metaobject was last updated.
"""
updatedAt: DateTime!
}
"An auto-generated type for paginating through multiple Metaobjects.\n"
type MetaobjectConnection {
"""
A list of edges.
"""
edges: [MetaobjectEdge!]!
"""
A list of the nodes contained in MetaobjectEdge.
"""
nodes: [Metaobject!]!
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!
}
"An auto-generated type which holds one Metaobject and a cursor during pagination.\n"
type MetaobjectEdge {
"""
A cursor for use in pagination.
"""
cursor: String!
"""
The item at the end of MetaobjectEdge.
"""
node: Metaobject!
}
"""
Provides the value of a Metaobject field.
"""
type MetaobjectField {
"""
The field key.
"""
key: String!
"""
A referenced object if the field type is a resource reference.
"""
reference: MetafieldReference
"""
A list of referenced objects if the field type is a resource reference list.
"""
references(
"""
Returns the elements that come after the specified cursor.
"""
after: String
"""
Returns the elements that come before the specified cursor.
"""
before: String
"""
Returns up to the first `n` elements from the list.
"""
first: Int
"""
Returns up to the last `n` elements from the list.
"""
last: Int
): MetafieldReferenceConnection
"The type name of the field.\nSee the list of [supported types](https://shopify.dev/apps/metafields/definitions/types).\n"
type: String!
"""
The field value.
"""
value: String
}
"""
The input fields used to retrieve a metaobject by handle.
"""
input MetaobjectHandleInput {
"""
The handle of the metaobject.
"""
handle: String!
"""
The type of the metaobject.
"""
type: String!
}
"""
Represents a Shopify hosted 3D model.
"""
@ -7783,11 +8094,6 @@ type Model3dSource {
url: String!
}
"""
A monetary value string without a currency symbol or code. Example value: `"100.57"`.
"""
scalar Money
"""
Specifies the fields for a monetary value with currency.
"""
@ -7835,11 +8141,9 @@ type Mutation {
cartId: ID!
): CartAttributesUpdatePayload
"Updates customer information associated with a cart.\nBuyer identity is used to determine\n[international pricing](https://shopify.dev/api/examples/international-pricing#create-a-checkout)\nand should match the customer's shipping address.\n"
"Updates customer information associated with a cart.\nBuyer identity is used to determine\n[international pricing](https://shopify.dev/custom-storefronts/internationalization/international-pricing)\nand should match the customer's shipping address.\n"
cartBuyerIdentityUpdate(
"""
The customer associated with the cart. Used to determine [international pricing](https://shopify.dev/api/examples/international-pricing#create-a-checkout). Buyer identity should match the customer's shipping address.
"""
"The customer associated with the cart. Used to determine\n[international pricing](https://shopify.dev/custom-storefronts/internationalization/international-pricing).\nBuyer identity should match the customer's shipping address.\n"
buyerIdentity: CartBuyerIdentityInput!
"""
@ -7931,6 +8235,21 @@ type Mutation {
note: String
): CartNoteUpdatePayload
"""
Update the selected delivery options for a delivery group.
"""
cartSelectedDeliveryOptionsUpdate(
"""
The ID of the cart.
"""
cartId: ID!
"""
The selected delivery options.
"""
selectedDeliveryOptions: [CartSelectedDeliveryOptionInput!]!
): CartSelectedDeliveryOptionsUpdatePayload
"""
Updates the attributes of a checkout if `allowPartialAddresses` is `true`.
"""
@ -8325,7 +8644,7 @@ type Mutation {
customerAccessToken: String!
): CustomerDefaultAddressUpdatePayload
"\"Sends a reset password email to the customer. The reset password email contains a reset password URL and token that you can pass to the [`customerResetByUrl`](https://shopify.dev/api/storefront/latest/mutations/customerResetByUrl) or [`customerReset`](https://shopify.dev/api/storefront/latest/mutations/customerReset) mutation to reset the customer password.\"\n"
"Sends a reset password email to the customer. The reset password\nemail contains a reset password URL and token that you can pass to\nthe [`customerResetByUrl`](https://shopify.dev/api/storefront/latest/mutations/customerResetByUrl) or\n[`customerReset`](https://shopify.dev/api/storefront/latest/mutations/customerReset) mutation to reset the\ncustomer password.\n\nThis mutation is throttled by IP. With authenticated access,\nyou can provide a [`Shopify-Storefront-Buyer-IP`](https://shopify.dev/api/usage/authentication#optional-ip-header) instead of the request IP.\n\nMake sure that the value provided to `Shopify-Storefront-Buyer-IP` is trusted. Unthrottled access to this\nmutation presents a security risk.\n"
customerRecover(
"""
The email address of the customer to recover.
@ -8432,6 +8751,11 @@ type Order implements HasMetafields & Node {
"""
currentTotalTax: MoneyV2!
"""
A list of the custom attributes added to the order.
"""
customAttributes: [Attribute!]!
"""
The locale code in which this specific order happened.
"""
@ -8592,12 +8916,12 @@ type Order implements HasMetafields & Node {
"""
Price of the order before shipping and taxes.
"""
subtotalPrice: Money @deprecated(reason: "Use `subtotalPriceV2` instead.")
subtotalPrice: MoneyV2
"""
Price of the order before duties, shipping and taxes.
"""
subtotalPriceV2: MoneyV2
subtotalPriceV2: MoneyV2 @deprecated(reason: "Use `subtotalPrice` instead.")
"""
List of the orders successful fulfillments.
@ -8610,45 +8934,45 @@ type Order implements HasMetafields & Node {
): [Fulfillment!]
"""
The sum of all the prices of all the items in the order, taxes and discounts included (must be positive).
The sum of all the prices of all the items in the order, duties, taxes and discounts included (must be positive).
"""
totalPrice: Money! @deprecated(reason: "Use `totalPriceV2` instead.")
totalPrice: MoneyV2!
"""
The sum of all the prices of all the items in the order, duties, taxes and discounts included (must be positive).
"""
totalPriceV2: MoneyV2!
totalPriceV2: MoneyV2! @deprecated(reason: "Use `totalPrice` instead.")
"""
The total amount that has been refunded.
"""
totalRefunded: Money! @deprecated(reason: "Use `totalRefundedV2` instead.")
totalRefunded: MoneyV2!
"""
The total amount that has been refunded.
"""
totalRefundedV2: MoneyV2!
totalRefundedV2: MoneyV2! @deprecated(reason: "Use `totalRefunded` instead.")
"""
The total cost of shipping.
"""
totalShippingPrice: Money!
@deprecated(reason: "Use `totalShippingPriceV2` instead.")
totalShippingPrice: MoneyV2!
"""
The total cost of shipping.
"""
totalShippingPriceV2: MoneyV2!
@deprecated(reason: "Use `totalShippingPrice` instead.")
"""
The total cost of taxes.
"""
totalTax: Money @deprecated(reason: "Use `totalTaxV2` instead.")
totalTax: MoneyV2
"""
The total cost of taxes.
"""
totalTaxV2: MoneyV2
totalTaxV2: MoneyV2 @deprecated(reason: "Use `totalTax` instead.")
}
"""
@ -8697,6 +9021,11 @@ type OrderConnection {
Information to aid in pagination.
"""
pageInfo: PageInfo!
"""
The total count of Orders.
"""
totalCount: UnsignedInt64!
}
"An auto-generated type which holds one Order and a cursor during pagination.\n"
@ -9058,12 +9387,12 @@ type Payment implements Node {
"""
The amount of the payment.
"""
amount: Money! @deprecated(reason: "Use `amountV2` instead.")
amount: MoneyV2!
"""
The amount of the payment.
"""
amountV2: MoneyV2!
amountV2: MoneyV2! @deprecated(reason: "Use `amount` instead.")
"""
The billing address for the payment.
@ -9325,6 +9654,11 @@ type Product implements HasMetafields & Node & OnlineStorePublishable {
sortKey: ProductImageSortKeys = POSITION
): ImageConnection!
"""
Whether the product is a gift card.
"""
isGiftCard: Boolean!
"""
The media associated with the product.
"""
@ -9626,6 +9960,11 @@ input ProductFilter {
"""
productVendor: String
"""
A product tag to filter on.
"""
tag: String
"""
A variant metafield to filter on.
"""
@ -9776,12 +10115,12 @@ type ProductVariant implements HasMetafields & Node {
"""
The compare at price of the variant. This can be used to mark a variant as on sale, when `compareAtPrice` is higher than `price`.
"""
compareAtPrice: Money @deprecated(reason: "Use `compareAtPriceV2` instead.")
compareAtPrice: MoneyV2
"""
The compare at price of the variant. This can be used to mark a variant as on sale, when `compareAtPriceV2` is higher than `priceV2`.
"""
compareAtPriceV2: MoneyV2
compareAtPriceV2: MoneyV2 @deprecated(reason: "Use `compareAtPrice` instead.")
"""
Whether a product is out of stock but still available for purchase (used for backorders).
@ -9822,12 +10161,12 @@ type ProductVariant implements HasMetafields & Node {
"""
The product variants price.
"""
price: Money! @deprecated(reason: "Use `priceV2` instead.")
price: MoneyV2!
"""
The product variants price.
"""
priceV2: MoneyV2!
priceV2: MoneyV2! @deprecated(reason: "Use `price` instead.")
"""
The product object that the product variant belongs to.
@ -9908,6 +10247,11 @@ type ProductVariant implements HasMetafields & Node {
"""
last: Int
"""
Used to sort results based on proximity to the provided location.
"""
near: GeoCoordinateInput
"""
Reverse the order of the underlying list.
"""
@ -10104,9 +10448,7 @@ type QueryRoot {
sortKey: BlogSortKeys = ID
): BlogConnection!
"""
Retrieve a cart by its ID. For more information, refer to [Manage a cart with the Storefront API](https://shopify.dev/api/examples/cart).
"""
"Retrieve a cart by its ID. For more information, refer to\n[Manage a cart with the Storefront API](https://shopify.dev/custom-storefronts/cart/manage).\n"
cart(
"""
The ID of the cart.
@ -10240,6 +10582,61 @@ type QueryRoot {
handle: String!
): Menu
"""
Fetch a specific Metaobject by one of its unique identifiers.
"""
metaobject(
"""
The handle and type of the metaobject.
"""
handle: MetaobjectHandleInput
"""
The ID of the metaobject.
"""
id: ID
): Metaobject
"""
All active metaobjects for the shop.
"""
metaobjects(
"""
Returns the elements that come after the specified cursor.
"""
after: String
"""
Returns the elements that come before the specified cursor.
"""
before: String
"""
Returns up to the first `n` elements from the list.
"""
first: Int
"""
Returns up to the last `n` elements from the list.
"""
last: Int
"""
Reverse the order of the underlying list.
"""
reverse: Boolean = false
"""
The key of a field to sort with. Supports "id" and "updated_at".
"""
sortKey: String
"""
The type of metaobject to retrieve.
"""
type: String!
): MetaobjectConnection!
"""
Returns a specific node by ID.
"""
@ -10446,6 +10843,9 @@ type QueryRoot {
"""
last: Int
"Supported filter parameters:\n - `created_at`\n - `path`\n - `target`\n\nSee the detailed [search syntax](https://shopify.dev/api/usage/search-syntax)\nfor more information about using filters.\n"
query: String
"""
Reverse the order of the underlying list.
"""
@ -10901,12 +11301,12 @@ type ShippingRate {
"""
Price of this shipping rate.
"""
price: Money! @deprecated(reason: "Use `priceV2` instead.")
price: MoneyV2!
"""
Price of this shipping rate.
"""
priceV2: MoneyV2!
priceV2: MoneyV2! @deprecated(reason: "Use `price` instead.")
"""
Title of this shipping rate.
@ -10918,6 +11318,11 @@ type ShippingRate {
Shop represents a collection of the general settings and information about the shop.
"""
type Shop implements HasMetafields & Node {
"""
The shop's branding configuration.
"""
brand: Brand
"""
A description of the shop.
"""
@ -11180,12 +11585,12 @@ type Transaction {
"""
The amount of money that the transaction was for.
"""
amount: Money! @deprecated(reason: "Use `amountV2` instead.")
amount: MoneyV2!
"""
The amount of money that the transaction was for.
"""
amountV2: MoneyV2!
amountV2: MoneyV2! @deprecated(reason: "Use `amount` instead.")
"""
The kind of the transaction.
@ -11392,6 +11797,9 @@ enum UnitSystem {
METRIC_SYSTEM
}
"An unsigned 64-bit integer. Represents whole numeric values between 0 and 2^64 - 1 encoded as a string of base-10 digits.\n\nExample value: `\"50\"`.\n"
scalar UnsignedInt64
"""
A redirect on the online store.
"""

View File

@ -1,34 +1,15 @@
import {
SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CHECKOUT_URL_COOKIE,
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
} from '../../../const'
import associateCustomerWithCheckoutMutation from '../../../utils/mutations/associate-customer-with-checkout'
import { SHOPIFY_CART_URL_COOKIE } from '../../../const'
import type { CheckoutEndpoint } from '.'
const getCheckout: CheckoutEndpoint['handlers']['getCheckout'] = async ({
req,
config,
}) => {
const { cookies } = req
const checkoutUrl = cookies.get(SHOPIFY_CHECKOUT_URL_COOKIE)?.value
const customerCookie = cookies.get(SHOPIFY_CUSTOMER_TOKEN_COOKIE)?.value
const cartUrl = cookies.get(SHOPIFY_CART_URL_COOKIE)?.value
if (customerCookie) {
try {
await config.fetch(associateCustomerWithCheckoutMutation, {
variables: {
checkoutId: cookies.get(SHOPIFY_CHECKOUT_ID_COOKIE)?.value,
customerAccessToken: cookies.get(SHOPIFY_CUSTOMER_TOKEN_COOKIE)
?.value,
},
})
} catch (error) {
console.error(error)
}
return {
redirectTo: cartUrl || '/cart',
}
return { redirectTo: checkoutUrl ?? '/cart' }
}
export default getCheckout

View File

@ -8,7 +8,7 @@ import {
API_URL,
API_TOKEN,
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CART_ID_COOKIE,
} from '../const'
import fetchGraphqlApi from './utils/fetch-graphql-api'
@ -40,7 +40,7 @@ const config: ShopifyConfig = {
commerceUrl: API_URL,
apiToken: API_TOKEN,
customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE,
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
cartCookie: SHOPIFY_CART_ID_COOKIE,
cartCookieMaxAge: ONE_DAY * 30,
fetch: fetchGraphqlApi,
}

View File

@ -1,23 +1,28 @@
import { useCallback } from 'react'
import type { AddItemHook } from '@vercel/commerce/types/cart'
import type { MutationHook } from '@vercel/commerce/utils/types'
import type {
CartLinesAddMutation,
CartLinesAddMutationVariables,
} from '../../schema'
import { useCallback } from 'react'
import { CommerceError } from '@vercel/commerce/utils/errors'
import useAddItem, { UseAddItem } from '@vercel/commerce/cart/use-add-item'
import type { AddItemHook } from '@vercel/commerce/types/cart'
import useCart from './use-cart'
import {
checkoutLineItemAddMutation,
getCheckoutId,
checkoutToCart,
checkoutCreate,
} from '../utils'
import { Mutation, MutationCheckoutLineItemsAddArgs } from '../../schema'
import { normalizeCart } from '../utils/normalize'
import { getCartId, cartCreate } from '../utils/cart'
import throwUserErrors from '../utils/throw-user-errors'
import { cartLinesAddMutation } from '../utils/mutations/cart-mutations'
export default useAddItem as UseAddItem<typeof handler>
export const handler: MutationHook<AddItemHook> = {
fetchOptions: {
query: checkoutLineItemAddMutation,
query: cartLinesAddMutation,
},
async fetcher({ input: item, options, fetch }) {
if (
@ -29,29 +34,33 @@ export const handler: MutationHook<AddItemHook> = {
})
}
const lineItems = [
const lines = [
{
variantId: item.variantId,
merchandiseId: item.variantId,
quantity: item.quantity ?? 1,
},
]
let checkoutId = getCheckoutId()
let cartId = getCartId()
if (!checkoutId) {
return checkoutToCart(await checkoutCreate(fetch, lineItems))
if (!cartId) {
const cart = await cartCreate(fetch, lines)
return normalizeCart(cart)
} else {
const { checkoutLineItemsAdd } = await fetch<
Mutation,
MutationCheckoutLineItemsAddArgs
const { cartLinesAdd } = await fetch<
CartLinesAddMutation,
CartLinesAddMutationVariables
>({
...options,
variables: {
checkoutId,
lineItems,
cartId,
lines,
},
})
return checkoutToCart(checkoutLineItemsAdd)
throwUserErrors(cartLinesAdd?.userErrors)
return normalizeCart(cartLinesAdd?.cart)
}
},
useHook:

View File

@ -1,40 +1,33 @@
import type { SWRHook } from '@vercel/commerce/utils/types'
import type { GetCartHook } from '@vercel/commerce/types/cart'
import type { GetCartQueryVariables, QueryRoot } from '../../schema'
import { useMemo } from 'react'
import useCommerceCart, { type UseCart } from '@vercel/commerce/cart/use-cart'
import { checkoutToCart } from '../utils'
import getCheckoutQuery from '../utils/queries/get-checkout-query'
import Cookies from 'js-cookie'
import useCommerceCart, { UseCart } from '@vercel/commerce/cart/use-cart'
import {
SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CHECKOUT_URL_COOKIE,
} from '../const'
import { SHOPIFY_CART_ID_COOKIE } from '../const'
import { setCartUrlCookie } from '../utils/cart'
import { normalizeCart } from '../utils/normalize'
import { getCartQuery } from '../utils/queries/get-cart-query'
export default useCommerceCart as UseCart<typeof handler>
export const handler: SWRHook<GetCartHook> = {
fetchOptions: {
query: getCheckoutQuery,
query: getCartQuery,
},
async fetcher({ input: { cartId }, options, fetch }) {
if (cartId) {
const { node: checkout } = await fetch({
let { cart } = await fetch<QueryRoot, GetCartQueryVariables>({
...options,
variables: {
checkoutId: cartId,
},
variables: { cartId },
})
if (checkout?.completedAt) {
Cookies.remove(SHOPIFY_CHECKOUT_ID_COOKIE)
Cookies.remove(SHOPIFY_CHECKOUT_URL_COOKIE)
return null
if (cart) {
setCartUrlCookie(cart.checkoutUrl)
return normalizeCart(cart)
} else {
return checkoutToCart({
checkout,
})
Cookies.remove(SHOPIFY_CART_ID_COOKIE)
}
}
return null
@ -50,7 +43,7 @@ export const handler: SWRHook<GetCartHook> = {
Object.create(response, {
isEmpty: {
get() {
return (response.data?.lineItems.length ?? 0) <= 0
return (response.data?.lineItems?.length ?? 0) <= 0
},
enumerable: true,
},

View File

@ -1,19 +1,33 @@
import { useCallback } from 'react'
import type {
MutationHookContext,
HookFetcherContext,
} from '@vercel/commerce/utils/types'
import { ValidationError } from '@vercel/commerce/utils/errors'
import useRemoveItem, {
UseRemoveItem,
} from '@vercel/commerce/cart/use-remove-item'
import type {
CartLinesRemoveMutation,
CartLinesRemoveMutationVariables,
} from '../../schema'
import type {
Cart,
LineItem,
RemoveItemHook,
} from '@vercel/commerce/types/cart'
import { useCallback } from 'react'
import { ValidationError } from '@vercel/commerce/utils/errors'
import useRemoveItem, {
UseRemoveItem,
} from '@vercel/commerce/cart/use-remove-item'
import useCart from './use-cart'
import { getCartId } from '../utils/cart'
import { normalizeCart } from '../utils/normalize'
import { cartLinesRemoveMutation } from '../utils/mutations/cart-mutations'
import throwUserErrors from '../utils/throw-user-errors'
export type RemoveItemFn<T = any> = T extends LineItem
? (input?: RemoveItemActionInput<T>) => Promise<Cart | null | undefined>
: (input: RemoveItemActionInput<T>) => Promise<Cart | null>
@ -24,28 +38,26 @@ export type RemoveItemActionInput<T = any> = T extends LineItem
export default useRemoveItem as UseRemoveItem<typeof handler>
import {
checkoutLineItemRemoveMutation,
getCheckoutId,
checkoutToCart,
} from '../utils'
import { Mutation, MutationCheckoutLineItemsRemoveArgs } from '../../schema'
export const handler = {
fetchOptions: {
query: checkoutLineItemRemoveMutation,
query: cartLinesRemoveMutation,
},
async fetcher({
input: { itemId },
options,
fetch,
}: HookFetcherContext<RemoveItemHook>) {
const data = await fetch<Mutation, MutationCheckoutLineItemsRemoveArgs>({
const data = await fetch<
CartLinesRemoveMutation,
CartLinesRemoveMutationVariables
>({
...options,
variables: { checkoutId: getCheckoutId(), lineItemIds: [itemId] },
variables: { cartId: getCartId(), lineIds: [itemId] },
})
return checkoutToCart(data.checkoutLineItemsRemove)
throwUserErrors(data.cartLinesRemove?.userErrors)
return normalizeCart(data.cartLinesRemove?.cart)
},
useHook:
({ fetch }: MutationHookContext<RemoveItemHook>) =>

View File

@ -1,26 +1,29 @@
import type { UpdateItemHook, LineItem } from '@vercel/commerce/types/cart'
import type {
Mutation,
MutationCheckoutLineItemsUpdateArgs,
CartLinesUpdateMutation,
CartLinesUpdateMutationVariables,
} from '../../schema'
import type {
HookFetcherContext,
MutationHookContext,
} from '@vercel/commerce/utils/types'
import type { UpdateItemHook, LineItem } from '@vercel/commerce/types/cart'
import { useCallback } from 'react'
import debounce from 'lodash.debounce'
import { ValidationError } from '@vercel/commerce/utils/errors'
import useUpdateItem, {
type UseUpdateItem,
UseUpdateItem,
} from '@vercel/commerce/cart/use-update-item'
import useCart from './use-cart'
import { handler as removeItemHandler } from './use-remove-item'
import {
getCheckoutId,
checkoutLineItemUpdateMutation,
checkoutToCart,
} from '../utils'
import { getCartId } from '../utils/cart'
import { normalizeCart } from '../utils/normalize'
import { cartLinesUpdateMutation } from '../utils/mutations/cart-mutations'
export type UpdateItemActionInput<T = any> = T extends LineItem
? Partial<UpdateItemHook['actionInput']>
@ -30,7 +33,7 @@ export default useUpdateItem as UseUpdateItem<typeof handler>
export const handler = {
fetchOptions: {
query: checkoutLineItemUpdateMutation,
query: cartLinesUpdateMutation,
},
async fetcher({
input: { itemId, item },
@ -51,14 +54,14 @@ export const handler = {
message: 'The item quantity has to be a valid integer',
})
}
const { checkoutLineItemsUpdate } = await fetch<
Mutation,
MutationCheckoutLineItemsUpdateArgs
const { cartLinesUpdate } = await fetch<
CartLinesUpdateMutation,
CartLinesUpdateMutationVariables
>({
...options,
variables: {
checkoutId: getCheckoutId(),
lineItems: [
cartId: getCartId(),
lines: [
{
id: itemId,
quantity: item.quantity,
@ -67,7 +70,7 @@ export const handler = {
},
})
return checkoutToCart(checkoutLineItemsUpdate)
return normalizeCart(cartLinesUpdate?.cart)
},
useHook:
({ fetch }: MutationHookContext<UpdateItemHook>) =>

View File

@ -1,6 +1,6 @@
export const SHOPIFY_CHECKOUT_ID_COOKIE = 'shopify_checkoutId'
export const SHOPIFY_CART_ID_COOKIE = 'shopify_cartId'
export const SHOPIFY_CHECKOUT_URL_COOKIE = 'shopify_checkoutUrl'
export const SHOPIFY_CART_URL_COOKIE = 'shopify_cartUrl'
export const SHOPIFY_CUSTOMER_TOKEN_COOKIE = 'shopify_customerToken'
@ -8,6 +8,6 @@ export const STORE_DOMAIN = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN
export const SHOPIFY_COOKIE_EXPIRE = 30
export const API_URL = `https://${STORE_DOMAIN}/api/2022-07/graphql.json`
export const API_URL = `https://${STORE_DOMAIN}/api/2023-01/graphql.json`
export const API_TOKEN = process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN

View File

@ -1,4 +1,4 @@
import { SHOPIFY_CHECKOUT_ID_COOKIE } from './const'
import { SHOPIFY_CART_ID_COOKIE } from './const'
import { handler as useCart } from './cart/use-cart'
import { handler as useAddItem } from './cart/use-add-item'
@ -16,7 +16,7 @@ import fetcher from './fetcher'
export const shopifyProvider = {
locale: 'en-us',
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
cartCookie: SHOPIFY_CART_ID_COOKIE,
fetcher,
cart: { useCart, useAddItem, useUpdateItem, useRemoveItem },
customer: { useCustomer },

View File

@ -0,0 +1,65 @@
import type { FetcherOptions } from '@vercel/commerce/utils/types'
import type {
CartLineInput,
CartCreateMutation,
CartDetailsFragment,
CartCreateMutationVariables,
} from '../../schema'
import Cookies from 'js-cookie'
import { cartCreateMutation } from './mutations/cart-mutations'
import throwUserErrors from './throw-user-errors'
import {
SHOPIFY_CART_ID_COOKIE,
SHOPIFY_CART_URL_COOKIE,
SHOPIFY_COOKIE_EXPIRE,
} from '../const'
export const setCartUrlCookie = (cartUrl: string) => {
if (cartUrl) {
const oldCookie = Cookies.get(SHOPIFY_CART_URL_COOKIE)
if (oldCookie !== cartUrl) {
Cookies.set(SHOPIFY_CART_URL_COOKIE, cartUrl, {
expires: SHOPIFY_COOKIE_EXPIRE,
})
}
}
}
export const getCartId = (id?: string) => {
return id || Cookies.get(SHOPIFY_CART_ID_COOKIE)
}
export const cartCreate = async (
fetch: <T = any, B = Body>(options: FetcherOptions<B>) => Promise<T>,
lines?: Array<CartLineInput> | CartLineInput
): Promise<CartDetailsFragment | null | undefined> => {
const { cartCreate } = await fetch<
CartCreateMutation,
CartCreateMutationVariables
>({
query: cartCreateMutation,
variables: {
input: {
lines,
},
},
})
const cart = cartCreate?.cart
throwUserErrors(cartCreate?.userErrors)
if (cart?.id) {
const options = {
expires: SHOPIFY_COOKIE_EXPIRE,
}
Cookies.set(SHOPIFY_CART_ID_COOKIE, cart.id, options)
}
setCartUrlCookie(cart?.checkoutUrl)
return cart
}

View File

@ -1,45 +0,0 @@
import Cookies from 'js-cookie'
import {
SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CHECKOUT_URL_COOKIE,
SHOPIFY_COOKIE_EXPIRE,
} from '../const'
import checkoutCreateMutation from './mutations/checkout-create'
import {
CheckoutCreatePayload,
CheckoutLineItemInput,
Mutation,
MutationCheckoutCreateArgs,
} from '../../schema'
import { FetcherOptions } from '@vercel/commerce/utils/types'
export const checkoutCreate = async (
fetch: <T = any, B = Body>(options: FetcherOptions<B>) => Promise<T>,
lineItems: CheckoutLineItemInput[]
): Promise<CheckoutCreatePayload> => {
const { checkoutCreate } = await fetch<Mutation, MutationCheckoutCreateArgs>({
query: checkoutCreateMutation,
variables: {
input: { lineItems },
},
})
const checkout = checkoutCreate?.checkout
if (checkout) {
const checkoutId = checkout?.id
const options = {
expires: SHOPIFY_COOKIE_EXPIRE,
}
Cookies.set(SHOPIFY_CHECKOUT_ID_COOKIE, checkoutId, options)
if (checkout?.webUrl) {
Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout.webUrl, options)
}
}
return checkoutCreate!
}
export default checkoutCreate

View File

@ -1,41 +0,0 @@
import type { Cart } from '@vercel/commerce/types/cart'
import { CommerceError } from '@vercel/commerce/utils/errors'
import {
CheckoutLineItemsAddPayload,
CheckoutLineItemsRemovePayload,
CheckoutLineItemsUpdatePayload,
CheckoutCreatePayload,
CheckoutUserError,
Checkout,
Maybe,
} from '../../schema'
import { normalizeCart } from './normalize'
import throwUserErrors from './throw-user-errors'
export type CheckoutQuery = {
checkout: Checkout
checkoutUserErrors?: Array<CheckoutUserError>
}
export type CheckoutPayload =
| CheckoutLineItemsAddPayload
| CheckoutLineItemsUpdatePayload
| CheckoutLineItemsRemovePayload
| CheckoutCreatePayload
| CheckoutQuery
const checkoutToCart = (checkoutPayload?: Maybe<CheckoutPayload>): Cart => {
throwUserErrors(checkoutPayload?.checkoutUserErrors)
if (!checkoutPayload?.checkout) {
throw new CommerceError({
message: 'Missing checkout object from response',
})
}
return normalizeCart(checkoutPayload?.checkout)
}
export default checkoutToCart

View File

@ -0,0 +1,82 @@
export const cartDetailsFragment = /* GraphQL */ `
fragment CartDetails on Cart {
id
checkoutUrl
createdAt
updatedAt
lines(first: 10) {
edges {
node {
id
quantity
merchandise {
... on ProductVariant {
id
id
sku
title
selectedOptions {
name
value
}
image {
url
altText
width
height
}
price {
amount
currencyCode
}
compareAtPrice {
amount
currencyCode
}
product {
title
handle
}
}
}
}
}
}
attributes {
key
value
}
buyerIdentity {
email
customer {
id
}
}
estimatedCost {
totalAmount {
amount
currencyCode
}
subtotalAmount {
amount
currencyCode
}
totalTaxAmount {
amount
currencyCode
}
totalDutyAmount {
amount
currencyCode
}
}
}
`
export const userErrorsFragment = /* GraphQL */ `
fragment UserErrors on CartUserError {
code
field
message
}
`

View File

@ -1,8 +0,0 @@
import Cookies from 'js-cookie'
import { SHOPIFY_CHECKOUT_ID_COOKIE } from '../const'
const getCheckoutId = (id?: string) => {
return id ?? Cookies.get(SHOPIFY_CHECKOUT_ID_COOKIE)
}
export default getCheckoutId

View File

@ -3,9 +3,6 @@ export { default as getSearchVariables } from './get-search-variables'
export { default as getSortVariables } from './get-sort-variables'
export { default as getBrands } from './get-brands'
export { default as getCategories } from './get-categories'
export { default as getCheckoutId } from './get-checkout-id'
export { default as checkoutCreate } from './checkout-create'
export { default as checkoutToCart } from './checkout-to-cart'
export { default as handleLogin, handleAutomaticLogin } from './handle-login'
export { default as handleAccountActivation } from './handle-account-activation'
export { default as throwUserErrors } from './throw-user-errors'

View File

@ -0,0 +1,64 @@
import {
cartDetailsFragment,
userErrorsFragment,
} from '../fragments/cart-details-fragment'
export const cartCreateMutation = /* GraphQL */ `
mutation cartCreate($input: CartInput = {}) {
cartCreate(input: $input) {
cart {
...CartDetails
}
userErrors {
...UserErrors
}
}
}
${cartDetailsFragment}
${userErrorsFragment}
`
export const cartLinesAddMutation = /* GraphQL */ `
mutation cartLinesAdd($lines: [CartLineInput!]!, $cartId: ID!) {
cartLinesAdd(lines: $lines, cartId: $cartId) {
cart {
...CartDetails
}
userErrors {
...UserErrors
}
}
}
${cartDetailsFragment}
${userErrorsFragment}
`
export const cartLinesRemoveMutation = /* GraphQL */ `
mutation cartLinesRemove($cartId: ID!, $lineIds: [ID!]!) {
cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {
cart {
...CartDetails
}
userErrors {
...UserErrors
}
}
}
${cartDetailsFragment}
${userErrorsFragment}
`
export const cartLinesUpdateMutation = /* GraphQL */ `
mutation cartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!) {
cartLinesUpdate(cartId: $cartId, lines: $lines) {
cart {
...CartDetails
}
userErrors {
...UserErrors
}
}
}
${cartDetailsFragment}
${userErrorsFragment}
`

View File

@ -1,19 +0,0 @@
import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutCreateMutation = /* GraphQL */ `
mutation checkoutCreate($input: CheckoutCreateInput = {}) {
checkoutCreate(input: $input) {
checkoutUserErrors {
code
field
message
}
checkout {
...checkoutDetails
}
}
}
${checkoutDetailsFragment}
`
export default checkoutCreateMutation

View File

@ -1,22 +0,0 @@
import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutLineItemAddMutation = /* GraphQL */ `
mutation checkoutLineItemAdd(
$checkoutId: ID!
$lineItems: [CheckoutLineItemInput!]!
) {
checkoutLineItemsAdd(checkoutId: $checkoutId, lineItems: $lineItems) {
checkoutUserErrors {
code
field
message
}
checkout {
...checkoutDetails
}
}
}
${checkoutDetailsFragment}
`
export default checkoutLineItemAddMutation

View File

@ -1,21 +0,0 @@
import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutLineItemRemoveMutation = /* GraphQL */ `
mutation checkoutLineItemRemove($checkoutId: ID!, $lineItemIds: [ID!]!) {
checkoutLineItemsRemove(
checkoutId: $checkoutId
lineItemIds: $lineItemIds
) {
checkoutUserErrors {
code
field
message
}
checkout {
...checkoutDetails
}
}
}
${checkoutDetailsFragment}
`
export default checkoutLineItemRemoveMutation

View File

@ -1,22 +0,0 @@
import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutLineItemUpdateMutation = /* GraphQL */ `
mutation checkoutLineItemUpdate(
$checkoutId: ID!
$lineItems: [CheckoutLineItemUpdateInput!]!
) {
checkoutLineItemsUpdate(checkoutId: $checkoutId, lineItems: $lineItems) {
checkoutUserErrors {
code
field
message
}
checkout {
...checkoutDetails
}
}
}
${checkoutDetailsFragment}
`
export default checkoutLineItemUpdateMutation

View File

@ -1,8 +1,4 @@
export { default as customerCreateMutation } from './customer-create'
export { default as checkoutCreateMutation } from './checkout-create'
export { default as checkoutLineItemAddMutation } from './checkout-line-item-add'
export { default as checkoutLineItemUpdateMutation } from './checkout-line-item-update'
export { default as checkoutLineItemRemoveMutation } from './checkout-line-item-remove'
export { default as customerAccessTokenCreateMutation } from './customer-access-token-create'
export { default as customerAccessTokenDeleteMutation } from './customer-access-token-delete'
export { default as customerActivateMutation } from './customer-activate'

View File

@ -5,8 +5,6 @@ import type { Category } from '@vercel/commerce/types/site'
import type {
Product as ShopifyProduct,
Checkout,
CheckoutLineItemEdge,
SelectedOption,
ImageConnection,
ProductVariantConnection,
@ -15,9 +13,11 @@ import type {
Page as ShopifyPage,
PageEdge,
Collection,
CartDetailsFragment,
} from '../../schema'
import { colorMap } from './colors'
import { CommerceError } from '@vercel/commerce/utils/errors'
const money = ({ amount, currencyCode }: MoneyV2) => {
return {
@ -67,8 +67,8 @@ const normalizeProductVariants = ({ edges }: ProductVariantConnection) => {
selectedOptions,
sku,
title,
priceV2,
compareAtPriceV2,
price,
compareAtPrice,
requiresShipping,
availableForSale,
},
@ -77,8 +77,8 @@ const normalizeProductVariants = ({ edges }: ProductVariantConnection) => {
id,
name: title,
sku,
price: +priceV2.amount,
listPrice: +compareAtPriceV2?.amount,
price: +price.amount,
listPrice: +compareAtPrice?.amount,
requiresShipping,
availableForSale,
options: selectedOptions.map(({ name, value }: SelectedOption) => {
@ -129,51 +129,57 @@ export function normalizeProduct({
}
}
export function normalizeCart(checkout: Checkout): Cart {
return {
id: checkout.id,
url: checkout.webUrl,
customerId: '',
email: '',
createdAt: checkout.createdAt,
currency: {
code: checkout.totalPriceV2?.currencyCode,
},
taxesIncluded: checkout.taxesIncluded,
lineItems: checkout.lineItems?.edges.map(normalizeLineItem),
lineItemsSubtotalPrice: +checkout.subtotalPriceV2?.amount,
subtotalPrice: +checkout.subtotalPriceV2?.amount,
totalPrice: checkout.totalPriceV2?.amount,
discounts: [],
}
}
function normalizeLineItem({
node: { id, title, variant, quantity },
}: CheckoutLineItemEdge): LineItem {
node: { id, merchandise: variant, quantity },
}: {
node: any
}): LineItem {
return {
id,
variantId: String(variant?.id),
productId: String(variant?.id),
name: `${title}`,
quantity,
variantId: variant?.id,
productId: variant?.id,
name: variant?.product?.title || variant?.title,
quantity: quantity ?? 0,
variant: {
id: String(variant?.id),
id: variant?.id,
sku: variant?.sku ?? '',
name: variant?.title!,
image: {
url: variant?.image?.url || '/product-img-placeholder.svg',
},
requiresShipping: variant?.requiresShipping ?? false,
price: variant?.priceV2?.amount,
listPrice: variant?.compareAtPriceV2?.amount,
price: +variant?.price?.amount,
listPrice: +variant?.compareAtPrice?.amount,
},
path: String(variant?.product?.handle),
path: variant?.product?.handle,
discounts: [],
options: variant?.title == 'Default Title' ? [] : variant?.selectedOptions,
}
}
export function normalizeCart(
cart: CartDetailsFragment | undefined | null
): Cart {
if (!cart) {
throw new CommerceError({ message: 'Missing cart details' })
}
return {
id: cart.id,
customerId: cart.buyerIdentity?.customer?.id,
email: cart.buyerIdentity?.email ?? '',
createdAt: cart.createdAt,
currency: {
code: cart.estimatedCost?.totalAmount?.currencyCode,
},
taxesIncluded: !!cart.estimatedCost?.totalTaxAmount?.amount,
lineItems: cart.lines?.edges?.map(normalizeLineItem) ?? [],
lineItemsSubtotalPrice: +cart.estimatedCost?.subtotalAmount?.amount,
subtotalPrice: +cart.estimatedCost?.subtotalAmount?.amount,
totalPrice: +cart.estimatedCost?.totalAmount?.amount,
discounts: [],
}
}
export const normalizePage = (
{ title: name, handle, ...page }: ShopifyPage,
locale: string = 'en-US'

View File

@ -1,4 +1,4 @@
export const getAllPagesQuery = /* GraphQL */ `
const getAllPagesQuery = /* GraphQL */ `
query getAllPages($first: Int = 250) {
pages(first: $first) {
edges {

View File

@ -0,0 +1,10 @@
import { cartDetailsFragment } from '../fragments/cart-details-fragment'
export const getCartQuery = /* GraphQL */ `
query getCart($cartId: ID!) {
cart(id: $cartId) {
...CartDetails
}
}
${cartDetailsFragment}
`

View File

@ -1,70 +0,0 @@
export const checkoutDetailsFragment = /* GraphQL */ `
fragment checkoutDetails on Checkout {
id
webUrl
subtotalPriceV2 {
amount
currencyCode
}
totalTaxV2 {
amount
currencyCode
}
totalPriceV2 {
amount
currencyCode
}
completedAt
createdAt
taxesIncluded
lineItems(first: 250) {
pageInfo {
hasNextPage
hasPreviousPage
}
edges {
node {
id
title
variant {
id
sku
title
selectedOptions {
name
value
}
image {
url
altText
width
height
}
priceV2 {
amount
currencyCode
}
compareAtPriceV2 {
amount
currencyCode
}
product {
handle
}
}
quantity
}
}
}
}
`
const getCheckoutQuery = /* GraphQL */ `
query getCheckout($checkoutId: ID!) {
node(id: $checkoutId) {
...checkoutDetails
}
}
${checkoutDetailsFragment}
`
export default getCheckoutQuery

View File

@ -1,4 +1,4 @@
export const getCustomerQuery = /* GraphQL */ `
const getCustomerQuery = /* GraphQL */ `
query getCustomerId($customerAccessToken: String!) {
customer(customerAccessToken: $customerAccessToken) {
id

View File

@ -1,4 +1,4 @@
export const getCustomerQuery = /* GraphQL */ `
const getCustomerQuery = /* GraphQL */ `
query getCustomer($customerAccessToken: String!) {
customer(customerAccessToken: $customerAccessToken) {
id

View File

@ -1,4 +1,4 @@
export const getPageQuery = /* GraphQL */ `
const getPageQuery = /* GraphQL */ `
query getPage($id: ID!) {
node(id: $id) {
id

View File

@ -40,11 +40,11 @@ const getProductQuery = /* GraphQL */ `
name
value
}
priceV2 {
price {
amount
currencyCode
}
compareAtPriceV2 {
compareAtPrice {
amount
currencyCode
}

View File

@ -4,7 +4,6 @@ export { default as getAllProductsQuery } from './get-all-products-query'
export { default as getAllProductsPathtsQuery } from './get-all-products-paths-query'
export { default as getAllProductVendors } from './get-all-product-vendors-query'
export { default as getCollectionProductsQuery } from './get-collection-products-query'
export { default as getCheckoutQuery } from './get-checkout-query'
export { default as getAllPagesQuery } from './get-all-pages-query'
export { default as getPageQuery } from './get-page-query'
export { default as getCustomerQuery } from './get-customer-query'

View File

@ -5,13 +5,18 @@ import {
CheckoutUserError,
CustomerErrorCode,
CustomerUserError,
CartUserError,
CartErrorCode,
} from '../../schema'
export type UserErrors = Array<CheckoutUserError | CustomerUserError>
export type UserErrors = Array<
CheckoutUserError | CustomerUserError | CartUserError
>
export type UserErrorCode =
| CustomerErrorCode
| CheckoutErrorCode
| CartErrorCode
| null
| undefined
@ -24,7 +29,7 @@ const getCustomMessage = (code: UserErrorCode, message: string) => {
return message
}
export const throwUserErrors = (errors?: UserErrors) => {
const throwUserErrors = (errors?: UserErrors) => {
if (errors && errors.length) {
throw new ValidationError({
errors: errors.map(({ code, message }) => ({