Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Product provider work #1397

Merged
merged 18 commits into from
Jun 7, 2022
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/good-coats-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@shopify/hydrogen': minor
---

## `<ProductProvider/>` and `<ProductOptionsProvider/>`

- `<ProductProvider/>` has been removed
- `<ProductPrice/>` was the only component left that used it; now it requires a `data` prop that takes in the product object
- `<ProductOptionsProvider/>` now maintains and provides the state that `useProductOptions` used to keep track of by itself. This change enables you to use multiple `useProductOptions` hook calls and have them share the same state (such as selected variant, options, etc.)
300 changes: 300 additions & 0 deletions docs/components/product-variant/productoptionsprovider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
---
gid: 80d51c7e-fafe-11eb-9a03-0242ac130003
title: ProductOptionsProvider
description: The ProductOptionsProvider component sets up a context with state that tracks the selected variant and options.
---

The `ProductOptionsProvider` component sets up a context with state that tracks the selected variant and options. Descendents of this component can use the [`useProductOptions`](https://shopify.dev/api/hydrogen/hooks/product-variant/useproductoptions) hook.

## Example code

```tsx
import {ProductOptionsProvider, gql} from '@shopify/hydrogen';

const QUERY = gql`
query product($handle: String!) {
product: product(handle: $handle) {
compareAtPriceRange {
maxVariantPrice {
currencyCode
amount
}
minVariantPrice {
currencyCode
amount
}
}
descriptionHtml
handle
id
media(first: $numProductMedia) {
nodes {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This query can be improved via … 

 fragment MediaFields on Media {
    mediaContentType
    alt
    previewImage {
      url
    }
    ... on MediaImage {
      id
      image {
        url
        width
        height
      }
    }
    ... on Video {
      id
      sources {
        mimeType
        url
      }
    }
    ... on Model3d {
      id
      sources {
        mimeType
        url
      }
    }
    ... on ExternalVideo {
      id
      embedUrl
      host
    }
  }

Sadly the id can't actually be pulled up to the top.

... on MediaImage {
mediaContentType
image {
id
url
altText
width
height
}
}
... on Video {
mediaContentType
id
previewImage {
url
}
sources {
mimeType
url
}
}
... on ExternalVideo {
mediaContentType
id
embedUrl
host
}
... on Model3d {
mediaContentType
id
alt
mediaContentType
previewImage {
url
}
sources {
url
}
}
}
}
metafields(first: $numProductMetafields) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metafields as an array will need to be removed. Our API no longer supports this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup that work is coming up. This was just a copy/paste from previous file.

nodes {
id
type
namespace
key
value
createdAt
updatedAt
description
reference @include(if: $includeReferenceMetafieldDetails) {
__typename
... on MediaImage {
id
mediaContentType
image {
id
url
altText
width
height
}
}
}
}
}
priceRange {
maxVariantPrice {
currencyCode
amount
}
minVariantPrice {
currencyCode
amount
}
}
title
variants(first: $numProductVariants) {
nodes {
id
title
availableForSale
image {
id
url
altText
width
height
}
unitPriceMeasurement {
measuredType
quantityUnit
quantityValue
referenceUnit
referenceValue
}
unitPrice {
currencyCode
amount
}
priceV2 {
currencyCode
amount
}
compareAtPriceV2 {
currencyCode
amount
}
selectedOptions {
name
value
}
metafields(first: $numProductVariantMetafields) {
nodes {
id
type
namespace
key
value
createdAt
updatedAt
description
reference @include(if: $includeReferenceMetafieldDetails) {
__typename
... on MediaImage {
id
mediaContentType
image {
id
url
altText
width
height
}
}
}
}
}
sellingPlanAllocations(
first: $numProductVariantSellingPlanAllocations
) {
nodes {
priceAdjustments {
compareAtPrice {
currencyCode
amount
}
perDeliveryPrice {
currencyCode
amount
}
price {
currencyCode
amount
}
unitPrice {
currencyCode
amount
}
}
sellingPlan {
id
description
name
options {
name
value
}
priceAdjustments {
orderCount
adjustmentValue {
... on SellingPlanFixedAmountPriceAdjustment {
adjustmentAmount {
currencyCode
amount
}
}
... on SellingPlanFixedPriceAdjustment {
price {
currencyCode
amount
}
}
... on SellingPlanPercentagePriceAdjustment {
adjustmentPercentage
}
}
}
recurringDeliveries
}
}
}
}
}
sellingPlanGroups(first: $numProductSellingPlanGroups) {
nodes {
sellingPlans(first: $numProductSellingPlans) {
nodes {
id
description
name
options {
name
value
}
priceAdjustments {
orderCount
adjustmentValue {
... on SellingPlanFixedAmountPriceAdjustment {
adjustmentAmount {
currencyCode
amount
}
}
... on SellingPlanFixedPriceAdjustment {
price {
currencyCode
amount
}
}
... on SellingPlanPercentagePriceAdjustment {
adjustmentPercentage
}
}
}
recurringDeliveries
}
}
appName
name
options {
name
values
}
}
}
}
}
`;

export function Product() {
const {data} = useShopQuery({query: QUERY});

return (
<ProductOptionsProvider data={data.product} initialVariantId="some-id">{/* Your JSX */}</ProductOptionsProvider>
);
}
```

