Tech refinement - Add offer Combo/Picker to the cart
Table of Contents
More details here: Promo code at checkout page X config offer type
PoC working example
Important: Please disregard the delay when adding the offer. This is a PoC example. This needs to be improved in the final solution.
Tasks breakdown
Main file to be changed:
src/state/loyalty/hooks/use-redeem-promo-code-checkout.ts
PoC branch: poc/apply-multiple-offer-types-checkout
The only needed changes will be at:
src/state/loyalty/hooks/use-redeem-promo-code-checkout.ts
src/hooks/menu/use-product-price.ts
Task 1 - Create a new method responsible to add other types of offer
Get the whole Picker/Combo from Config Offers incentives
Option 1: adjust and extend the
config-offer.graphql
query to get all the Combo/PickerReuse this data to apply the offer item to the cart. Today we have a problem with this solution described here Promo code at checkout page X config offer type | Option 1 Transform and apply “In App Benefits” Combo/Picker item directly (de...
Option 2: with the return id from the Config Offers incentives item, make two new queries (new method) to get the item data:
If combo:
GetComboDocument
GetComboAvailabilityDocument
If Picker:
GetPickerDocument
GetPickerAvailabilityDocument
One option is to use the
Promise.all
to run the two queries and then merge the results of the queries using themerge
from lodash. This solution is based on what the menu methodqueryMenuData
(src/state/menu-options/legacy-menu-options.tsx
) does. We can also transform this function into a utils one to reuse.
Use
ProductWizardUtils.ComputeSelectedOption
to transform the itens correctly. This is important for Picker. The method will convert the Picker to a regular itemUse the
ProductWizardUtils.SetDefaultSelections
to get the default selectionsUse the
transformMenuObjectToCartItem
to convert the Combo/Picker (the data that will come from Option1 or Option 2)Update the Redux state using the
dispatch
and theactions.loyalty.applyOffer
Use the
totalPrice
method (src/hooks/menu/use-product-price.ts
) to calculate the correct price ----> We had a problem here and I was able to fix the code (suggestion on the PoC code example below). The value always needs to be correct (see PoC code example for more details and tips)If we have a vendor config the value should be from there
If we don’t have a vendor config the value should be the offer price (offer config content)
If we don’t have any value at all then we need to look at the vendor config for the item
Adjust the loading state to only finish when we in fact add the new item into the cart
Use the
upsertCart
to add the transformed item to the cartWe need also to ensure
If the offer from incentives is type
Item
,Swap
orOffer Discount
we need to return an invalid promo code error. We validated this with @Lopes da Costa, Valentina and she said that this types of offer are not supported today (they come from the legacy US code)
PoC code example and mentions
The code below should not be the final solution
The objective of the PoC is to prove an idea. I didn't make the code semantic or beautiful. This will be a responsibility for the dev
We should create new methods and reuse the code at maximum (see Suggestion of implementation below)
PoC code is inside this collapse:
Suggestion of implementation
I extracted part of the logic (showed in the PoC code) from the
useProductCart
hook (frontend/src/components/product-detail/use-product-cart.ts) in theaddToOrder
andhandleOffers
methods. We can create new methods for isolating the desired logics on that hook and reuse them in our implementation. This will improve the reuse of code and its maintainability.I also extracted some part of the logic from
legacy-menu-options.tsx
file. This should be an utils or something like that, and then, we can reuse this piece of code in more than one place
Problems to be fixed
Sometimes, when we enter the cart page for the first time, we can get an error about invalid items in the cart. As we have our
useEffect
running all the time, I think that this is part of the problem. We need to ensure that nothing will be running at the wrong timeWhen we add a Picker item, the price can be wrong (without considering the offer
vendorConfig
information). The best way to know if the offer item was added correctly is to compare what happens if we add the same offer through the legacy flow (/offers
page). If something on the item (price, sub-items, etc) is wrong, then we have a problem!
About the item validation
The checkout page already has validations to prevent and invalid item to be used (for example if I tried to use a promo code that has an invalid item for my selected store):
After some seconds the page will also show this modal:
This legacy validations are important and we always need to ensure:
An offer item can only be used if the store returns that this is a valid/available item. As we are using the availability query we can know if the item is invalid too, if necessary
To test this we can use a menu item that is not available at a specific restaurant, for example
DOD-LIKE
Validate the behavior with manual tests
Adjust and create new unit tests for our hook
Task 2 - Adjust the hook to respect the reuse logic behavior
The main point here is to keep the following behaviors:
If the user tried to add an already-added offer, he should receive the error message below the promo code input, as we do for the Offer Discount type
If the user tried to add an already redeemed offer, we need to get the information from the user offer available list (as we do for the Offer Discount type)
If the user applies an offer into the cart and goes back to the
/offers
page the current offer should be selectedIf the user adds the same offer again we don’t want to add the same Combo/Picker item to the cart again. If necessary we need to check the
cartEntries
(we can get that fromuseOrderContext
) to know if our offer cart item is already addedTip: we always need to compare and ensure that our page is “connected” with the
/offers
page and we also need to ensure that we have the same behaviors of the legacy flow
Problems to be fixed
applyOfferPromoCode
: for Picker/Combo offer we can’t set thesetAppliedOfferPromoCode
. We need to add a condition here. He don’t want to show the discount offer card as showed below:
Task 3 - Adjust the code to deal with more than one Combo/Picker incentives
The user has the ability to add more than one Combo/Picker on Sanity. With that in mind, we need to ensure that our logic will be good enough to deal with an iterable list of incentives.
This needs to work with the reuse logic developed on Task 2
Add new unit tests to cover this kind of scenario