fix: APP-410 save buy flow on last user interaction#2574
Conversation
✅ Deploy Preview for regen-website ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
✅ Deploy Preview for terrasos ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
|
@erikalogie see testing instructions |
|
LGTM |
fef3652 to
0b294da
Compare
blushi
left a comment
There was a problem hiding this comment.
Two additional comments:
- We don't save values for the last step to local storage
- When using credit card, if the user leaves the page while being on the last step, when he comes back, we should go back to step 2 (Payment info) because we need the user to re-enter credit card info since this is something we can't save to local storage of course
web-marketplace/src/components/molecules/CreditsAmount/CreditsAmount.tsx
Outdated
Show resolved
Hide resolved
web-marketplace/src/components/molecules/CreditsAmount/CreditsAmount.tsx
Show resolved
Hide resolved
web-marketplace/src/components/molecules/CreditsAmount/CreditsAmount.tsx
Show resolved
Hide resolved
web-marketplace/src/components/molecules/CreditsAmount/CurrencyInput.tsx
Outdated
Show resolved
Hide resolved
web-marketplace/src/components/organisms/PaymentInfoForm/PaymentInfoForm.tsx
Outdated
Show resolved
Hide resolved
|
@erikalogie can you review the changes mentioned in this comment please #2574 (review) |
|
LGTM |
|
LGTM ! |
| name: 'postalCode', | ||
| }); | ||
|
|
||
| const { anonymousPurchase, followProject, subscribeNewsletter, agreeErpa } = |
There was a problem hiding this comment.
it would be more appropriate to move that getValues() into the useEffect that uses them, looks like we don't need them at the component top level
this is also going to cause a bug when we enable anonymousPurchase checkbox (commented for now) because we use it in the checked prop and getValues does not subscribe to input change, which will cause the checkbox to be unresponsive, that's why we use useWatch instead, which you commented
There was a problem hiding this comment.
I believe this would only cause a bug if we wouldn't update the getValues when we uncomment the anonymousPurchase field. However, it'd probably be better to use useWatch for all fields. I've made the update, please review.
I've changed the way we handle @erikalogie @S4mmyb have a look how the currency and credits fields behave now when a user leaves the inputs with a value of zero or empty, let me know if you want to change anything. @blushi although the CI shows some failed tests they weren't related with the code updates and a redeploy seems to have been successful: https://app.netlify.com/sites/regen-website/deploys/6788180794db4932a06dce1f |
There was a problem hiding this comment.
I've changed the way we handle
onBlurwhen a user leaves the credits and currency inputs. Now if a user leaves the input with a value of0or empty''I'm resetting the credits to1and then setting the corresponding currency amount.
We should also reset the SELL_ORDERS value in this case. If I set one of the field to 0, then the currency/amount fields do update but not the selected sell orders
Here's how my local storage looks like after that:
and then when I go through the end of the flow, I cannot purchase because I'm getting an "invalid amount" error from our server endpoint /marketplace/v1/stripe/create-payment-intent since quantity is NaN
| const stripeAmount = | ||
| data?.[CURRENCY_AMOUNT] || | ||
| getCurrencyAmount({ | ||
| currentCreditsAmount: 1, | ||
| card: paymentOption === PAYMENT_OPTIONS.CARD, | ||
| orderedSellOrders: cardSellOrders, | ||
| creditTypePrecision: creditTypeData?.creditType?.precision, | ||
| }).currencyAmount; |
There was a problem hiding this comment.
should we put this in a useMemo too? getCurrencyAmount is a bit computation heavy
I think this is fine? @S4mmyb wdyt |
| setValue(CURRENCY_AMOUNT, currencyAmount, { shouldValidate: true }); | ||
| setValue(CREDITS_AMOUNT, 1, { shouldValidate: true }); | ||
| setValue(SELL_ORDERS, sellOrders); | ||
| handleOnChange(event); |
There was a problem hiding this comment.
could you say why we need handleOnChange now?
There was a problem hiding this comment.
We need to update the multiStep data as well. Please see to the latest updates where it has been modified to a more clear approach."
blushi
left a comment
There was a problem hiding this comment.
Looks like there has been a regression with the last few commits because this was working before:
If I go through the credit card flow until last "Retirement" step but leave the page and come back, I'm still at the "Retirement" step while I should be at "Payment info" step to re-enter credit card info
662d86f to
e2a3733
Compare
| if (maxStep !== 0) { | ||
| setMaxAllowedStep(maxStep); | ||
| } | ||
| setPaymentOption(paymentOption as PaymentOptionsType); |
There was a problem hiding this comment.
why do we need this here in addition to setPaymentOption(prev => data?.paymentOption || prev); in BuyCreditsForm?
There was a problem hiding this comment.
It quickly updates paymentOption when loading the form if there is localStorage data saved, avoiding this way a visual jump between sections (from step 2 to step 1) when the form was left in the retirement step.
There was a problem hiding this comment.
worth adding a comment about this then in the code
There was a problem hiding this comment.
is setPaymentOption(prev => data?.paymentOption || prev); still needed then?
There was a problem hiding this comment.
I think so. The new setPaymentOption gets triggered only when the form is instantiated. The other one every time data changes, its purpose hasn't changed I assume.
There was a problem hiding this comment.
I'm just questioning if we really need those react/jotai state variables now that the data in local storage is synced in real time but maybe we can think about that in a follow-up.
Looks like now the useEffect where we have setPaymentOption(prev => data?.paymentOption || prev) is called several times instead of just once when the user switches payment option.
We could probably update the dep array there to include only data?.retiring, data?.paymentOption instead of the whole data to mitigate that
There was a problem hiding this comment.
I have updated the deps in BuyCredits.Form.tsx and now it re-renders only once.
I'm just questioning if we really need those
My first thought is that we need them to trigger a re-render if there is localStorage data because we don't have access to the multiStep data in BuyCredits.tsx. Happy to review whether we can optimise this if we can allocate some time for it.
| steps={formModel.steps} | ||
| initialValues={{}} | ||
| classes={{ formWrap: 'max-w-[942px]' }} | ||
| forceStep={ |
There was a problem hiding this comment.
why do we need this in addition to the useEffect line 184 in BuyCreditsForm?
There was a problem hiding this comment.
Similar to my previous comment, doing it here avoids a visual jump from retirement to payment steps in cases when the form is loaded after a user left the form in the retirement step. I believe the code that we don't need anymore is the one in BuyCreditsForm.
352179b to
79ca1e3
Compare
Yeah I think this is good. @r41ph I just tested and was noticing:
|
@S4mmyb
And in the case where credits are only selected from one sell order, the avg price is the same as the sell order price. The issue here is that the price for one credit is lower than 0.5 USD which is the minimum accepted by Stripe. So quite an edge case, but we could have a follow-up issue to set it to 0.5 USD in this case and adjust the credits amount accordingly instead of having just 1 credit selected by default. |
I do not see this option in France. I guess this is a default option for US folks set up from Stripe, but we could disable it from Stripe dashboard since we haven't really planned for it. |
Yes, let's disable it. Maybe I haven't been seeing it either because I'm in the DR, though I do use a VPN for Miami. I can see it now though. |
Ok I've turnt it off |
Realistically, we won't multiple prices for fiat purchases atm as right now as we'll be managing them on-behalf of partners (i.e. project developers) who will be selling credits into a retired state. In the future when this more of a self-serve feature where any credit holder can manage selling on-chain credits with fiat we can treat this use case like we do crypto sell orders and list at multiple prices. For now though, I think we do price per credit. |
| newCreditsAmount = calculateCredits( | ||
| orderedSellOrders as CardSellOrder[], | ||
| MIN_USD_CURRENCY_AMOUNT, | ||
| ); |
There was a problem hiding this comment.
sell orders (to be set below in setValue(SELL_ORDERS, ...)) should be recomputed too
also can't we just use the existing function getCreditsAmount with value param equal to MIN_USD_CURRENCY_AMOUNT? this also returns the new sell orders
There was a problem hiding this comment.
Thanks - not sure what I was thinking!
There was a problem hiding this comment.
@blushi see refactored code using getCreditsAmount please
…es need to be selected in order to pay $0.5
d92dc95 to
93c9813
Compare



Description
https://regennetwork.atlassian.net/browse/APP-410
Now when users interact with the forms the information should be stored in the localstorage automatically even when the next button hasn't been clicked yet, and therefore, on navigating away and back to the same page, users should be in the same step and see the same form data as before navigating away.
Author Checklist
All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.
I have...
How to test
Reviewers Checklist
All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.
I have...