saleor-sdk icon indicating copy to clipboard operation
saleor-sdk copied to clipboard

Variant Details query

Open JannikZed opened this issue 4 years ago • 6 comments

We don't like the storefront implementation of the cart - it shows just the product thumbnails and not of the chosen variant - this is bad usability, as users dont really understand, what kind of variants they have chosen. I wanted to add this feature, but realized, that the SDK has no useProductvariant hook or otherwise, is not requesting variant images inn the useCart API. I would like to see that kind of feature - what do you think?

JannikZed avatar Nov 19 '20 15:11 JannikZed

Nowadays, you can get variant information from the ProductDetails query, and there's a hook for that. It used to be that you had to fetch Variant information separately, but that's been deprecated AFAIK.

beatboxchad avatar Nov 20 '20 16:11 beatboxchad

could you tell me more about the ProductDetails hook? - in my opinion, fetching a Variant only is definitely not deprecated. We just need data of a specific, selected variant in the card, to that would be the most elegant way. I was trying to use the useProductDetails hooks, resulting in this error: [Error] TypeError: react_apollo_1.useApolloClient is not a function. (In 'react_apollo_1.useApolloClient()', 'react_apollo_1.useApolloClient' is undefined) sentryWrapped (app.js:49757) dispatchEvent invokeGuardedCallbackDev (app.js:9566) invokeGuardedCallback (app.js:9621) commitRootImpl (app.js:34219) commitRootImpl unstable_runWithPriority (app.js:173800) commitRoot (app.js:34068) finishSyncRender (app.js:33475) performSyncWorkOnRoot (app.js:33453) performSyncWorkOnRoot (anonymous function) (app.js:21361) unstable_runWithPriority (app.js:173800) flushSyncCallbackQueueImpl (app.js:21356) flushSyncCallbackQueue (app.js:21344) scheduleUpdateOnFiber (app.js:32855) dispatchAction (app.js:26236) dispatchAction (anonymous function) (app.js:43169) (anonymous function) (app.js:41296) (anonymous function) (app.js:41202) forEach (anonymous function) (app.js:41201) (anonymous function) (app.js:43925) (anonymous function) (app.js:41198) forEach (anonymous function) (app.js:41196) saveObject (app.js:41085) setCheckout (app.js:41007) (anonymous function) (app.js:37508) generatorResume fulfilled (app.js:37482) promiseReactionJob

Code fragment:

import { useProductDetails } from "@saleor/sdk";

// import { TaxedMoney } from "@components/containers";
import { Thumbnail } from "@components/molecules";

import { generateProductUrl } from "../../../core/utils";
import removeImg from "../../../images/garbage.svg";

const ProductList: React.SFC<{
  lines: ICheckoutModelLine[];
  remove(variantId: string): void;
}> = ({ lines, remove }) => {
  const data = useProductDetails({ id: "XYTZ" });

So if you got it running, tell me how please :P

JannikZed avatar Nov 20 '20 16:11 JannikZed

Oh! Yes I know that error! It just started happening. They removed the useProductDetails hook in v0.5 -- it was part of the LegacyAPIProxy

Now, you have to destructure products from the useSaleorClient hook and call the getDetails attribute. getDetails is not a hook itself, it's a Promise wrapper around the Apollo client, so I use it async in an effect. For a full example, here's a hook I wrote that uses another context to fetch variant details with a different countryCode variable (apparently unused in vanilla Saleor, but I wrote a plugin on the backend that changes the price based on the countryCode):

import { useContext, useState, useEffect } from "react";
import { CountryContext } from "@temp/components/CountryProvider/context";
import { CountryCode, useSaleorClient } from "@saleor/sdk";
import { IProduct } from "@types";

export const useProductPricing = (product: IProduct): IProduct => {
  const [ret, setRet] = useState(product);
  const { country } = useContext(CountryContext);
  const { products } = useSaleorClient();

  useEffect(() => {
    const getDetails = async () => {
      const data = await products.getDetails({
        id: product.id,
        countryCode: country.code as CountryCode,
      });
      setRet(data.data as IProduct);
    };
    getDetails();
  }, [country]);

  return ret;
};

beatboxchad avatar Nov 20 '20 17:11 beatboxchad

ahh amazing! that looks good and it works as well. Should be added to the docs!

But I would really look to see the SDK useCart API to be enriched with variant Images .. otherwise, I would need to change it at so many places. I'm currently trying to create a little fork of the library to maybe later create a pull request. Do you actually know, where I would need to add the images query in order have them visible in the { lines} of useCart()?

JannikZed avatar Nov 23 '20 18:11 JannikZed

Hi there! I have same problem. I want get slug from getDetails in ProductList (src/components/OverlayManager/Cart/ProductList.tsx). How can I did it?

I have a problem generating url in Cyrillic, so I want to change the productUrl

korolevpavel avatar Nov 24 '20 09:11 korolevpavel

I did this, maybe it will be useful to someone

const ProductList: React.FC<{
  lines: ICheckoutModelLine[];
  remove(variantId: string): void;
}> = ({ lines, remove }) => {
  const [detailLines, setDetailLines] = React.useState([]);
  const { products } = useSaleorClient();

  React.useEffect(() => {
    const getDetails = async () => {
      const requestedProductLines = lines.map(line => {
        return products.getDetails({
          id: line.variant.product.id,
        });
      });

      Promise.all(requestedProductLines).then(products => {
        setDetailLines(
          products.map((productLine, index) => {
            return {
              ...lines[index],
              url: generateProductUrl(
                productLine.data.id,
                productLine.data.slug
              ),
            };
          })
        );
      });
    };
    getDetails();
  }, [lines]);

  return (
    <ul className="cart__list">
      {detailLines.map((line, index) => {
        const productUrl = line.url;
// ....

korolevpavel avatar Nov 24 '20 17:11 korolevpavel