diff --git a/.gitignore b/.gitignore index 15e85d3e..34ff5c91 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ node/coverage/* ### VS Code ### *.vscode +### Claude Code ### +.claude/ + ### OSX ### .DS_Store .AppleDouble diff --git a/CHANGELOG.md b/CHANGELOG.md index ae1e2e98..8c99beaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Added + +- Fetch `commertialOffer.priceToken` in the product queries and forward it as `priceToken` on the `addToCart` payload of `AutocompleteBlock` and `CategoryBlock`, so the Checkout can close the cart with the signed price while the Pricing is unavailable (Pricing Fallback V2) + ## [3.16.8] - 2026-06-29 ### Fixed diff --git a/react/AutocompleteBlock.tsx b/react/AutocompleteBlock.tsx index cfd97b1a..8fa9388c 100644 --- a/react/AutocompleteBlock.tsx +++ b/react/AutocompleteBlock.tsx @@ -187,12 +187,18 @@ const AutocompleteBlock: FunctionComponent = ({ const selectedSku = data.product.items.length === 1 ? data.product.items[0].itemId : null - const seller = selectedSku + const defaultSeller = selectedSku ? data.product.items[0].sellers.find((item: any) => { return item.sellerDefault === true - }).sellerId + }) : null + const seller = selectedSku ? defaultSeller.sellerId : null + + // Signed price from the search response, forwarded on addToCart so the + // Checkout can close the cart even while the Pricing is unavailable + const priceToken = defaultSeller?.commertialOffer?.priceToken ?? null + let multiplier = 1 if (data.product.items.length === 1) { @@ -203,7 +209,7 @@ const AutocompleteBlock: FunctionComponent = ({ ...state, selectedItem: !!product && product.length - ? { ...product[0], value: selectedSku, seller, data } + ? { ...product[0], value: selectedSku, seller, priceToken, data } : null, unitMultiplier: multiplier, quantitySelected: multiplier, @@ -214,24 +220,21 @@ const AutocompleteBlock: FunctionComponent = ({ } const selectSku = (value: string) => { - const seller = selectedItem.data.product.items - .find((item: any) => { - return item.itemId === value - }) - .sellers.find((s: any) => { - return s.sellerDefault === true - }).sellerId + const matchedItem = selectedItem.data.product.items.find( + (item) => item.itemId === value + ) + + const defaultSeller = matchedItem.sellers.find((s: any) => { + return s.sellerDefault === true + }) const newSelected = { ...selectedItem, - seller, + seller: defaultSeller.sellerId, + priceToken: defaultSeller.commertialOffer?.priceToken ?? null, value, } - const matchedItem = selectedItem.data.product.items.find( - (item) => item.itemId === value - ) - setState({ ...state, selectedItem: newSelected, @@ -262,6 +265,9 @@ const AutocompleteBlock: FunctionComponent = ({ unitMultiplier ), seller: selectedItem.seller, + ...(selectedItem.priceToken + ? { priceToken: selectedItem.priceToken } + : {}), }, ] diff --git a/react/CategoryBlock.tsx b/react/CategoryBlock.tsx index 72bd9b89..6b0aab41 100644 --- a/react/CategoryBlock.tsx +++ b/react/CategoryBlock.tsx @@ -37,6 +37,8 @@ const CategoryBlock: FunctionComponent = ({ categoryItems: {}, quantitySelected: {}, defaultSeller: {}, + // Signed price of the selected seller, by SKU, as returned by the search + priceTokens: {}, // All the items with their respective units unitMultiplierList: {}, }) @@ -52,6 +54,7 @@ const CategoryBlock: FunctionComponent = ({ categoryItems, quantitySelected, defaultSeller, + priceTokens, unitMultiplierList, } = state @@ -274,6 +277,8 @@ const CategoryBlock: FunctionComponent = ({ if (skus?.length) { const items = skus.map((item: any) => { + const priceToken = priceTokens[item] + return { id: parseInt(item, 10), quantity: calculateDivisible( @@ -281,6 +286,7 @@ const CategoryBlock: FunctionComponent = ({ item ), seller: defaultSeller[item], + ...(priceToken ? { priceToken } : {}), } }) @@ -373,19 +379,34 @@ const CategoryBlock: FunctionComponent = ({ newQtd[content.itemId] = e.target.value const newSeller = defaultSeller + const newPriceTokens = priceTokens const seller = content.sellers.find((s: any) => { return s.sellerDefault === true }) - newSeller[content.itemId] = + const sellerId = seller?.sellerId || (content.sellers.length ? content.sellers[0].sellerId : '1') + // the token has to come from the very seller sent + // on addToCart, since it signs that seller's price + const selectedSeller = content.sellers.find( + (s: any) => { + return s.sellerId === sellerId + } + ) + + newSeller[content.itemId] = sellerId + newPriceTokens[content.itemId] = + selectedSeller?.commertialOffer?.priceToken ?? + null + _setState({ quantitySelected: newQtd, defaultSeller: newSeller, + priceTokens: newPriceTokens, }) }} onBlur={() => { diff --git a/react/queries/product.gql b/react/queries/product.gql index b826f81b..ddb51817 100644 --- a/react/queries/product.gql +++ b/react/queries/product.gql @@ -10,6 +10,9 @@ query Product($skuId: ID!) { sellerId sellerName sellerDefault + commertialOffer { + priceToken + } } referenceId { Key diff --git a/react/queries/productsByCategory.gql b/react/queries/productsByCategory.gql index a85c83ec..345fa13c 100644 --- a/react/queries/productsByCategory.gql +++ b/react/queries/productsByCategory.gql @@ -10,6 +10,9 @@ query SearchByCategory($selectedFacets: [SelectedFacetInput]) { sellerId sellerName sellerDefault + commertialOffer { + priceToken + } } images(quantity: 1) { imageUrl