Shopify / js-buy-sdk

The JS Buy SDK is a lightweight library that allows you to build ecommerce into any website. It is based on Shopify's API and provides the ability to retrieve products and collections from your shop, add products to a cart, and checkout.
https://shopify.github.io/js-buy-sdk
MIT License
990 stars 261 forks source link

Using @inContext with queries/mutations #884

Open sjelfull opened 2 years ago

sjelfull commented 2 years ago

Feature details

Is your feature request related to a problem? Please describe. Since the removal of presentment prices and adding the @inContext directive, it seems like multi-currency behaviour is not consistent or helpful in the Buy SDK, meaning you have to run custom queries somehow.

My current problem that I'm trying to solve: I want to add multi-currency support, and I want to see the cart and line items in the currently selected currency.

Step 1 was figuring out how to set the currency on the cart. After a few rounds and touching the deprecated presentmentCurrencyCode, I found buyerIdentity.countryCode which gives me the correct currency on the cart, meaning the total will show in the associated currency.

However, the line item totals/prices is NOT returned in the correct currency - they use the default currency.

It was kind of hard to find the place that explains why this is - why would the cart show in two different currencies? My current understanding is that I need to use the new @inContext directive to ALSO get the line items in the correct currency.

Describe the solution you'd like Do you plan to add support for the @inContext directive in the short term, or could you help with a example that shows how to get the cart and all prices/totals in the same currency?

Describe alternatives you've considered I have considered trying to do the queries manually, but it requires a bit of a lift to do this since we use the JS SDK everywhere.

Additional context

Sample response:

{
  "data": {
    "node": {
      "__typename": "Checkout",
      "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dC81ZmNhNzEzNTA3Y2E5OGY3NWE4NWJjNDkwNWNjZmI3ZT9rZXk9YWUzODgyYmNmY2YwMTAyOWZlYTBmZWM3YmM2MmUyOTc=",
      "ready": true,
      "requiresShipping": true,
      "note": null,
      "paymentDue": "475.00",
      "paymentDueV2": { "amount": "475.0", "currencyCode": "CAD" },
      "webUrl": "https://shopName.myshopify.com/1508114519/checkouts/5fca713507ca98f75a85bc4905ccfb7e?key=ae3882bcfcf01029fea0fec7bc62exxx",
      "orderStatusUrl": null,
      "taxExempt": false,
      "taxesIncluded": false,
      "currencyCode": "CAD",
      "totalTax": "0.00",
      "totalTaxV2": { "amount": "0.0", "currencyCode": "CAD" },
      "lineItemsSubtotalPrice": { "amount": "475.0", "currencyCode": "CAD" },
      "subtotalPrice": "380.75",
      "subtotalPriceV2": { "amount": "475.0", "currencyCode": "CAD" },
      "totalPrice": "380.75",
      "totalPriceV2": { "amount": "475.0", "currencyCode": "CAD" },
      "completedAt": null,
      "createdAt": "2022-03-26T14:43:21Z",
      "updatedAt": "2022-03-26T14:43:23Z",
      "email": null,
      "discountApplications": {
        "pageInfo": { "hasNextPage": false, "hasPreviousPage": false },
        "edges": []
      },
      "appliedGiftCards": [],
      "shippingAddress": null,
      "shippingLine": null,
      "customAttributes": [],
      "order": null,
      "lineItems": {
        "pageInfo": { "hasNextPage": false, "hasPreviousPage": false },
        "edges": [
          {
            "cursor": "eyJsYXN0X2lkIjoxMjI4NzQ5ODI1NjQ3MTAsImxhc3RfdmFsdWUiOjEyMjg3NDk4MjU2NDcxMH0=",
            "node": {
              "id": "Z2lkOi8vc2hvcGlmeS9DaGVja291dExpbmVJdGVtLzEyMjg3NDk4MjU2NDcxMD9jaGVja291dD01ZmNhNzEzNTA3Y2E5OGY3NWE4NWJjNDkwNWNjZmI3ZQ==",
              "title": "Revol",
              "variant": {
                "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8xMjI4NzQ5ODI1NjQ3MQ==",
                "title": "S / Grey",
                "price": "375.00",
                "priceV2": { "amount": "375.0", "currencyCode": "USD" },
                "weight": 25.0,
                "available": true,
                "sku": "CRA003AASG",
                "compareAtPrice": null,
                "compareAtPriceV2": null,
                "image": {
                  "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0SW1hZ2UvMjk0OTY4Mjk5MDMwMzQ=",
                  "src": "https://cdn.shopify.com/s/files/",
                  "altText": null,
                  "width": 800,
                  "height": 800
                },
                "selectedOptions": [
                  { "name": "Size", "value": "S" },
                  { "name": "Color", "value": "Grey" }
                ],
                "unitPrice": null,
                "unitPriceMeasurement": {
                  "measuredType": null,
                  "quantityUnit": null,
                  "quantityValue": 0.0,
                  "referenceUnit": null,
                  "referenceValue": 0
                },
                "product": {
                  "id": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzEzMzkyMTkzNzgyNjM=",
                  "handle": "product-slug"
                }
              },
              "quantity": 1,
              "customAttributes": [
                { "key": "_preorder", "value": "false" },
                { "key": "_backorder", "value": "false" }
              ],
              "discountAllocations": []
            }
          }
        ]
      }
    }
  }
}
sjelfull commented 2 years ago

