Template
Initial commit
This commit is contained in:
+177
@@ -0,0 +1,177 @@
|
||||
import { gql } from '@shopify/hydrogen';
|
||||
|
||||
// Cart Fragment for consistent cart data
|
||||
const CartFragment = gql(`
|
||||
fragment CartFragment on Cart {
|
||||
id
|
||||
checkoutUrl
|
||||
totalQuantity
|
||||
discountCodes {
|
||||
code
|
||||
applicable
|
||||
}
|
||||
cost {
|
||||
subtotalAmount {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
totalAmount {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
totalTaxAmount {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
}
|
||||
lines(first: 100) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
quantity
|
||||
cost {
|
||||
totalAmount {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
}
|
||||
merchandise {
|
||||
... on ProductVariant {
|
||||
id
|
||||
title
|
||||
selectedOptions {
|
||||
name
|
||||
value
|
||||
}
|
||||
price {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
image {
|
||||
id
|
||||
url
|
||||
altText
|
||||
width
|
||||
height
|
||||
}
|
||||
product {
|
||||
id
|
||||
title
|
||||
handle
|
||||
vendor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
// Create a new cart
|
||||
export const CREATE_CART_MUTATION = gql(
|
||||
`
|
||||
mutation CreateCart($lines: [CartLineInput!], $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
cartCreate(input: { lines: $lines }) {
|
||||
cart {
|
||||
...CartFragment
|
||||
}
|
||||
userErrors {
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[CartFragment]
|
||||
);
|
||||
|
||||
// Add lines to cart
|
||||
export const ADD_CART_LINES_MUTATION = gql(
|
||||
`
|
||||
mutation AddCartLines($cartId: ID!, $lines: [CartLineInput!]!, $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
cartLinesAdd(cartId: $cartId, lines: $lines) {
|
||||
cart {
|
||||
...CartFragment
|
||||
}
|
||||
userErrors {
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[CartFragment]
|
||||
);
|
||||
|
||||
// Update cart lines
|
||||
export const UPDATE_CART_LINES_MUTATION = gql(
|
||||
`
|
||||
mutation UpdateCartLines($cartId: ID!, $lines: [CartLineUpdateInput!]!, $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
cartLinesUpdate(cartId: $cartId, lines: $lines) {
|
||||
cart {
|
||||
...CartFragment
|
||||
}
|
||||
userErrors {
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[CartFragment]
|
||||
);
|
||||
|
||||
// Remove lines from cart
|
||||
export const REMOVE_CART_LINES_MUTATION = gql(
|
||||
`
|
||||
mutation RemoveCartLines($cartId: ID!, $lineIds: [ID!]!, $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {
|
||||
cart {
|
||||
...CartFragment
|
||||
}
|
||||
userErrors {
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[CartFragment]
|
||||
);
|
||||
|
||||
// Apply (or clear) discount codes on the cart
|
||||
export const UPDATE_CART_DISCOUNT_CODES_MUTATION = gql(
|
||||
`
|
||||
mutation UpdateCartDiscountCodes($cartId: ID!, $discountCodes: [String!]!, $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) {
|
||||
cart {
|
||||
...CartFragment
|
||||
}
|
||||
userErrors {
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[CartFragment]
|
||||
);
|
||||
|
||||
// Get cart by ID
|
||||
export const GET_CART_QUERY = gql(
|
||||
`
|
||||
query GetCart($cartId: ID!, $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
cart(id: $cartId) {
|
||||
...CartFragment
|
||||
}
|
||||
}
|
||||
`,
|
||||
[CartFragment]
|
||||
);
|
||||
@@ -0,0 +1,91 @@
|
||||
import { gql } from '@shopify/hydrogen';
|
||||
import { ProductFragment } from '@/graphql/products';
|
||||
|
||||
// Get all collections
|
||||
export const GET_COLLECTIONS_QUERY = gql(`
|
||||
query GetCollections($first: Int!, $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
collections(first: $first) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
title
|
||||
handle
|
||||
description
|
||||
descriptionHtml
|
||||
image {
|
||||
id
|
||||
url
|
||||
altText
|
||||
width
|
||||
height
|
||||
}
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
// Get products in a collection
|
||||
export const GET_COLLECTION_PRODUCTS_QUERY = gql(
|
||||
`
|
||||
query GetCollectionProducts(
|
||||
$handle: String!
|
||||
$first: Int!
|
||||
$after: String
|
||||
$sortKey: ProductCollectionSortKeys
|
||||
$reverse: Boolean
|
||||
$filters: [ProductFilter!]
|
||||
$country: CountryCode
|
||||
$language: LanguageCode
|
||||
) @inContext(country: $country, language: $language) {
|
||||
collection(handle: $handle) {
|
||||
id
|
||||
title
|
||||
handle
|
||||
description
|
||||
descriptionHtml
|
||||
image {
|
||||
id
|
||||
url
|
||||
altText
|
||||
width
|
||||
height
|
||||
}
|
||||
products(
|
||||
first: $first
|
||||
after: $after
|
||||
sortKey: $sortKey
|
||||
reverse: $reverse
|
||||
filters: $filters
|
||||
) {
|
||||
filters {
|
||||
id
|
||||
label
|
||||
type
|
||||
values {
|
||||
id
|
||||
label
|
||||
count
|
||||
input
|
||||
}
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
...ProductFragment
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[ProductFragment]
|
||||
);
|
||||
@@ -0,0 +1,178 @@
|
||||
// Customer account operations (classic Storefront customer accounts).
|
||||
// https://shopify.dev/docs/api/storefront/latest/objects/Customer
|
||||
import { gql } from '@shopify/hydrogen';
|
||||
|
||||
const CustomerFragment = gql(`
|
||||
fragment CustomerFragment on Customer {
|
||||
id
|
||||
email
|
||||
firstName
|
||||
lastName
|
||||
phone
|
||||
displayName
|
||||
acceptsMarketing
|
||||
createdAt
|
||||
defaultAddress {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
address1
|
||||
address2
|
||||
city
|
||||
province
|
||||
zip
|
||||
country
|
||||
phone
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const CUSTOMER_QUERY = gql(
|
||||
`
|
||||
query GetCustomer($customerAccessToken: String!, $orderCount: Int!) {
|
||||
customer(customerAccessToken: $customerAccessToken) {
|
||||
...CustomerFragment
|
||||
orders(first: $orderCount, reverse: true) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
orderNumber
|
||||
processedAt
|
||||
financialStatus
|
||||
fulfillmentStatus
|
||||
statusUrl
|
||||
currentTotalPrice {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
lineItems(first: 5) {
|
||||
edges {
|
||||
node {
|
||||
title
|
||||
quantity
|
||||
variant {
|
||||
image {
|
||||
url
|
||||
altText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[CustomerFragment]
|
||||
);
|
||||
|
||||
export const CUSTOMER_CREATE_MUTATION = gql(`
|
||||
mutation CustomerCreate($input: CustomerCreateInput!) {
|
||||
customerCreate(input: $input) {
|
||||
customer {
|
||||
id
|
||||
email
|
||||
}
|
||||
customerUserErrors {
|
||||
code
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const CUSTOMER_ACCESS_TOKEN_CREATE_MUTATION = gql(`
|
||||
mutation CustomerAccessTokenCreate($input: CustomerAccessTokenCreateInput!) {
|
||||
customerAccessTokenCreate(input: $input) {
|
||||
customerAccessToken {
|
||||
accessToken
|
||||
expiresAt
|
||||
}
|
||||
customerUserErrors {
|
||||
code
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const CUSTOMER_ACCESS_TOKEN_DELETE_MUTATION = gql(`
|
||||
mutation CustomerAccessTokenDelete($customerAccessToken: String!) {
|
||||
customerAccessTokenDelete(customerAccessToken: $customerAccessToken) {
|
||||
deletedAccessToken
|
||||
userErrors {
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
// Sends the "reset your password" email.
|
||||
export const CUSTOMER_RECOVER_MUTATION = gql(`
|
||||
mutation CustomerRecover($email: String!) {
|
||||
customerRecover(email: $email) {
|
||||
customerUserErrors {
|
||||
code
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
// Completes the reset using the id + token from the emailed link.
|
||||
export const CUSTOMER_RESET_MUTATION = gql(`
|
||||
mutation CustomerReset($id: ID!, $input: CustomerResetInput!) {
|
||||
customerReset(id: $id, input: $input) {
|
||||
customerAccessToken {
|
||||
accessToken
|
||||
expiresAt
|
||||
}
|
||||
customerUserErrors {
|
||||
code
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
// Activation link sent to customers created by the merchant.
|
||||
export const CUSTOMER_ACTIVATE_MUTATION = gql(`
|
||||
mutation CustomerActivate($id: ID!, $input: CustomerActivateInput!) {
|
||||
customerActivate(id: $id, input: $input) {
|
||||
customerAccessToken {
|
||||
accessToken
|
||||
expiresAt
|
||||
}
|
||||
customerUserErrors {
|
||||
code
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const CUSTOMER_UPDATE_MUTATION = gql(
|
||||
`
|
||||
mutation CustomerUpdate($customerAccessToken: String!, $customer: CustomerUpdateInput!) {
|
||||
customerUpdate(customerAccessToken: $customerAccessToken, customer: $customer) {
|
||||
customer {
|
||||
...CustomerFragment
|
||||
}
|
||||
customerUserErrors {
|
||||
code
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[CustomerFragment]
|
||||
);
|
||||
@@ -0,0 +1,45 @@
|
||||
import { gql } from '@shopify/hydrogen';
|
||||
|
||||
// Shop policies are exposed on the `shop` object of the Storefront API.
|
||||
// There is no lookup-by-handle field, so we fetch all of them and match.
|
||||
export const GET_SHOP_POLICIES_QUERY = gql(`
|
||||
query GetShopPolicies {
|
||||
shop {
|
||||
privacyPolicy {
|
||||
id
|
||||
title
|
||||
handle
|
||||
body
|
||||
url
|
||||
}
|
||||
termsOfService {
|
||||
id
|
||||
title
|
||||
handle
|
||||
body
|
||||
url
|
||||
}
|
||||
refundPolicy {
|
||||
id
|
||||
title
|
||||
handle
|
||||
body
|
||||
url
|
||||
}
|
||||
shippingPolicy {
|
||||
id
|
||||
title
|
||||
handle
|
||||
body
|
||||
url
|
||||
}
|
||||
subscriptionPolicy {
|
||||
id
|
||||
title
|
||||
handle
|
||||
body
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
@@ -0,0 +1,150 @@
|
||||
import { gql } from '@shopify/hydrogen';
|
||||
|
||||
// Product Fragment for consistent product data
|
||||
export const ProductFragment = gql(`
|
||||
fragment ProductFragment on Product {
|
||||
id
|
||||
title
|
||||
handle
|
||||
description
|
||||
descriptionHtml
|
||||
vendor
|
||||
productType
|
||||
tags
|
||||
availableForSale
|
||||
priceRange {
|
||||
minVariantPrice {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
maxVariantPrice {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
}
|
||||
compareAtPriceRange {
|
||||
minVariantPrice {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
maxVariantPrice {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
}
|
||||
images(first: 10) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
url
|
||||
altText
|
||||
width
|
||||
height
|
||||
}
|
||||
}
|
||||
}
|
||||
variants(first: 100) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
title
|
||||
availableForSale
|
||||
quantityAvailable
|
||||
selectedOptions {
|
||||
name
|
||||
value
|
||||
}
|
||||
price {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
compareAtPrice {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
image {
|
||||
id
|
||||
url
|
||||
altText
|
||||
width
|
||||
height
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
options {
|
||||
id
|
||||
name
|
||||
values
|
||||
optionValues {
|
||||
id
|
||||
name
|
||||
swatch {
|
||||
color
|
||||
image {
|
||||
previewImage {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
firstSelectableVariant {
|
||||
id
|
||||
image {
|
||||
id
|
||||
url
|
||||
altText
|
||||
width
|
||||
height
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
// Get multiple products
|
||||
export const GET_PRODUCTS_QUERY = gql(
|
||||
`
|
||||
query GetProducts($first: Int!, $after: String, $query: String, $sortKey: ProductSortKeys, $reverse: Boolean, $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
products(first: $first, after: $after, query: $query, sortKey: $sortKey, reverse: $reverse) {
|
||||
edges {
|
||||
node {
|
||||
...ProductFragment
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[ProductFragment]
|
||||
);
|
||||
|
||||
// Get a single product by handle
|
||||
export const GET_PRODUCT_QUERY = gql(
|
||||
`
|
||||
query GetProduct($handle: String!, $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
product(handle: $handle) {
|
||||
...ProductFragment
|
||||
}
|
||||
}
|
||||
`,
|
||||
[ProductFragment]
|
||||
);
|
||||
|
||||
// Get product recommendations
|
||||
export const QUERY_PRODUCT_RECOMMENDATIONS = gql(
|
||||
`
|
||||
query GetProductRecommendations($productId: ID!, $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
productRecommendations(productId: $productId) {
|
||||
...ProductFragment
|
||||
}
|
||||
}
|
||||
`,
|
||||
[ProductFragment]
|
||||
);
|
||||
@@ -0,0 +1,89 @@
|
||||
import { gql } from '@shopify/hydrogen';
|
||||
import { ProductFragment } from '@/graphql/products';
|
||||
|
||||
// Storefront search over products. `productFilters` accepts the raw `input`
|
||||
// values returned in `productFilters[].values[].input`, so facets round-trip
|
||||
// without the client needing to know each filter's shape.
|
||||
export const SEARCH_PRODUCTS_QUERY = gql(
|
||||
`
|
||||
query SearchProducts(
|
||||
$query: String!
|
||||
$first: Int!
|
||||
$after: String
|
||||
$sortKey: SearchSortKeys
|
||||
$reverse: Boolean
|
||||
$productFilters: [ProductFilter!]
|
||||
$country: CountryCode
|
||||
$language: LanguageCode
|
||||
) @inContext(country: $country, language: $language) {
|
||||
search(
|
||||
query: $query
|
||||
first: $first
|
||||
after: $after
|
||||
types: PRODUCT
|
||||
sortKey: $sortKey
|
||||
reverse: $reverse
|
||||
productFilters: $productFilters
|
||||
) {
|
||||
totalCount
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
productFilters {
|
||||
id
|
||||
label
|
||||
type
|
||||
values {
|
||||
id
|
||||
label
|
||||
count
|
||||
input
|
||||
}
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
# types: PRODUCT already narrows the results, but the schema still
|
||||
# types nodes as a union — __typename lets callers narrow too.
|
||||
__typename
|
||||
... on Product {
|
||||
...ProductFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[ProductFragment]
|
||||
);
|
||||
|
||||
// Lightweight variant for the autocomplete dropdown — just enough to render a
|
||||
// row, so the dialog stays responsive while typing.
|
||||
export const SEARCH_SUGGESTIONS_QUERY = gql(`
|
||||
query SearchSuggestions($query: String!, $first: Int!, $country: CountryCode, $language: LanguageCode)
|
||||
@inContext(country: $country, language: $language) {
|
||||
search(query: $query, first: $first, types: PRODUCT) {
|
||||
totalCount
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
... on Product {
|
||||
id
|
||||
title
|
||||
handle
|
||||
featuredImage {
|
||||
url
|
||||
altText
|
||||
}
|
||||
priceRange {
|
||||
minVariantPrice {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
Reference in New Issue
Block a user