Loading
Salesforce now sends email only from verified domains. Read More
Nonprofit Cloud
Table of Contents
Select Filters

          No results
          No results
          Here are some search tips

          Check the spelling of your keywords.
          Use more general search terms.
          Select fewer filters to broaden your search.

          Search all of Salesforce Help
          Configure a Column Modal in a Gift Entry Grid Template in Nonprofit

          Configure a Column Modal in a Gift Entry Grid Template in Nonprofit

          Customize the gift entry experience by configuring interactive column modals. You can embed standard field sets or custom Lightning web components (LWC) directly into the grid to capture complex donor details without leaving the primary workflow.

          Required Editions

          REQUIRED EDITIONS
          Available in: Lightning Experience

          Available in: Enterprise, Performance, Unlimited, and Developer Editions with Education Cloud

          Available in: Enterprise, Unlimited, and Developer Editions with Nonprofit Cloud

          User Permissions Needed
          To configure a column modal:

          FundraisingAccess permission set

          OR

          Education Cloud Full Access permission set

          1. In Display Columns, for the column that you want to configure, click Edit column.
          2. Click Modal.
          3. Select Lightning Web Components as the modal type.
            You can use an existing LWC that you created or installed from a managed package. Alternatively, you can select the fields to show by selecting the

            $GiftEntryGrid.FieldsModal

            standard LWC and then adding fields in the Set Fields in Modal section.
          4. Select your Lightning web component as the Lightning Web Component name.
          5. Enter a modal label.
          6. Enter an icon to show for your modal. (our default is: utility:expand_alt).
            The default icon is utility:expand_alt, but you can choose others from the SLDS Icon Library.
          7. Optionally, add an alternate label for the modal.
            If criteria are met to display the alternate, it will appear instead of the Modal Label value.

          Sample Gift Entry Grid Modal Component

          This sample Lightning web component code snippet shows a credit card processor and could be configured as the modal for the Payment Method field.

          REQUIRED EDITIONS
          Available in: Lightning Experience

          Available in: Enterprise, Performance, Unlimited, and Developer Editions with Education Cloud

          Available in: Enterprise, Unlimited, and Developer Editions with Nonprofit Cloud

          giftEntryGridPaymentAuthModal.html

          <template>
              <!--
              Sample Gift Entry Grid Modal Component
              There are no implementation requirements for this component, however the modal portal size is limited.
              -->
              <lightning-card title="Credit Card Authorization">
                  <div class="slds-p-around_medium">
                      <form onsubmit={handleSubmit} class="slds-form">
                          <!-- Row 1: PaymentMethod GiftEntry field -->
                          <lightning-record-edit-form object-api-name="GiftEntry" onsuccess={handleSuccess} class="slds-m-bottom_medium">
                              <div class="slds-grid">
                                  <div class="slds-col slds-size_1-of-1">
                                      <lightning-input-field
                                          field-name="PaymentMethod"
                                          value={paymentMethod}
                                          onchange={handleInputChange}
                                          required
                                      ></lightning-input-field>
                                  </div>
                              </div>
                          </lightning-record-edit-form>
          
                          <!-- Only show credit card fields if needed -->
                          <template if:true={showCreditCardFields}>
                              <!-- Row 2: NameOnCard and CardNumber -->
                              <div class="slds-grid slds-gutters slds-m-bottom_medium">
                                  <div class="slds-col slds-size_1-of-2">
                                      <lightning-input
                                          name="NameOnCard"
                                          label="Name on Card"
                                          value={nameOnCard}
                                          onchange={handleInputChange}
                                          required
                                      ></lightning-input>
                                  </div>
                                  <div class="slds-col slds-size_1-of-2">
                                      <lightning-input
                                          name="CreditCardNumber"
                                          label="Credit Card Number"
                                          value={creditCardNumber}
                                          placeholder="XXXX-XXXX-XXXX-XXXX"
                                          maxlength="19"
                                          inputmode="numeric"
                                          pattern="(?:\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}|\d{3}[-\s]?\d{6}[-\s]?\d{5}|\d{16}|\d{15})"
                                          message-when-pattern-mismatch="Enter a valid credit card number."
                                          onchange={handleInputChange}
                                          required
                                      ></lightning-input>
                                  </div>
                              </div>
                              <!-- Row 3: ExpiryMonth, ExpiryYear, CVV -->
                              <div class="slds-grid slds-gutters">
                                  <div class="slds-col slds-size_1-of-3">
                                      <lightning-input
                                          name="ExpiryMonth"
                                          label="Expiration Month"
                                          value={expiryMonth}
                                          onchange={handleInputChange}
                                          inputmode="numeric"
                                          pattern="\d{2}"
                                          required
                                      ></lightning-input>
                                  </div>
                                  <div class="slds-col slds-size_1-of-3">
                                      <lightning-input
                                          name="ExpiryYear"
                                          label="Expiration Year"
                                          value={expiryYear}
                                          onchange={handleInputChange}
                                          inputmode="numeric"
                                          pattern="\d{2}|\d{4}"
                                          required
                                      ></lightning-input>
                                  </div>
                                  <div class="slds-col slds-size_1-of-3">
                                      <lightning-input
                                          name="Cvv"
                                          label="CVV"
                                          value={cvv}
                                          onchange={handleInputChange}
                                          inputmode="numeric"
                                          pattern="\d{3,4}"
                                          required
                                      ></lightning-input>
                                  </div>
                              </div>
                          </template>
                      </form>
                  </div>
                  <template if:true={showCreditCardFields}>
                      <div class="slds-grid slds-grid_align-end slds-m-top_medium">
                          <lightning-button
                              variant="brand"
                              label="Charge Card"
                              onclick={handleChargeCardClick}
                              class="slds-m-right_none"
                              disabled={isChargeCardDisabled}
                          ></lightning-button>
                      </div>
                  </template>
              </lightning-card>
          </template>
          

          giftEntryGridPaymentAuthModal.js

          import { LightningElement, api, track } from 'lwc';
          
          const CONSTANTS = {
              CREDIT_CARD: 'Credit Card',
              ACH: 'ACH'
          }
          
          /**
           * Sample Gift Entry Grid Modal Component
           */
          export default class giftEntryGridPaymentAuthModal extends LightningElement {
              /**
               * Required input property.
               * Not generally used within a custom component
               */
              @api
              set modalFields(value) {
                  this._modalFields = value || [];
                  this.initializeFields();
              }
              get modalFields() {
                  return this._modalFields;
              }
          
              /**
               * Required input property.
               * Contains all the data for the row.
               */
              @api
              set rowData(value) {
                  this._rowData = value || {};
                  this.initializeFields();
              }
              get rowData() {
                  return this._rowData;
              }
          
          
              // ------------------------------------------------------------
              // Required Exposed API Functions for GiftEntryGrid
              // ------------------------------------------------------------
          
              /**
               * Validates the component fields.
               * @returns {Object} An object with properties for isValid (boolean) and an invalidFields collection with errors
               * - isValid: true if the component fields are valid, false otherwise.
               * - invalidFields: A Set of field names and errors to render
               */
              @api
              validate() {
                  let isValid = true;
                  let invalidFields = new Set();
                  if (!this.paymentMethod) {
                      isValid = false;
                      invalidFields.add('PaymentMethod');
                  }
                  if (this.showCreditCardFields) {
                      if (!this.chargeCardClicked) {
                          isValid = false;
                          invalidFields.add('ChargeCard');
                      }
                      if (!this.creditCardNumber || !this.validateCreditCardNumber()) {
                          isValid = false;
                          invalidFields.add('CreditCardNumber is invalid');
                      }
                      if (!this.nameOnCard) {
                          isValid = false;
                          invalidFields.add('NameOnCard is missing');
                      }
                      if (!this.expiryMonth || !this.validateExpiryMonth()) {
                          isValid = false;
                          invalidFields.add('ExpiryMonth is not valid');
                      }
                      if (!this.expiryYear || !this.validateExpiryYear()) {
                          isValid = false;
                          invalidFields.add('ExpiryYear is not valid');
                      }
                      if (!this.cvv || !this.validateCVV()) {
                          isValid = false;
                          invalidFields.add('CVV is not valid');
                      }
                  }
                  return { isValid, invalidFields };
              }
          
              /**
               * Returns values to be saved to the row. These are directly applied to the rowData object within the Grid
               * Properties in this object do not need to be actual GiftEntry fields. Dummy properties are allowed, but 
               * they will not persist to the GiftEntry row when the record is saved.
               * @returns {Object} An object with the values that represent GiftEntry fields.
               */
              @api
              getComponentValues() {
                  let result = {}
                  result['PaymentMethod'] = this.paymentMethod;
                  if (this.showCreditCardFields) {
                      result['Last4'] = this.creditCardNumber ? this.creditCardNumber.slice(-4) : null;
                      result['ExpiryMonth'] = this.expiryMonth;
                      result['ExpiryYear'] = this.expiryYear;
                      result['CCAuthCode__c'] = this.generateRandomString(16);
                      result['NameOnCard__c'] = this.nameOnCard;
                      result['Card_CVV__c'] = this.cvv;
                      result['GatewayTransactionFee__c'] = 0.12345;
                      result['GatewayReference__c'] = this.creditCardNumber;
                  } else {
                      result['Last4'] = null;
                      result['ExpiryMonth'] = null;
                      result['ExpiryYear'] = null;
                      result['CCAuthCode__c'] = null;
                      result['NameOnCard__c'] = null;
                      result['Card_CVV__c'] = null;
                      result['GatewayTransactionFee__c'] = null;
                      result['GatewayReference__c'] = null;
                  }
                  return result;
              }
          
              // ------------------------------------------------------------
              // Everything below this is generic custom code to illustrate the component behavior
              // ------------------------------------------------------------
              _modalFields = [];
              _rowData = {};
          
              @track paymentMethod = CONSTANTS.CREDIT_CARD;
              @track creditCardNumber = '';
              @track nameOnCard = '';
              @track expiryMonth = '';
              @track expiryYear = '';
              @track cvv = '';
              @track gatewaytransactionfee = null;
              @track gatewayreference = null;
              @track chargeCardClicked = false;
          
              connectedCallback() {
                  this.initializeFields();
              }
          
              initializeFields() {
                  this.paymentMethod = this._rowData['PaymentMethod'] || '';
                  this.creditCardNumber = (this._rowData['Last4'] ? "****-****-****-" + this._rowData['Last4'] : '');
                  if (this._rowData['NameOnCard__c']) {
                      this.nameOnCard = this._rowData['NameOnCard__c'];
                  } else if (this._rowData['FirstName'] && this._rowData['LastName']) {
                      this.nameOnCard = this._rowData['FirstName'] + ' ' + this._rowData['LastName'];
                  } else {
                      this.nameOnCard = '';
                  }
                  this.expiryMonth = this._rowData['ExpiryMonth'] || '';
                  this.expiryYear = this._rowData['ExpiryYear'] || '';
                  this.cvv = this._rowData['Card_CVV__c'] || '';
                  this.gatewayTransactionFee = this._rowData['GatewayTransactionFee__c'] || null;
                  this.gatewayReference = this._rowData['GatewayReference__c'] || null;
              }
          
              handleInputChange(event) {
                  let fieldName = event?.target?.fieldName || event?.target?.name;
                  if (fieldName) {
                      fieldName = fieldName.charAt(0).toLowerCase() + fieldName.slice(1);
                  }
          
                  const fieldValue = event?.target?.value;
                  this[fieldName] = fieldValue;
                  if (fieldName === 'paymentMethod') {
                      if (!this.showCreditCardFields) {
                          this.creditCardNumber = '';
                          this.nameOnCard = '';
                          this.expiryMonth = '';
                          this.expiryYear = '';
                          this.cvv = '';
                      }
                  }
                  if (fieldName === 'creditCardNumber') {
                      this.validateCreditCardNumber();
                  }
                  if (fieldName === 'expiryMonth') {
                      this.validateExpiryMonth();
                  }
                  if (fieldName === 'expiryYear') {
                      this.validateExpiryYear();
                  }
              }
          
              handleChargeCardClick() {
                  this.chargeCardClicked = true;
              }
          
              canChargeCard() {
                  if (this.chargeCardClicked) return false;
                  if (!this.showCreditCardFields) return false;
                  return (
                      !!this.creditCardNumber && this.validateCreditCardNumber() &&
                      !!this.nameOnCard &&
                      !!this.expiryMonth && this.validateExpiryMonth() &&
                      !!this.expiryYear && this.validateExpiryYear() &&
                      !!this.cvv && this.validateCVV()
                  );
              }
          
              validateCreditCardNumber() {
                  const regex = /^(?:\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}|\d{3}[-\s]?\d{6}[-\s]?\d{5}|\d{16}|\d{15})$/;
                  return this.creditCardNumber === '' || regex.test(this.creditCardNumber);
              }
          
              validateExpiryMonth() {
                  const month = parseInt(this.expiryMonth, 10);
                  return this.expiryMonth === '' || (month >= 1 && month <= 12);
              }
          
              validateExpiryYear() {
                  let year = parseInt(this.expiryYear, 10);
                  year = year < 99 ? 2000 + year : year;
                  const currentYear = new Date().getFullYear();
                  return this.expiryYear === '' || (year >= currentYear && year <= currentYear + 10);
              }
          
              validateCVV() {
                  return this.cvv === '' || /^\d{2}|\d{4}/.test(this.cvv);
              }
          
              generateRandomString(length) {
                  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
                  let result = '';
                  for (let i = 0; i < length; i++) {
                      result += chars.charAt(Math.floor(Math.random() * chars.length));
                  }
                  return result;
              }
          
              get showCreditCardFields() {
                  return this.paymentMethod === CONSTANTS.CREDIT_CARD || this.paymentMethod === CONSTANTS.ACH;
              }
          
              get minExpiryYear() {
                  return new Date().getFullYear();
              }
          
              get maxExpiryYear() {
                  return new Date().getFullYear() + 10;
              }
          
              get isChargeCardDisabled() {
                  return !this.canChargeCard();
              }
          }
          
           
          Loading
          Salesforce Help | Article