Since the Buy SDK doesn't work with this at all I ended up rewriting all calls to use raw GraphQL queries.

sblackstone commented 2 years ago

@sjelfull Were you able to use @inContext directives using the same gql library js-buy-sdk uses? graphql-js-client ?

It seems like they support directives but not on the root query object.....

sjelfull commented 2 years ago

I ended up using apollographql/graphql-tag/loader (included in Gatsby) and graphql-request - think the latter was 1/3 the size of graphql-js-client according to Bundlephobia.

I copied all the .graphql files, added the @inContext directive, and used this code to change the country code depending on the language:

function replaceContextCountry(query) {
  query.definitions[0].directives[0].arguments[0].value.value = regionIsoCode

  return query
}
Adu88 commented 2 years ago

i modified the structure of the buy sdk a bit and managed to make directives work. I will paste here some screenshots of what i did: modified the parse args function, the operation object, the send method, the checkout/product resource methods and the queries by adding that internationalization parameter. Then when you call buy sdk from react you call it: client.checkout.create(input, @inContext(country: 'US') and everything should work.

Screenshot 2022-05-12 at 16 41 29 Screenshot 2022-05-12 at 16 42 57 Screenshot 2022-05-12 at 16 43 02 Screenshot 2022-05-12 at 16 17 00 Screenshot 2022-05-12 at 16 18 18 Screenshot 2022-05-12 at 16 37 55
sblackstone commented 2 years ago

@Adu88 Thank you! I've actually been working on modifying graphql-js-client to try to support this correctly - if we're writing our own queries anyways, you really don't need js-buy-sdk, just the graphql-js-client-compiler and the schema.json file.

JeffJassky commented 1 year ago

@Adu88 Any chance you'd be open to sharing your changes with the community via pull request? There are a number of us who just got bit by presentmentPrices being discontinued this week in #959 and #853

Adu88 commented 1 year ago

@JeffJassky Here you go i created a repo with the file i use for the buy-sdk client when i make queries to shopify. https://github.com/Adu88/buy-sdk. Feel free to clone it and see the updates/differences i wrote above.

Also from above it's missing this:

Screenshot 2023-07-07 at 08 09 38

and of course when you call that method you've modified from the client you need to call it with your internationalDirective like this : client.product.fetchMultiple(product_ids, internationalizationDirective), with the internationalizationDirective value should look like this: '@inContext(country:${selectedCountry.isoCode})' ex: '@inContext(country: RO)'

joshuajylin commented 1 year ago

@Adu88 Based on your code, I fixed some issues that occourred when the internationalizationDirective was not provided. https://github.com/joshuajylin/buy-sdk