From dff5d19bf48032d7db172c493585cefbbc7a278e Mon Sep 17 00:00:00 2001 From: Thomas Cristina de Carvalho Date: Thu, 7 Dec 2023 10:33:13 -0500 Subject: [PATCH] Add PriceBlock and VariantPrice --- .../app/components/blocks/PriceBlock.tsx | 32 +++++++++++++++++++ .../app/components/product/ProductDetails.tsx | 2 ++ .../app/components/product/ProductForm.tsx | 5 --- .../app/components/product/VariantPrice.tsx | 31 ++++++++++++++++++ templates/hydrogen-theme/app/qroq/blocks.ts | 5 +++ templates/hydrogen-theme/app/qroq/sections.ts | 2 ++ .../objects/global/productRichtext.tsx | 22 ++++++++++++- 7 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 templates/hydrogen-theme/app/components/blocks/PriceBlock.tsx create mode 100644 templates/hydrogen-theme/app/components/product/VariantPrice.tsx diff --git a/templates/hydrogen-theme/app/components/blocks/PriceBlock.tsx b/templates/hydrogen-theme/app/components/blocks/PriceBlock.tsx new file mode 100644 index 0000000..69c8c21 --- /dev/null +++ b/templates/hydrogen-theme/app/components/blocks/PriceBlock.tsx @@ -0,0 +1,32 @@ +import type {InferType} from 'groqd'; + +import {Await, useLoaderData} from '@remix-run/react'; +import {flattenConnection} from '@shopify/hydrogen-react'; +import {Suspense} from 'react'; + +import type {PRICE_BLOCK} from '~/qroq/blocks'; +import type {loader} from '~/routes/($locale).products.$productHandle'; + +import {VariantPrice} from '../product/VariantPrice'; + +export function PriceBlock(props: InferType) { + const loaderData = useLoaderData(); + const variantsPromise = loaderData.variants; + + return ( + <> + {/* Todo => Add skeleton and errorElement */} + + + {({product}) => { + const variants = product?.variants?.nodes.length + ? flattenConnection(product.variants) + : []; + + return ; + }} + + + + ); +} diff --git a/templates/hydrogen-theme/app/components/product/ProductDetails.tsx b/templates/hydrogen-theme/app/components/product/ProductDetails.tsx index 8e371bf..9a8bb2a 100644 --- a/templates/hydrogen-theme/app/components/product/ProductDetails.tsx +++ b/templates/hydrogen-theme/app/components/product/ProductDetails.tsx @@ -3,6 +3,7 @@ import {PortableText} from '@portabletext/react'; import type {ProductInformationSectionProps} from '../sections/ProductInformationSection'; import {AddToCartButtonBlock} from '../blocks/AddToCartButtonBlock'; +import {PriceBlock} from '../blocks/PriceBlock'; import {ShopifyDescriptionBlock} from '../blocks/ShopifyDescriptionBlock'; import {ShopifyTitleBlock} from '../blocks/ShopifyTitleBlock'; @@ -16,6 +17,7 @@ export function ProductDetails(props: {data: ProductInformationSectionProps}) { addToCartButton: ({value}) => { return ; }, + price: ({value}) => , shopifyDescription: ({value}) => ( ), diff --git a/templates/hydrogen-theme/app/components/product/ProductForm.tsx b/templates/hydrogen-theme/app/components/product/ProductForm.tsx index d7d56fe..a9e2088 100644 --- a/templates/hydrogen-theme/app/components/product/ProductForm.tsx +++ b/templates/hydrogen-theme/app/components/product/ProductForm.tsx @@ -26,11 +26,6 @@ export function ProductForm({ const selectedVariant = useSelectedVariant({variants}); const isOutOfStock = !selectedVariant?.availableForSale; - const isOnSale = - selectedVariant?.price?.amount && - selectedVariant?.compareAtPrice?.amount && - selectedVariant?.price?.amount < selectedVariant?.compareAtPrice?.amount; - return (
diff --git a/templates/hydrogen-theme/app/components/product/VariantPrice.tsx b/templates/hydrogen-theme/app/components/product/VariantPrice.tsx new file mode 100644 index 0000000..e4742b0 --- /dev/null +++ b/templates/hydrogen-theme/app/components/product/VariantPrice.tsx @@ -0,0 +1,31 @@ +import type {ProductVariantFragmentFragment} from 'storefrontapi.generated'; + +import {Money} from '@shopify/hydrogen-react'; + +import {useSelectedVariant} from '~/hooks/useSelectedVariant'; + +export function VariantPrice({ + variants, +}: { + variants: ProductVariantFragmentFragment[]; +}) { + const selectedVariant = useSelectedVariant({variants}); + const price = selectedVariant?.price; + const compareAtPrice = selectedVariant?.compareAtPrice; + const isOutOfStock = !selectedVariant?.availableForSale; + + const isOnSale = + selectedVariant?.price?.amount && + selectedVariant?.compareAtPrice?.amount && + selectedVariant?.price?.amount < selectedVariant?.compareAtPrice?.amount; + + // Todo => Add sale and sold out badges + return ( +
+ {compareAtPrice && ( + + )} + {price && } +
+ ); +} diff --git a/templates/hydrogen-theme/app/qroq/blocks.ts b/templates/hydrogen-theme/app/qroq/blocks.ts index 1524ed0..157629e 100644 --- a/templates/hydrogen-theme/app/qroq/blocks.ts +++ b/templates/hydrogen-theme/app/qroq/blocks.ts @@ -20,3 +20,8 @@ export const ADD_TO_CART_BUTTON_BLOCK = q.object({ _type: q.literal('addToCartButton'), size: z.enum(['small', 'medium', 'large']), }); + +export const PRICE_BLOCK = q.object({ + _key: q.string(), + _type: q.literal('price'), +}); diff --git a/templates/hydrogen-theme/app/qroq/sections.ts b/templates/hydrogen-theme/app/qroq/sections.ts index 137278b..d2ef781 100644 --- a/templates/hydrogen-theme/app/qroq/sections.ts +++ b/templates/hydrogen-theme/app/qroq/sections.ts @@ -4,6 +4,7 @@ import {q, z} from 'groqd'; import { ADD_TO_CART_BUTTON_BLOCK, + PRICE_BLOCK, SHOPIFY_DESCRIPTION_BLOCK, SHOPIFY_TITLE_BLOCK, } from './blocks'; @@ -117,6 +118,7 @@ export const PRODUCT_INFORMATION_SECTION_FRAGMENT = { SHOPIFY_TITLE_BLOCK, SHOPIFY_DESCRIPTION_BLOCK, ADD_TO_CART_BUTTON_BLOCK, + PRICE_BLOCK, q.contentBlock(), ]), ) diff --git a/templates/hydrogen-theme/studio/schemas/objects/global/productRichtext.tsx b/templates/hydrogen-theme/studio/schemas/objects/global/productRichtext.tsx index 90ee614..c552808 100644 --- a/templates/hydrogen-theme/studio/schemas/objects/global/productRichtext.tsx +++ b/templates/hydrogen-theme/studio/schemas/objects/global/productRichtext.tsx @@ -1,4 +1,4 @@ -import {ShoppingCart, Text, Type} from 'lucide-react'; +import {BadgeDollarSign, ShoppingCart, Text, Type} from 'lucide-react'; import {defineField} from 'sanity'; export default defineField({ @@ -50,6 +50,26 @@ export default defineField({ }, }, }, + { + name: 'price', + type: 'object', + fields: [ + defineField({ + name: 'priceProxy', + title: 'Price', + type: 'proxyString', + options: {field: 'store.priceRange.minVariantPrice'}, + }), + ], + icon: () => , + preview: { + prepare: () => { + return { + title: 'Price', + }; + }, + }, + }, { name: 'addToCartButton', type: 'object',