- 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