From c2e5eb85018fbca5eb07c013a6e58e961e5a2997 Mon Sep 17 00:00:00 2001 From: cond0r Date: Sat, 27 Mar 2021 19:09:00 +0200 Subject: [PATCH] Sell only available products / fix out of stock --- .../product/ProductView/ProductView.tsx | 6 +++++- framework/commerce/types.ts | 6 ++++++ framework/shopify/customer/use-customer.tsx | 13 +++++++----- framework/shopify/types.ts | 4 +--- .../shopify/utils/get-search-variables.ts | 6 +++--- framework/shopify/utils/normalize.ts | 20 ++++++++++++++----- .../utils/queries/get-all-products-query.ts | 4 ++-- .../utils/queries/get-product-query.ts | 4 +++- 8 files changed, 43 insertions(+), 20 deletions(-) diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index 05e7a1cee..89c69734f 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -146,8 +146,12 @@ const ProductView: FC = ({ product }) => { className={s.button} onClick={addToCart} loading={loading} + disabled={variant?.availableForSale === false} > - Add to Cart + {variant?.isInStock === false && + variant?.availableForSale === false + ? 'Out Of Stock' + : 'Add To Cart'} diff --git a/framework/commerce/types.ts b/framework/commerce/types.ts index a398070ac..88b104311 100644 --- a/framework/commerce/types.ts +++ b/framework/commerce/types.ts @@ -190,6 +190,12 @@ interface ProductImage { interface ProductVariant2 { id: string | number options: ProductOption[] + // Indicates whether this product variant is in stock. + isInStock?: boolean + // Indicates if the product variant is available for sale. + availableForSale?: boolean + // The total sellable quantity of the variant for online sales channels. + quantityAvailable?: number } interface ProductPrice { diff --git a/framework/shopify/customer/use-customer.tsx b/framework/shopify/customer/use-customer.tsx index 137f0da74..f1141ae89 100644 --- a/framework/shopify/customer/use-customer.tsx +++ b/framework/shopify/customer/use-customer.tsx @@ -10,11 +10,14 @@ export const handler: SWRHook = { query: getCustomerQuery, }, async fetcher({ options, fetch }) { - const data = await fetch({ - ...options, - variables: { customerAccessToken: getCustomerToken() }, - }) - return data.customer ?? null + const customerAccessToken = getCustomerToken() + if (customerAccessToken) { + const data = await fetch({ + ...options, + variables: { customerAccessToken }, + }) + return data.customer ?? null + } }, useHook: ({ useData }) => (input) => { return useData({ diff --git a/framework/shopify/types.ts b/framework/shopify/types.ts index 2f2176c35..f172a38c4 100644 --- a/framework/shopify/types.ts +++ b/framework/shopify/types.ts @@ -18,9 +18,7 @@ export interface LineItem extends Core.LineItem { * Cart mutations */ -export type Product = Core.Product & { - totalInventory?: Maybe -} +export type Product = Core.Product export type OptionSelections = { option_id: number diff --git a/framework/shopify/utils/get-search-variables.ts b/framework/shopify/utils/get-search-variables.ts index c1b40ae5d..b514db446 100644 --- a/framework/shopify/utils/get-search-variables.ts +++ b/framework/shopify/utils/get-search-variables.ts @@ -7,14 +7,14 @@ export const getSearchVariables = ({ categoryId, sort, }: SearchProductsInput) => { - let query = '' + let query = 'available_for_sale:true' if (search) { - query += `product_type:${search} OR title:${search} OR tag:${search}` + query += ` product_type:${search} OR title:${search} OR tag:${search}` } if (brandId) { - query += `${search ? ' AND ' : ''}vendor:${brandId}` + query += ` ${search ? 'AND ' : ''}vendor:${brandId}` } return { diff --git a/framework/shopify/utils/normalize.ts b/framework/shopify/utils/normalize.ts index 246604dc3..d25b7548c 100644 --- a/framework/shopify/utils/normalize.ts +++ b/framework/shopify/utils/normalize.ts @@ -51,15 +51,27 @@ const normalizeProductImages = ({ edges }: ImageConnection) => const normalizeProductVariants = ({ edges }: ProductVariantConnection) => { return edges?.map( ({ - node: { id, selectedOptions, sku, title, priceV2, compareAtPriceV2 }, + node: { + id, + title, + sku, + priceV2, + compareAtPriceV2, + selectedOptions, + requiresShipping, + availableForSale, + quantityAvailable, + }, }) => { return { id, name: title, - sku: sku ?? id, + sku: sku ?? '', price: +priceV2.amount, listPrice: +compareAtPriceV2?.amount, - requiresShipping: true, + requiresShipping, + availableForSale, + isInStock: Boolean(Number(quantityAvailable) > 0), options: selectedOptions.map(({ name, value }: SelectedOption) => { const options = normalizeProductOption({ id, @@ -84,7 +96,6 @@ export function normalizeProduct(productNode: ShopifyProduct): Product { handle, priceRange, options, - totalInventory, ...rest } = productNode @@ -98,7 +109,6 @@ export function normalizeProduct(productNode: ShopifyProduct): Product { price: money(priceRange?.minVariantPrice), images: normalizeProductImages(images), variants: variants ? normalizeProductVariants(variants) : [], - totalInventory, options: options ? options .filter((o) => o.name !== 'Title') // By default Shopify adds a 'Title' name when there's only one option. We don't need it. https://community.shopify.com/c/Shopify-APIs-SDKs/Adding-new-product-variant-is-automatically-adding-quot-Default/td-p/358095 diff --git a/framework/shopify/utils/queries/get-all-products-query.ts b/framework/shopify/utils/queries/get-all-products-query.ts index bcd05ee93..f9ec72e83 100644 --- a/framework/shopify/utils/queries/get-all-products-query.ts +++ b/framework/shopify/utils/queries/get-all-products-query.ts @@ -10,7 +10,7 @@ edges { vendor handle description - totalInventory + availableForSale priceRange { minVariantPrice { amount @@ -48,7 +48,7 @@ products( const getAllProductsQuery = /* GraphQL */ ` query getAllProducts( $first: Int = 250 - $query: String = "" + $query: String = "available_for_sale:true" $sortKey: ProductSortKeys = RELEVANCE $reverse: Boolean = false ) { diff --git a/framework/shopify/utils/queries/get-product-query.ts b/framework/shopify/utils/queries/get-product-query.ts index 8386e23af..0e33fb348 100644 --- a/framework/shopify/utils/queries/get-product-query.ts +++ b/framework/shopify/utils/queries/get-product-query.ts @@ -8,7 +8,6 @@ const getProductQuery = /* GraphQL */ ` vendor description descriptionHtml - totalInventory options { id name @@ -34,6 +33,9 @@ const getProductQuery = /* GraphQL */ ` id title sku + availableForSale + requiresShipping + quantityAvailable selectedOptions { name value