Bug 1440499 - Add payerName/Email/Phone contact picker. r?MattN draft
authorSam Foster <sfoster@mozilla.com>
Thu, 01 Mar 2018 11:48:16 -0800
changeset 762279 ca25c8f9b3e2fd4ba9a12fdcca984889b4e5fb69
parent 762278 4f1b33b96dfae45b5c1cccb17d707c6915edef39
push id101115
push userbmo:sfoster@mozilla.com
push dateThu, 01 Mar 2018 23:33:37 +0000
reviewersMattN
bugs1440499
milestone60.0a1
Bug 1440499 - Add payerName/Email/Phone contact picker. r?MattN * WIP, tests to ensure the paymentOptions values propagate to the picker underway * Add a field-names attribute to address-picker options, populated from the request paymentOptions * Initial/placeholder CSS to selectively render address fields MozReview-Commit-ID: Br8i5MVyeQ3
toolkit/components/payments/res/components/address-option.css
toolkit/components/payments/res/components/address-option.js
toolkit/components/payments/res/containers/address-picker.js
toolkit/components/payments/res/containers/payment-dialog.js
toolkit/components/payments/res/paymentRequest.xhtml
--- a/toolkit/components/payments/res/components/address-option.css
+++ b/toolkit/components/payments/res/components/address-option.css
@@ -12,17 +12,17 @@ address-option {
 
 rich-select[open] > .rich-select-popup-box > address-option {
   grid-template-areas:
     "name           name          "
     "street-address street-address"
     "email          tel           ";
 }
 
-address-option[hide-address] {
+address-picker.payer-related address-option {
   grid-template-areas:
     "name name"
     "tel  email";
 }
 
 address-option > .name {
   grid-area: name;
 }
@@ -34,20 +34,28 @@ address-option > .street-address {
 address-option > .email {
   grid-area: email;
 }
 
 address-option > .tel {
   grid-area: tel;
 }
 
+/* Hide all the fields by default, and enable them explicitly for each format case */
 address-option > .name,
 address-option > .street-address,
 address-option > .email,
 address-option > .tel {
   white-space: nowrap;
+  display: none;
 }
 
-address-option[hide-address] > .street-address,
-.rich-select-selected-clone:not([hide-address]) > .email,
-.rich-select-selected-clone:not([hide-address]) > .tel {
-  display: none;
+address-option:not([address-fields]) > .name,
+address-option:not([address-fields]) > .street-address {
+  display: inline-block;
 }
+
+address-option[address-fields~='name'] > .name,
+address-option[address-fields~='email'] > .email,
+address-option[address-fields~='tel'] > .tel {
+  display: inline-block;
+}
+
--- a/toolkit/components/payments/res/components/address-option.js
+++ b/toolkit/components/payments/res/components/address-option.js
@@ -21,17 +21,17 @@
 /* global ObservedPropertiesMixin, RichOption */
 
 class AddressOption extends ObservedPropertiesMixin(RichOption) {
   static get observedAttributes() {
     return RichOption.observedAttributes.concat([
       "address-level1",
       "address-level2",
       "country",
-      "hide-address",
+      "address-fields",
       "email",
       "guid",
       "name",
       "postal-code",
       "street-address",
       "tel",
     ]);
   }
--- a/toolkit/components/payments/res/containers/address-picker.js
+++ b/toolkit/components/payments/res/containers/address-picker.js
@@ -21,28 +21,51 @@ class AddressPicker extends PaymentState
 
   connectedCallback() {
     this.appendChild(this.dropdown);
     super.connectedCallback();
   }
 
   render(state) {
     let {savedAddresses} = state;
-    let hideAddress = this.hasAttribute("hide-address"); // TODO
+    let payerRelated = this.classList.contains("payer-related");
+    let fieldNames = new Set(["name", "tel", "email"]);
+    let useFieldNames = false;
+
+    if (payerRelated) {
+      let paymentOptions = state.request.paymentOptions;
+      fieldNames.clear();
+      if (paymentOptions.requestPayerName) {
+        fieldNames.add("name");
+      }
+      if (paymentOptions.requestPayerEmail) {
+        fieldNames.add("email");
+      }
+      if (paymentOptions.requestPayerPhone) {
+        fieldNames.add("tel");
+      }
+      useFieldNames = !!fieldNames.size;
+    }
+
     let desiredOptions = [];
     for (let [guid, address] of Object.entries(savedAddresses)) {
       let optionEl = this.dropdown.getOptionByValue(guid);
       if (!optionEl) {
         optionEl = document.createElement("address-option");
         optionEl.value = guid;
       }
+
       for (let [key, val] of Object.entries(address)) {
         optionEl.setAttribute(key, val);
       }
-      optionEl.hideAddress = hideAddress;
+      if (useFieldNames && fieldNames.size) {
+        optionEl.setAttribute("address-fields", [...fieldNames].join(" "));
+      } else {
+        optionEl.removeAttribute("address-fields");
+      }
       desiredOptions.push(optionEl);
     }
     let el = null;
     while ((el = this.dropdown.popupBox.querySelector(":scope > address-option"))) {
       el.remove();
     }
     for (let option of desiredOptions) {
       this.dropdown.popupBox.appendChild(option);
--- a/toolkit/components/payments/res/containers/payment-dialog.js
+++ b/toolkit/components/payments/res/containers/payment-dialog.js
@@ -29,16 +29,18 @@ class PaymentDialog extends PaymentState
 
     this._viewAllButton = contents.querySelector("#view-all");
     this._viewAllButton.addEventListener("click", this);
 
     this._orderDetailsOverlay = contents.querySelector("#order-details-overlay");
     this._shippingTypeLabel = contents.querySelector("#shipping-type-label");
     this._shippingRelatedEls = contents.querySelectorAll(".shipping-related");
     this._payerRelatedEls = contents.querySelectorAll(".payer-related");
+    this._payerAddressPicker = contents.querySelector("address-picker.payer-related");
+
     this._errorText = contents.querySelector("#error-text");
 
     this._disabledOverlay = contents.getElementById("disabled-overlay");
 
     this.appendChild(contents);
 
     super.connectedCallback();
   }
@@ -156,17 +158,16 @@ class PaymentDialog extends PaymentState
 
     // Ensure `selectedPayerAddress` never refers to a deleted address and refers
     // to an address if one exists.
     if (!savedAddresses[selectedPayerAddress]) {
       this.requestStore.setState({
         selectedPayerAddress: Object.keys(savedAddresses)[0] || null,
       });
     }
-
   }
 
   _renderPayButton(state) {
     this._payButton.disabled = state.changesPrevented;
     switch (state.completionState) {
       case "initial":
       case "processing":
         break;
@@ -203,24 +204,29 @@ class PaymentDialog extends PaymentState
 
     let totalItem = paymentDetails.totalItem;
     let totalAmountEl = this.querySelector("#total > currency-amount");
     totalAmountEl.value = totalItem.amount.value;
     totalAmountEl.currency = totalItem.amount.currency;
 
     this._orderDetailsOverlay.hidden = !state.orderDetailsShowing;
     this._errorText.textContent = paymentDetails.error;
+
     let paymentOptions = request.paymentOptions;
     for (let element of this._shippingRelatedEls) {
       element.hidden = !paymentOptions.requestShipping;
     }
-    let payerRequested = paymentOptions.requestPayerName || paymentOptions.requestPayerEmail || paymentOptions.requestPayerPhone;
+
+    let payerRequested = paymentOptions.requestPayerName ||
+                         paymentOptions.requestPayerEmail ||
+                         paymentOptions.requestPayerPhone;
     for (let element of this._payerRelatedEls) {
       element.hidden = !payerRequested;
     }
+
     let shippingType = paymentOptions.shippingType || "shipping";
     this._shippingTypeLabel.querySelector("label").textContent =
       this._shippingTypeLabel.dataset[shippingType + "AddressLabel"];
 
     this._renderPayButton(state);
 
     let {
       changesPrevented,
--- a/toolkit/components/payments/res/paymentRequest.xhtml
+++ b/toolkit/components/payments/res/paymentRequest.xhtml
@@ -78,17 +78,16 @@
           <address-picker class="shipping-related" selected-state-key="selectedShippingAddress"></address-picker>
           <div class="shipping-related"><label>&shippingOptionsLabel;</label></div>
           <shipping-option-picker class="shipping-related"></shipping-option-picker>
           <div><label>&paymentMethodsLabel;</label></div>
           <payment-method-picker selected-state-key="selectedPaymentCard"></payment-method-picker>
 
           <div class="payer-related"><label>&payerLabel;</label></div>
           <address-picker class="payer-related"
-                          hide-address=""
                           selected-state-key="selectedPayerAddress"></address-picker>
         </section>
 
         <footer id="controls-container">
           <button id="cancel">&cancelPaymentButton.label;</button>
           <button id="pay"
                   data-initial-label="&approvePaymentButton.label;"
                   data-processing-label="&processingPaymentButton.label;"></button>