- From: Marcos Cáceres <notifications@github.com>
- Date: Wed, 02 May 2018 01:02:30 -0700
- To: w3c/payment-request <payment-request@noreply.github.com>
- Cc: Subscribed <subscribed@noreply.github.com>
- Message-ID: <w3c/payment-request/issues/705@github.com>
@domenic, @aestes, @zkoch, @adrianba, @mnoorenberghe, @stpeter, all, here is an attempt to solve the retry issue. It builds on the fine grained error recovery proposal at #647, and on payment method change event (#695).
## Retrying a payment flow
I did a bunch of experimentation, and I think the most logical solution is to mixin the handlers from `PaymentRequest` into `PaymentResponse` (or just add them directly as below?... hi @domenic!), plus add a `onpayerdetailschange` and `onpaymentmethodchange` event handlers, and a `.retry()` method.
That means that we don't need to screw around with dead `PaymentRequest`s by resetting their state machines.
The rationale for adding the new `onpayerdetailschange` being that `PaymentRequest` never gets things like `payerName`, `payerEmail`, etc. so there is no way to detect those changing. Similarly, `onpaymentmethodchange` reflects the full payment handler response, which is not available on `PaymentRequest`.
Thus... I'd like to propose:
### IDL changes
```JS
/* see https://github.com/w3c/payment-request/issues/647#issuecomment-385852164 */
dictionary PaymentErrors {
PayerErrors payerErrors;
AddressErrors shippingAddressErrors;
}
// we could make this a mixin
partial interface PaymentResponse {
attribute EventHandler onshippingaddresschange;
attribute EventHandler onshippingoptionchange;
// name, email, phone
attribute EventHandler onpayerdetailschange;
// https://github.com/w3c/payment-request/pull/695
attribute EventHandler onpaymentmethodchange;
void retry(PaymentErrors errors)
}
```
### `retry()` method
The `retry()` method signals that something is wrong with the sheet.
What's actually wrong with the sheet is represented by the `PaymentErrors errors` argument.
`retry()` can only be called once. It tells the browser: "let the user change the requested inputs" (i.e., what's in `PaymentOptions` and the ). Calling it again, rejects a `retryPromise` with `"InvalidState"` error.
Empty `PaymentErrors` dictionary (i.e., `.retry({})`) means "unknown" error, meaning the user should check all their inputs. Otherwise, fix the `errors`.
Question: is there any reason `.retry()` should return a promise? I left it "fire and forget" like `.updateWith()`, because I couldn't think of any reason not to.
## `onpayerdetailschange` event handler
The `onpayerdetailschange` fires when the user changes `name`, `email`, `phone`, depending on whether `PaymentOptions` requested them.
When this event fires, the merchant simply queries `PaymentResponse` for the thing they are interested in validating/checking. If value of attribute is invalid, the merchant calls `ev.updateWith({ stuffToFix })` (see #647).
## Example of usage
This shows how a merchant could use async validators to process a `PaymentResponse`.
(Mock code, untested... treat a pseudo code for illustrative purposes).
```JS
async function doPaymentRequest() {
const request = new PaymentRequest(methodData, details, options);
const response = await request.show();
const validator = new Validator(); // user code
// collect any errors from response
const {
shippingAddressErrors,
payerErrors,
paymentMethodErrors, // <- needs exploration.
} = await validator.validateResponse(response);
// Ok, we got bad input... let's get the user to fix those!
if (shippingAddressErrors || payerErrors || paymentMethodErrors) {
const promisesToFixThings = [];
// let's make sure the shipping address is fixed
if (shippingAddressErrors) {
const promiseToFixAddress = new Promise(resolve => {
// Browser keeps calling this until promise resolves.
response.onpaymentaddresschange = async ev => {
const promiseToValidate = validator.validateShippingAddress(response);
ev.updateWith(promiseToValidate);
// we could abort here via try/catch
const errors = await promiseToValidate;
if (!errors) {
resolve(); // yay! Address is fixed!
}
};
});
promisesToFixThings.push(promiseToFixAddress);
}
if (payerErrors) {
// As above for payer errors
}
response.retry({ shippingAddressErrors, payerErrors });
await Promise.all(promisesToFixThings);
}
await response.complete("success");
}
doPaymentRequest();
```
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/payment-request/issues/705
Received on Wednesday, 2 May 2018 08:02:54 UTC