Compare commits
1 commit
main
...
cathryn/pr
Author | SHA1 | Date | |
---|---|---|---|
4427c87ee8 |
|
@ -1,6 +1,6 @@
|
|||
export default {
|
||||
locale: 'en-us',
|
||||
storeDomain: 'hydrogen-preview.myshopify.com',
|
||||
storefrontToken: '3b580e70970c4528da70c98e097c2fa0',
|
||||
storeDomain: 'react-advanced-hydrogen.myshopify.com',
|
||||
storefrontToken: '267baac86464f30e5a6cd11451406690',
|
||||
graphqlApiVersion: 'unstable',
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ import gql from 'graphql-tag';
|
|||
|
||||
import Layout from './Layout.server';
|
||||
import Button from './Button.client';
|
||||
import ProductCard from './ProductCard.server';
|
||||
import ProductCard from './ProductCard';
|
||||
|
||||
function NotFoundHero() {
|
||||
return (
|
||||
|
@ -68,6 +68,7 @@ export default function NotFound({country = {isoCode: 'US'}}) {
|
|||
const QUERY = gql`
|
||||
query NotFoundProductDetails(
|
||||
$country: CountryCode
|
||||
$includeReferenceMetafieldDetails: Boolean = false
|
||||
$numProductMetafields: Int!
|
||||
$numProductVariants: Int!
|
||||
$numProductMedia: Int!
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
BUTTON_PRIMARY_CLASSES,
|
||||
BUTTON_SECONDARY_CLASSES,
|
||||
} from './Button.client';
|
||||
import ProductCard from './ProductCard';
|
||||
|
||||
function ProductPriceMarkup() {
|
||||
return (
|
||||
|
@ -104,9 +105,57 @@ function SizeChart() {
|
|||
);
|
||||
}
|
||||
|
||||
function RecommendedProducts() {
|
||||
const {metafields} = useProduct();
|
||||
const recommendedProducts = metafields.filter((metafield) =>
|
||||
metafield.key.includes('recommended_product'),
|
||||
);
|
||||
|
||||
if (recommendedProducts.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-10 col-span-3">
|
||||
<h3 className="text-2xl font-bold text-center mb-6">
|
||||
You might also like...
|
||||
</h3>
|
||||
<div className="grid grid-cols-3 gap-6">
|
||||
<Product.Metafield
|
||||
keyName="recommended_product_1"
|
||||
namespace="my_fields"
|
||||
>
|
||||
{(metafield) => {
|
||||
return <ProductCard product={metafield.reference} />;
|
||||
}}
|
||||
</Product.Metafield>
|
||||
<Product.Metafield
|
||||
keyName="recommended_product_2"
|
||||
namespace="my_fields"
|
||||
>
|
||||
{/* eslint-disable-next-line @shopify/jsx-prefer-fragment-wrappers */}
|
||||
<div>
|
||||
<Product.Title />
|
||||
<Product.SelectedVariant.Image />
|
||||
<Product.SelectedVariant.Price priceType="compareAt" />
|
||||
<Product.SelectedVariant.Price />
|
||||
</div>
|
||||
</Product.Metafield>
|
||||
<Product.Metafield
|
||||
keyName="recommended_product_3"
|
||||
namespace="my_fields"
|
||||
>
|
||||
{(metafield) => {
|
||||
return <ProductCard product={metafield.reference} />;
|
||||
}}
|
||||
</Product.Metafield>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function ProductDetails({product}) {
|
||||
const initialVariant = flattenConnection(product.variants)[0];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Seo product={product} />
|
||||
|
@ -230,6 +279,7 @@ export default function ProductDetails({product}) {
|
|||
}}
|
||||
</Product.Metafield>
|
||||
</div>
|
||||
<RecommendedProducts />
|
||||
</div>
|
||||
</Product>
|
||||
</>
|
||||
|
|
|
@ -9,7 +9,7 @@ import gql from 'graphql-tag';
|
|||
import {Link} from '../components/Link.client';
|
||||
import Layout from '../components/Layout.server';
|
||||
import FeaturedCollection from '../components/FeaturedCollection.server';
|
||||
import ProductCard from '../components/ProductCard.server';
|
||||
import ProductCard from '../components/ProductCard';
|
||||
import Welcome from '../components/Welcome.server';
|
||||
|
||||
function GradientBackground() {
|
||||
|
@ -132,6 +132,7 @@ const QUERY = gql`
|
|||
$country: CountryCode
|
||||
$numCollections: Int = 2
|
||||
$numProducts: Int = 3
|
||||
$includeReferenceMetafieldDetails: Boolean = false
|
||||
$numProductMetafields: Int = 0
|
||||
$numProductVariants: Int = 250
|
||||
$numProductMedia: Int = 1
|
||||
|
|
|
@ -10,7 +10,7 @@ import gql from 'graphql-tag';
|
|||
|
||||
import LoadMoreProducts from '../../components/LoadMoreProducts.client';
|
||||
import Layout from '../../components/Layout.server';
|
||||
import ProductCard from '../../components/ProductCard.server';
|
||||
import ProductCard from '../../components/ProductCard';
|
||||
import NotFound from '../../components/NotFound.server';
|
||||
|
||||
export default function Collection({
|
||||
|
@ -65,6 +65,7 @@ const QUERY = gql`
|
|||
$handle: String!
|
||||
$country: CountryCode
|
||||
$numProducts: Int!
|
||||
$includeReferenceMetafieldDetails: Boolean = false
|
||||
$numProductMetafields: Int = 0
|
||||
$numProductVariants: Int = 250
|
||||
$numProductMedia: Int = 6
|
||||
|
|
|
@ -32,6 +32,7 @@ const QUERY = gql`
|
|||
query product(
|
||||
$country: CountryCode
|
||||
$handle: String!
|
||||
$includeReferenceMetafieldDetails: Boolean = true
|
||||
$numProductMetafields: Int = 20
|
||||
$numProductVariants: Int = 250
|
||||
$numProductMedia: Int = 6
|
||||
|
|
|
@ -6,12 +6,13 @@ import {StarRating} from './components/StarRating';
|
|||
import {RawHtml} from '../RawHtml';
|
||||
import {ParsedMetafield, Measurement, Rating} from '../../types';
|
||||
import {MetafieldFragment as Fragment} from '../../graphql/graphql-constants';
|
||||
import {ProductProvider, Product} from '../ProductProvider';
|
||||
|
||||
export interface MetafieldProps {
|
||||
/** A [Metafield object](/api/storefront/reference/common-objects/metafield) from the Storefront API. */
|
||||
metafield: ParsedMetafield;
|
||||
/** A render function that takes a `Metafield` object as an argument. Refer to [Render props](#render-props). */
|
||||
children?: (value: ParsedMetafield) => ReactElement;
|
||||
/** A React Element, or a render function that takes a `Metafield` object as an argument. Refer to [Render props](#render-props). */
|
||||
children?: ReactElement | ((value: ParsedMetafield) => ReactElement);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,6 +104,19 @@ export function Metafield<TTag extends ElementType>(
|
|||
{JSON.stringify(metafield.value)}
|
||||
</Wrapper>
|
||||
);
|
||||
case 'product_reference': {
|
||||
if (metafield.reference != null) {
|
||||
const product = metafield.reference as Product;
|
||||
return (
|
||||
<ProductProvider
|
||||
product={product}
|
||||
initialVariantId={product?.variants?.edges?.[0]?.node.id ?? ''}
|
||||
>
|
||||
{children}
|
||||
</ProductProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
const Wrapper = as ?? 'span';
|
||||
return (
|
||||
|
|
|
@ -4,7 +4,50 @@ fragment MetafieldFragment on Metafield {
|
|||
namespace
|
||||
key
|
||||
value
|
||||
createdAt
|
||||
updatedAt
|
||||
description
|
||||
reference @include(if: $includeReferenceMetafieldDetails){
|
||||
... on Product {
|
||||
handle
|
||||
id
|
||||
title
|
||||
compareAtPriceRange {
|
||||
maxVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
minVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
}
|
||||
priceRange {
|
||||
maxVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
minVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
}
|
||||
variants (first: 1) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
title
|
||||
availableForSale
|
||||
image {
|
||||
...ImageFragment
|
||||
}
|
||||
priceV2 {
|
||||
...MoneyFragment
|
||||
}
|
||||
compareAtPriceV2 {
|
||||
...MoneyFragment
|
||||
}
|
||||
selectedOptions {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,54 @@
|
|||
import * as Types from '../../graphql/types/types';
|
||||
|
||||
import {MoneyFragmentFragment} from '../Money/MoneyFragment';
|
||||
import {ImageFragmentFragment} from '../Image/ImageFragment';
|
||||
export type MetafieldFragmentFragment = {__typename?: 'Metafield'} & Pick<
|
||||
Types.Metafield,
|
||||
| 'id'
|
||||
| 'type'
|
||||
| 'namespace'
|
||||
| 'key'
|
||||
| 'value'
|
||||
| 'createdAt'
|
||||
| 'updatedAt'
|
||||
| 'description'
|
||||
>;
|
||||
'id' | 'type' | 'namespace' | 'key' | 'value' | 'description'
|
||||
> & {
|
||||
reference?: Types.Maybe<
|
||||
| ({__typename?: 'MediaImage'} & Pick<
|
||||
Types.MediaImage,
|
||||
'id' | 'mediaContentType'
|
||||
>)
|
||||
| ({__typename?: 'Page'} & Pick<Types.Page, 'id'>)
|
||||
| ({__typename?: 'Product'} & Pick<
|
||||
Types.Product,
|
||||
'handle' | 'id' | 'title'
|
||||
> & {
|
||||
compareAtPriceRange: {__typename?: 'ProductPriceRange'} & {
|
||||
maxVariantPrice: {__typename?: 'MoneyV2'} & MoneyFragmentFragment;
|
||||
minVariantPrice: {__typename?: 'MoneyV2'} & MoneyFragmentFragment;
|
||||
};
|
||||
priceRange: {__typename?: 'ProductPriceRange'} & {
|
||||
maxVariantPrice: {__typename?: 'MoneyV2'} & MoneyFragmentFragment;
|
||||
minVariantPrice: {__typename?: 'MoneyV2'} & MoneyFragmentFragment;
|
||||
};
|
||||
variants: {__typename?: 'ProductVariantConnection'} & {
|
||||
edges: Array<
|
||||
{__typename?: 'ProductVariantEdge'} & {
|
||||
node: {__typename?: 'ProductVariant'} & Pick<
|
||||
Types.ProductVariant,
|
||||
'id' | 'title' | 'availableForSale'
|
||||
> & {
|
||||
image?: Types.Maybe<
|
||||
{__typename?: 'Image'} & ImageFragmentFragment
|
||||
>;
|
||||
priceV2: {__typename?: 'MoneyV2'} & MoneyFragmentFragment;
|
||||
compareAtPriceV2?: Types.Maybe<
|
||||
{__typename?: 'MoneyV2'} & MoneyFragmentFragment
|
||||
>;
|
||||
selectedOptions: Array<
|
||||
{__typename?: 'SelectedOption'} & Pick<
|
||||
Types.SelectedOption,
|
||||
'name' | 'value'
|
||||
>
|
||||
>;
|
||||
};
|
||||
}
|
||||
>;
|
||||
};
|
||||
})
|
||||
| ({__typename?: 'ProductVariant'} & Pick<Types.ProductVariant, 'id'>)
|
||||
>;
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ When no `children` prop is provided, the `Metafield` component renders the follo
|
|||
| `color` | A `span` containing the color value as a string. |
|
||||
| `single_line_text_field` | A `RawHtml` component with the text. |
|
||||
| `multi_line_text_field` | A `RawHtml` component with the text. |
|
||||
| `product_reference` | A `span` containing the product reference GID. |
|
||||
| `product_reference` | A `span` containing the product reference GID when the `reference` field is undefined, or a `ProductProvider` component using the `reference` data. details. |
|
||||
| `file_reference` | A `span` containing the file reference GID. |
|
||||
| `page_reference` | A `span` containing the page reference GID. |
|
||||
| `variant_reference` | A `span` containing the variant reference GID. |
|
||||
|
|
|
@ -9,8 +9,6 @@ fragment MetafieldFragment on Metafield {
|
|||
namespace
|
||||
key
|
||||
value
|
||||
createdAt
|
||||
updatedAt
|
||||
description
|
||||
}
|
||||
```
|
||||
|
|
|
@ -4,6 +4,7 @@ import {getParsedMetafield} from '../../../utilities/tests/metafields';
|
|||
import {mountWithShopifyProvider} from '../../../utilities/tests/shopify_provider';
|
||||
import {RawHtml} from '../../RawHtml';
|
||||
import {StarRating} from '../components';
|
||||
import {ProductProvider} from '../../ProductProvider';
|
||||
|
||||
describe('<Metafield />', () => {
|
||||
it('renders nothing when the metafield value is undefined', () => {
|
||||
|
@ -735,68 +736,119 @@ describe('<Metafield />', () => {
|
|||
});
|
||||
|
||||
describe('with `product_reference` type metafield', () => {
|
||||
it('renders the product reference as a string in a `span` by default', () => {
|
||||
const metafield = getParsedMetafield({type: 'product_reference'});
|
||||
const component = mountWithShopifyProvider(
|
||||
<Metafield metafield={metafield} />
|
||||
);
|
||||
describe('when `reference` is undefined', () => {
|
||||
it('renders the value as a string in a `span` by default', () => {
|
||||
const metafield = getParsedMetafield({
|
||||
type: 'product_reference',
|
||||
reference: undefined,
|
||||
});
|
||||
const component = mountWithShopifyProvider(
|
||||
<Metafield metafield={metafield} />
|
||||
);
|
||||
|
||||
expect(component).toContainReactComponent('span', {
|
||||
children: metafield.value,
|
||||
expect(component).toContainReactComponent('span', {
|
||||
children: metafield.value,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the value as a string in the element specified by the `as` prop', () => {
|
||||
const metafield = getParsedMetafield({
|
||||
type: 'product_reference',
|
||||
reference: undefined,
|
||||
});
|
||||
const component = mountWithShopifyProvider(
|
||||
<Metafield metafield={metafield} as="p" />
|
||||
);
|
||||
|
||||
expect(component).toContainReactComponent('p', {
|
||||
children: metafield.value,
|
||||
});
|
||||
});
|
||||
|
||||
it('passes the metafield as a render prop to the children render function', () => {
|
||||
const children = jest.fn().mockImplementation(() => {
|
||||
return null;
|
||||
});
|
||||
const metafield = getParsedMetafield({
|
||||
type: 'product_reference',
|
||||
reference: undefined,
|
||||
});
|
||||
|
||||
mountWithShopifyProvider(
|
||||
<Metafield metafield={metafield}>{children}</Metafield>
|
||||
);
|
||||
|
||||
expect(children).toHaveBeenCalledWith({
|
||||
...metafield,
|
||||
value: metafield.value,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders its children', () => {
|
||||
const metafield = getParsedMetafield({
|
||||
type: 'product_reference',
|
||||
reference: undefined,
|
||||
});
|
||||
const component = mountWithShopifyProvider(
|
||||
<Metafield metafield={metafield}>
|
||||
{({value}) => {
|
||||
return <p>The reference is {value}</p>;
|
||||
}}
|
||||
</Metafield>
|
||||
);
|
||||
|
||||
expect(component).toContainReactComponent('p', {
|
||||
children: [`The reference is `, metafield.value],
|
||||
});
|
||||
});
|
||||
|
||||
it('allows passthrough props', () => {
|
||||
const component = mountWithShopifyProvider(
|
||||
<Metafield
|
||||
metafield={getParsedMetafield({
|
||||
type: 'product_reference',
|
||||
reference: undefined,
|
||||
})}
|
||||
className="emphasized"
|
||||
/>
|
||||
);
|
||||
expect(component).toContainReactComponent('span', {
|
||||
className: 'emphasized',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the product reference as a string in the element specified by the `as` prop', () => {
|
||||
const metafield = getParsedMetafield({type: 'product_reference'});
|
||||
const component = mountWithShopifyProvider(
|
||||
<Metafield metafield={metafield} as="p" />
|
||||
);
|
||||
describe('when `reference` is not undefined', () => {
|
||||
it('renders a `ProductProvider` with its children by default', () => {
|
||||
const metafield = getParsedMetafield({type: 'product_reference'});
|
||||
function Children() {
|
||||
return null;
|
||||
}
|
||||
const component = mountWithShopifyProvider(
|
||||
<Metafield metafield={metafield}>
|
||||
<Children />
|
||||
</Metafield>
|
||||
);
|
||||
|
||||
expect(component).toContainReactComponent('p', {
|
||||
children: metafield.value,
|
||||
expect(component).toContainReactComponent(ProductProvider, {
|
||||
children: <Children />,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('passes the metafield as a render prop to the children render function', () => {
|
||||
const children = jest.fn().mockImplementation(() => {
|
||||
return null;
|
||||
});
|
||||
const metafield = getParsedMetafield({type: 'product_reference'});
|
||||
it('passes the metafield as a render prop to the children render function', () => {
|
||||
const children = jest.fn().mockImplementation(() => {
|
||||
return null;
|
||||
});
|
||||
const metafield = getParsedMetafield({type: 'product_reference'});
|
||||
|
||||
mountWithShopifyProvider(
|
||||
<Metafield metafield={metafield}>{children}</Metafield>
|
||||
);
|
||||
mountWithShopifyProvider(
|
||||
<Metafield metafield={metafield}>{children}</Metafield>
|
||||
);
|
||||
|
||||
expect(children).toHaveBeenCalledWith({
|
||||
...metafield,
|
||||
value: metafield.value,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders its children', () => {
|
||||
const metafield = getParsedMetafield({type: 'product_reference'});
|
||||
const component = mountWithShopifyProvider(
|
||||
<Metafield metafield={metafield}>
|
||||
{({value}) => {
|
||||
return <p>The reference is {value}</p>;
|
||||
}}
|
||||
</Metafield>
|
||||
);
|
||||
|
||||
expect(component).toContainReactComponent('p', {
|
||||
children: [`The reference is `, metafield.value],
|
||||
});
|
||||
});
|
||||
|
||||
it('allows passthrough props', () => {
|
||||
const component = mountWithShopifyProvider(
|
||||
<Metafield
|
||||
metafield={getParsedMetafield({type: 'product_reference'})}
|
||||
className="emphasized"
|
||||
/>
|
||||
);
|
||||
expect(component).toContainReactComponent('span', {
|
||||
className: 'emphasized',
|
||||
expect(children).toHaveBeenCalledWith({
|
||||
...metafield,
|
||||
value: metafield.value,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {createContext} from 'react';
|
||||
import {ProductOptionsHookValue} from '../../hooks';
|
||||
import {GraphQLConnection, ParsedMetafield} from '../../types';
|
||||
import {GraphQLConnection, ParsedMetafield, RawMetafield} from '../../types';
|
||||
import {ProductProviderFragmentFragment} from './ProductProviderFragment';
|
||||
import {Product} from './types';
|
||||
import {Collection, Image} from '../../graphql/types/types';
|
||||
|
@ -21,7 +21,7 @@ export type ProductContextType = Omit<
|
|||
media?: ProductProviderFragmentFragment['media']['edges'][0]['node'][];
|
||||
mediaConnection?: ProductProviderFragmentFragment['media'];
|
||||
metafields?: ParsedMetafield[];
|
||||
metafieldsConnection?: ProductProviderFragmentFragment['metafields'];
|
||||
metafieldsConnection?: GraphQLConnection<RawMetafield>;
|
||||
images?: Partial<Image>[];
|
||||
imagesConnection?: GraphQLConnection<Partial<Image>>;
|
||||
collections?: Partial<Collection>[];
|
||||
|
|
|
@ -3,3 +3,4 @@ export {
|
|||
ProductProviderFragment,
|
||||
} from './ProductProvider.client';
|
||||
export {useProduct} from '../../hooks/useProduct/useProduct';
|
||||
export type {Product} from './types';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {SellingPlanGroup, Variant} from '../../hooks/useProductOptions';
|
||||
import {GraphQLConnection} from '../../types';
|
||||
import {GraphQLConnection, RawMetafield} from '../../types';
|
||||
import {ProductProviderFragmentFragment} from './ProductProviderFragment';
|
||||
import {ImageFragmentFragment} from '../Image/ImageFragment';
|
||||
import {Collection} from '../../graphql/types/types';
|
||||
|
@ -12,7 +12,7 @@ export interface Product {
|
|||
handle?: ProductProviderFragmentFragment['descriptionHtml'];
|
||||
id?: ProductProviderFragmentFragment['id'];
|
||||
media?: ProductProviderFragmentFragment['media'];
|
||||
metafields?: ProductProviderFragmentFragment['metafields'];
|
||||
metafields?: GraphQLConnection<RawMetafield>;
|
||||
priceRange?: Partial<ProductProviderFragmentFragment['priceRange']>;
|
||||
title?: ProductProviderFragmentFragment['title'];
|
||||
variants?: GraphQLConnection<Variant>;
|
||||
|
|
|
@ -2194,9 +2194,62 @@ fragment Model3DFragment on Model3d {
|
|||
* namespace
|
||||
* key
|
||||
* value
|
||||
* createdAt
|
||||
* updatedAt
|
||||
* description
|
||||
* reference @include(if: $includeReferenceMetafieldDetails){
|
||||
* ... on Product {
|
||||
* handle
|
||||
* id
|
||||
* title
|
||||
* compareAtPriceRange {
|
||||
* maxVariantPrice {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* minVariantPrice {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* }
|
||||
* priceRange {
|
||||
* maxVariantPrice {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* minVariantPrice {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* }
|
||||
* variants (first: 1) {
|
||||
* edges {
|
||||
* node {
|
||||
* id
|
||||
* title
|
||||
* availableForSale
|
||||
* image {
|
||||
* ...ImageFragment
|
||||
* }
|
||||
* priceV2 {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* compareAtPriceV2 {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* selectedOptions {
|
||||
* name
|
||||
* value
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ... on MediaImage {
|
||||
* id
|
||||
* mediaContentType
|
||||
* }
|
||||
* ... on ProductVariant {
|
||||
* id
|
||||
* }
|
||||
* ... on Page {
|
||||
* id
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
|
||||
*```
|
||||
|
@ -2207,9 +2260,62 @@ export const MetafieldFragment: string = `fragment MetafieldFragment on Metafiel
|
|||
namespace
|
||||
key
|
||||
value
|
||||
createdAt
|
||||
updatedAt
|
||||
description
|
||||
reference @include(if: $includeReferenceMetafieldDetails){
|
||||
... on Product {
|
||||
handle
|
||||
id
|
||||
title
|
||||
compareAtPriceRange {
|
||||
maxVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
minVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
}
|
||||
priceRange {
|
||||
maxVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
minVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
}
|
||||
variants (first: 1) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
title
|
||||
availableForSale
|
||||
image {
|
||||
...ImageFragment
|
||||
}
|
||||
priceV2 {
|
||||
...MoneyFragment
|
||||
}
|
||||
compareAtPriceV2 {
|
||||
...MoneyFragment
|
||||
}
|
||||
selectedOptions {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on MediaImage {
|
||||
id
|
||||
mediaContentType
|
||||
}
|
||||
... on ProductVariant {
|
||||
id
|
||||
}
|
||||
... on Page {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -2341,9 +2447,62 @@ export const MoneyFragment: string = `fragment MoneyFragment on MoneyV2 {
|
|||
* namespace
|
||||
* key
|
||||
* value
|
||||
* createdAt
|
||||
* updatedAt
|
||||
* description
|
||||
* reference @include(if: $includeReferenceMetafieldDetails){
|
||||
* ... on Product {
|
||||
* handle
|
||||
* id
|
||||
* title
|
||||
* compareAtPriceRange {
|
||||
* maxVariantPrice {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* minVariantPrice {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* }
|
||||
* priceRange {
|
||||
* maxVariantPrice {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* minVariantPrice {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* }
|
||||
* variants (first: 1) {
|
||||
* edges {
|
||||
* node {
|
||||
* id
|
||||
* title
|
||||
* availableForSale
|
||||
* image {
|
||||
* ...ImageFragment
|
||||
* }
|
||||
* priceV2 {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* compareAtPriceV2 {
|
||||
* ...MoneyFragment
|
||||
* }
|
||||
* selectedOptions {
|
||||
* name
|
||||
* value
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ... on MediaImage {
|
||||
* id
|
||||
* mediaContentType
|
||||
* }
|
||||
* ... on ProductVariant {
|
||||
* id
|
||||
* }
|
||||
* ... on Page {
|
||||
* id
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* fragment VariantFragment on ProductVariant {
|
||||
|
@ -2630,9 +2789,62 @@ fragment MetafieldFragment on Metafield {
|
|||
namespace
|
||||
key
|
||||
value
|
||||
createdAt
|
||||
updatedAt
|
||||
description
|
||||
reference @include(if: $includeReferenceMetafieldDetails){
|
||||
... on Product {
|
||||
handle
|
||||
id
|
||||
title
|
||||
compareAtPriceRange {
|
||||
maxVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
minVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
}
|
||||
priceRange {
|
||||
maxVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
minVariantPrice {
|
||||
...MoneyFragment
|
||||
}
|
||||
}
|
||||
variants (first: 1) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
title
|
||||
availableForSale
|
||||
image {
|
||||
...ImageFragment
|
||||
}
|
||||
priceV2 {
|
||||
...MoneyFragment
|
||||
}
|
||||
compareAtPriceV2 {
|
||||
...MoneyFragment
|
||||
}
|
||||
selectedOptions {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on MediaImage {
|
||||
id
|
||||
mediaContentType
|
||||
}
|
||||
... on ProductVariant {
|
||||
id
|
||||
}
|
||||
... on Page {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment VariantFragment on ProductVariant {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import {useMemo} from 'react';
|
||||
import {GraphQLConnection, ParsedMetafield} from '../../types';
|
||||
import {Metafield} from '../../graphql/types/types';
|
||||
import {GraphQLConnection, ParsedMetafield, RawMetafield} from '../../types';
|
||||
import {flattenConnection, parseMetafieldValue} from '../../utilities';
|
||||
|
||||
/**
|
||||
|
@ -8,7 +7,7 @@ import {flattenConnection, parseMetafieldValue} from '../../utilities';
|
|||
* in an array of metafields whose `values` have been parsed according to the metafield `type`.
|
||||
*/
|
||||
export function useParsedMetafields(
|
||||
metafields: GraphQLConnection<Partial<Metafield>> | undefined
|
||||
metafields: GraphQLConnection<RawMetafield> | undefined
|
||||
): ParsedMetafield[] {
|
||||
return useMemo(() => {
|
||||
if (metafields == null) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type {ServerResponse} from 'http';
|
||||
import type {ServerComponentResponse} from './framework/Hydration/ServerComponentResponse.server';
|
||||
import type {ServerComponentRequest} from './framework/Hydration/ServerComponentRequest.server';
|
||||
import type {Metafield} from './graphql/types/types';
|
||||
import type {Metafield, Product} from './graphql/types/types';
|
||||
|
||||
export type Renderer = (
|
||||
url: URL,
|
||||
|
@ -71,8 +71,14 @@ export interface GraphQLConnection<T> {
|
|||
edges?: {node: T}[];
|
||||
}
|
||||
|
||||
export type RawMetafield = Partial<Metafield>;
|
||||
export type ParsedMetafield = Omit<Partial<Metafield>, 'value'> & {
|
||||
export type RawMetafield = Omit<Partial<Metafield>, 'reference'> & {
|
||||
reference?: Product;
|
||||
};
|
||||
|
||||
export type ParsedMetafield = Omit<
|
||||
Partial<Metafield>,
|
||||
'value' | 'reference'
|
||||
> & {
|
||||
value?:
|
||||
| string
|
||||
| number
|
||||
|
@ -81,6 +87,7 @@ export type ParsedMetafield = Omit<Partial<Metafield>, 'value'> & {
|
|||
| Date
|
||||
| Rating
|
||||
| Measurement;
|
||||
reference?: Partial<Product>;
|
||||
};
|
||||
|
||||
export interface Rating {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import faker from 'faker';
|
||||
import {Metafield} from '../../graphql/types/types';
|
||||
import {ParsedMetafield, Rating, RawMetafield} from '../../types';
|
||||
import {getProduct} from './product';
|
||||
|
||||
export type MetafieldType =
|
||||
| 'single_line_text_field'
|
||||
|
@ -46,7 +47,7 @@ export const METAFIELDS: MetafieldType[] = [
|
|||
|
||||
export function getRawMetafield(
|
||||
metafield: Partial<Metafield> & {type?: MetafieldType} = {}
|
||||
): Omit<Metafield, 'parentResource' | 'valueType'> {
|
||||
): RawMetafield {
|
||||
const type: MetafieldType =
|
||||
metafield.type == null
|
||||
? faker.random.arrayElement(METAFIELDS)
|
||||
|
@ -62,6 +63,9 @@ export function getRawMetafield(
|
|||
type,
|
||||
updatedAt: metafield.updatedAt ?? faker.date.recent(),
|
||||
value: metafield.value ?? getMetafieldValue(type),
|
||||
reference: Object.keys(metafield).includes('reference')
|
||||
? metafield.reference
|
||||
: (getProduct({metafields: {edges: []}, variants: {edges: []}}) as any),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -167,6 +171,8 @@ export function getParsedMetafield(
|
|||
case 'single_line_text_field':
|
||||
case 'multi_line_text_field':
|
||||
case 'product_reference':
|
||||
field.value = rawField.value;
|
||||
break;
|
||||
case 'page_reference':
|
||||
case 'variant_reference':
|
||||
case 'file_reference':
|
||||
|
|
Loading…
Reference in a new issue