## Props

| Name | Type | Description |
| ----------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| children | <code>ReactNode</code> | A `ReactNode` element. |
| data | <code>PartialDeep&#60;ProductType&#62;</code> | An object with fields that correspond to the Storefront API's [Product object](/api/storefront/reference/products/product). |
| initialVariantId? | <code>Parameters&#60;typeof useProductOption&#62;['0']['initialvariantid']</code> | The initially selected variant. <br></br>The following logic applies to `initialVariantId`:<ul><li>If `initialVariantId` is provided, then it's used, even if it's out of stock.</li><li>If `initialVariantId` is provided, but is `null`, then no variant is used.</li><li>If nothing is passed to `initialVariantId`, and you're in a `ProductOptionsProvider` component, then `selectedVariant.id` is used.</li><li>If nothing is passed to `initialVariantId` and you're not in a `ProductOptionsProvider` component, then the first available or in-stock variant is used.</li><li>If nothing is passed to `initialVariantId`, you're not in a `ProductOptionsProvider` component, and no variants are in stock, then the first variant is used.</li></ul> |

## Component type

The `ProductOptionsProvider` component is a client component, which means that it renders on the client. For more information about component types, refer to [React Server Components](https://shopify.dev/custom-storefronts/hydrogen/framework/react-server-components).

## Related components

- [`ProductPrice`](https://shopify.dev/api/hydrogen/components/product-variant/productprice)

## Related hooks

- [`useProductOptions`](https://shopify.dev/api/hydrogen/hooks/product-variant/useproductoptions)
12 changes: 5 additions & 7 deletions docs/components/product-variant/productprice.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,17 @@ title: ProductPrice
description: The ProductPrice component renders a Money component with the product priceRange's maxVariantPrice or minVariantPrice, for either the regular price or compare at price range.
---

The `ProductPrice` component renders a `Money` component with the product
[`priceRange`](https://shopify.dev/api/storefront/reference/products/productpricerange)'s `maxVariantPrice` or `minVariantPrice`, for either the regular price or compare at price range. It must be a descendent of the `ProductProvider` component.
The `ProductPrice` component renders a [`Money`](https://shopify.dev/api/hydrogen/components/primitive/money) component with the product
[`priceRange`](https://shopify.dev/api/storefront/reference/products/productpricerange)'s `maxVariantPrice` or `minVariantPrice`, for either the regular price or compare at price range.

## Example code

```tsx
import {ProductPrice, ProductProvider} from '@shopify/hydrogen';
import {ProductPrice} from '@shopify/hydrogen';

export function Product({product}) {
return (
<ProductProvider data={product}>
<ProductPrice priceType="compareAt" valueType="max" />
</ProductProvider>
<ProductPrice product={product} priceType="compareAt" valueType="max" />
);
}
```
frehner marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -35,5 +33,5 @@ The `ProductPrice` component is a client component, which means that it renders

## Related components

- [`ProductProvider`](https://shopify.dev/api/hydrogen/components/product-variant/productprovider)
- [`ProductOptionsProvider`](https://shopify.dev/api/hydrogen/components/product-variant/productoptionsprovider)
- [`Money`](https://shopify.dev/api/hydrogen/components/primitive/money)
Loading