Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(payment): BOLT-19 added BoltCheckout implementation for customer… #1163

Closed

Conversation

serhii-tkachenko
Copy link
Contributor

@serhii-tkachenko serhii-tkachenko commented Jun 24, 2021

…s with bolt account

What?

Added BoltCheckout implementation for customers with bolt account.

Why?

We need to add custom flow for continue as guest, sign in and sign up events, to show BoltCheckout modal if the customer has BoltAccount

Task: https://jira.bigcommerce.com/browse/BOLT-19

Sibling pull-request

checkout-js: bigcommerce/checkout-js#619

Testing / Proof

Some gifs to figure out how it looks like:
continue_as_customer
sign_in
sign_up

There how it will looks like if the user have default flow or customer hasn't bolt account:
continue_as_guest_without_bolt_account

@bigcommerce/checkout @bigcommerce/payments

@serhii-tkachenko serhii-tkachenko requested a review from a team as a code owner June 24, 2021 06:36
@serhii-tkachenko serhii-tkachenko changed the title feat(payment): BOLT-19 added BoltCheckout implementation for customer… [draft-2, wip] feat(payment): BOLT-19 added BoltCheckout implementation for customer… Jun 24, 2021
@serhii-tkachenko serhii-tkachenko marked this pull request as draft June 24, 2021 08:45
Copy link
Contributor

@BC-ACherednichenko BC-ACherednichenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely done! I like this idea more than than the first revision #1158, we re-use the existing strategy without creating additional one that behaves pretty much in the same way

@davidchin @icatalina can you take a look at these two possible options and let us know your thoughts. The possible way that we will choose more likely correspond to the philosophy of the existing customer strategy, hence your input will be invaluable

@serhii-tkachenko serhii-tkachenko force-pushed the BOLT-19-2 branch 4 times, most recently from e390ee6 to 1dd651f Compare June 30, 2021 12:33
@serhii-tkachenko serhii-tkachenko marked this pull request as ready for review June 30, 2021 12:47
@serhii-tkachenko serhii-tkachenko changed the title [draft-2, wip] feat(payment): BOLT-19 added BoltCheckout implementation for customer… feat(payment): BOLT-19 added BoltCheckout implementation for customer… Jun 30, 2021
Copy link
Contributor

@BC-ACherednichenko BC-ACherednichenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! There is only one minor concern

@davidchin can take a look?

}
} catch (error) {
resolve();
throw error;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

per our discussion, it worth to just log an error in order to not interrupt the default flow (will check if throw fully interrupts the default flow). continueWith strategy is not as vital for checkout as a strategy of a payment provider. we can remain the default flow if we have any issue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked it and it is working as expected. If we somehow get an error, we will continue with default flow without any problem

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the intention is good. But I think what we should do, from SDK library's perspective, is to return an error and let the client to catch and decide what to do next as a recovery. The client may choose to silently ignore the error and log it behind the scene. Or it may choose to display a message informing that the shopper that something went wrong but they can still progress.

Copy link
Contributor

@vitalii-koshovyi vitalii-koshovyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, except some tests names. I've sent my propositions to @Sireks in slack message.

isContinuingAsGuest: false,
});

expect(customerStrategyReducer(initialState, action).statuses).toEqual({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is that expect useful?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is.

Already fixed all those propositions that you sent me in slack.

Copy link
Contributor

@davidchin davidchin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @Sireks. It's looking good no major issue with the code itself. However, as I mentioned in your other PR, I'm blocking this for now until we get some clarification from product.

const { methodId } = options;

if (!methodId) {
throw new MissingDataError(MissingDataErrorType.MissingPaymentMethod);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InvalidArgument is a better error to throw (i.e.: the required argument is not passed).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

const { developerConfig, publishableKey } = paymentMethod.initializationData;

return this._boltScriptLoader.load(publishableKey, paymentMethod.config.testMode, developerConfig)
.then(boltCheckout => this._boltClient = boltCheckout)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer async/await for any new files that we create.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

.then(() => this._store.getState());
}

private openCustomBoltCheckoutWidget(email: string, methodId: string): Promise<InternalCheckoutSelectors> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a convention of prefixing private members, including methods, with an underscore. This is because when TS is compiled to JS, people know that they shouldn't be accessing those members.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

};

this._boltClient.openCheckout(email, callbacks)
.then(result => !result && resolve());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can openCheckout return an error / rejected promise. If so, we need to handle it accordingly,.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is already wrapped in try...catch.
I will remove that then chaining, because it is unnecessary anymore

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try/catch block has no effect because you're using the then syntax. It only works if you use the async/await syntax.

}

private openCustomBoltCheckoutWidget(email: string, methodId: string): Promise<InternalCheckoutSelectors> {
return new Promise(resolve => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to manually construct a Promise as openCheckout already returns one. So you can just chain to it and return a Promise that way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will check this one

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change the method to make it more readable, but I need to keep new Promise(resolve => ...) to make all the code that left run only if the modal was closed.

If Bolt Checkout modal was closed, it's ok, we will run default customer flow. But if shopper will continue with Bolt Checkout Modal, he/she will be redirected to Success page in the end of the flow.

}
} catch (error) {
resolve();
throw error;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the intention is good. But I think what we should do, from SDK library's perspective, is to return an error and let the client to catch and decide what to do next as a recovery. The client may choose to silently ignore the error and log it behind the scene. Or it may choose to display a message informing that the shopper that something went wrong but they can still progress.

throw new MissingDataError(MissingDataErrorType.MissingPaymentMethod);
}

return this._store.dispatch(this._customerActionCreator.signInCustomer(credentials, options))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this mean that if a shopper chooses to sign into their BC account, and then refresh the page before they get a chance to complete whatever that's needed in the Bolt widget, they won't be prompted to complete the Bolt widget again (because the shopper is already signed in so they will be prompted to complete the next/shipping step instead)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am working on the implementation right now. We need to check if there any customContinueFlowEnabled in Checkout component and then handle to open customer step to open the BoltCheckout modal again.

bigcommerce/checkout-js#627

May be you can give me some advice how to do it right

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logged in shopper will have Bolt checkout modal open each time when open Checkout page and if the shopper has Bolt Account

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have to be careful on this because you're assuming that the shopper wants to use Bolt. It might be that they intentionally close the Bolt modal. But they are prompted again everytime they reopen checkout or go back to the customer step.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we don't know why the user closed Bolt Checkout modal, maybe shopper want to get more stuff to make the order or so. We will open the modal only for those customer that has their own Bolt Account. Otherwise the modal will not be showed.

We discussed this case a couple times... And we made the decision to make it like this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your team has made a decision. And I'm sorry if you feel like we're revisiting that decision. But considering that decision was made without consulting with our team, I think it's reasonable for us to question it and perhaps make adjustments to it if we both agree they are appropriate.

Anyway the reason why I brought this up is because you're making an assumption that shoppers with an existing Bolt account really want to use Bolt. Having a Bolt account does not mean the shopper wants to use it. It just means they have an account which they may choose to use it. Anyway, I guess you can say the shopper can just close it again if they really don't want use Bolt. That's fair enough. But what if the store has PayPal enabled and the shopper (with an existing Bolt account) clicks on the PayPal button on the cart page, authorises the payment on PayPal side and then get redirected to checkout, would they see the Bolt modal open automatically? If that's the case, I think we have a problem. At least, we have to make sure that if there's a payment in progress, don't try to encourage the shopper to abandon it and switch to use Bolt.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @davidchin!

It's ok. We will discuss the issue and I or someone from my team will tell you about what we will doing next.

But it's a question for another task and the case has not to be a blocker for current task.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your team has made a decision. And I'm sorry if you feel like we're revisiting that decision. But considering that decision was made without consulting with our team, I think it's reasonable for us to question it and perhaps make adjustments to it if we both agree they are appropriate.

@davidchin this is what these 2 PRs about, as long as the flow is a bit tricky, we made some decisions and started conversation with these 2 POCs

I think we have to be careful on this because you're assuming that the shopper wants to use Bolt. It might be that they intentionally close the Bolt modal. But they are prompted again everytime they reopen checkout or go back to the customer step.

To my knowdledge, we have decided to introduce some flag in checkout session (the research on this feature is in the progress), that will be set whenever a buyer mananges popup, so in the scope of single quote they will not be bombarded with the popup over and overagain

tslint.json Outdated
@@ -4,6 +4,7 @@
"max-line-length": false,
"no-empty": false,
"no-shadowed-variable": false,
"object-literal-sort-keys": false
"object-literal-sort-keys": false,
"cyclomatic-complexity": false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should try to resolve the cyclomatic complexity by refactoring the code rather than disabling the rule. If the refactoring takes too much effort and you'd rather tackle it separately, then you can disable the rule locally for the file only rather than disabling it globally for all files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

@serhii-tkachenko serhii-tkachenko force-pushed the BOLT-19-2 branch 2 times, most recently from 0ffb8f5 to 60ca262 Compare July 8, 2021 06:46
@serhii-tkachenko
Copy link
Contributor Author

@davidchin
I added some fixed. Can you check if everything all right?

@serhii-tkachenko serhii-tkachenko marked this pull request as draft July 28, 2021 11:09
@serhii-tkachenko serhii-tkachenko deleted the BOLT-19-2 branch October 20, 2022 08:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants