@internetarchive/donation-form 1.0.3-alpha-webdev7960.1 → 1.0.3-webdev-8122.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -661
- package/README.md +115 -115
- package/dist/demo/braintree-endpoint-manager.js.map +1 -1
- package/dist/demo/demo-analytics-handler.js.map +1 -1
- package/dist/demo/submit-form-with.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/src/braintree-manager/braintree-interfaces.js.map +1 -1
- package/dist/src/braintree-manager/braintree-manager.js.map +1 -1
- package/dist/src/braintree-manager/payment-clients.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay-interface.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-delegate.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-interface.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-manager.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/credit-card/credit-card-interface.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/credit-card/credit-card.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/credit-card/hosted-field-configuration.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/credit-card/hosted-field-container.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/google-pay-interface.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/google-pay.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/paypal/paypal-button-datasource.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/paypal/paypal-interface.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/paypal/paypal.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/venmo-interface.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers/venmo.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers-interface.js.map +1 -1
- package/dist/src/braintree-manager/payment-providers.js.map +1 -1
- package/dist/src/donation-form-controller.js +123 -123
- package/dist/src/donation-form-controller.js.map +1 -1
- package/dist/src/donation-form-error.js.map +1 -1
- package/dist/src/donation-form.js +107 -107
- package/dist/src/donation-form.js.map +1 -1
- package/dist/src/form-elements/badged-input.js +47 -47
- package/dist/src/form-elements/badged-input.js.map +1 -1
- package/dist/src/form-elements/contact-form/autocomplete-field-options.js.map +1 -1
- package/dist/src/form-elements/contact-form/contact-form.js +159 -157
- package/dist/src/form-elements/contact-form/contact-form.js.map +1 -1
- package/dist/src/form-elements/contact-form/countries.js.map +1 -1
- package/dist/src/form-elements/header/donation-form-header.js +14 -14
- package/dist/src/form-elements/header/donation-form-header.js.map +1 -1
- package/dist/src/form-elements/header/donation-summary.js +15 -15
- package/dist/src/form-elements/header/donation-summary.js.map +1 -1
- package/dist/src/form-elements/payment-selector.js +164 -164
- package/dist/src/form-elements/payment-selector.js.map +1 -1
- package/dist/src/form-elements/total-amount.js +16 -16
- package/dist/src/form-elements/total-amount.js.map +1 -1
- package/dist/src/modals/confirm-donation-modal-content.js +51 -51
- package/dist/src/modals/confirm-donation-modal-content.js.map +1 -1
- package/dist/src/modals/error-modal-content.js +22 -22
- package/dist/src/modals/error-modal-content.js.map +1 -1
- package/dist/src/modals/upsell-modal-content.js +182 -182
- package/dist/src/modals/upsell-modal-content.js.map +1 -1
- package/dist/src/payment-flow-handlers/donation-flow-modal-manager.js +20 -20
- package/dist/src/payment-flow-handlers/donation-flow-modal-manager.js.map +1 -1
- package/dist/src/payment-flow-handlers/handlers/applepay-flow-handler.js.map +1 -1
- package/dist/src/payment-flow-handlers/handlers/creditcard-flow-handler.js.map +1 -1
- package/dist/src/payment-flow-handlers/handlers/googlepay-flow-handler.js +2 -0
- package/dist/src/payment-flow-handlers/handlers/googlepay-flow-handler.js.map +1 -1
- package/dist/src/payment-flow-handlers/handlers/paypal-flow-handler.js +2 -0
- package/dist/src/payment-flow-handlers/handlers/paypal-flow-handler.js.map +1 -1
- package/dist/src/payment-flow-handlers/handlers/venmo-flow-handler.js.map +1 -1
- package/dist/src/payment-flow-handlers/handlers/venmo-restoration-state-handler.js.map +1 -1
- package/dist/src/payment-flow-handlers/payment-flow-handlers.js.map +1 -1
- package/dist/src/recaptcha-manager/recaptcha-manager.js.map +1 -1
- package/dist/src/util/promisedSleep.js.map +1 -1
- package/dist/test/helpers/fillInContactForm.js.map +1 -1
- package/dist/test/mocks/flow-handlers/individual-handlers/mock-applepay-flow-handler.js.map +1 -1
- package/dist/test/mocks/flow-handlers/individual-handlers/mock-creditcard-flow-handler.js.map +1 -1
- package/dist/test/mocks/flow-handlers/individual-handlers/mock-googlepay-flow-handler.js.map +1 -1
- package/dist/test/mocks/flow-handlers/individual-handlers/mock-paypal-flow-handler.js.map +1 -1
- package/dist/test/mocks/flow-handlers/individual-handlers/mock-venmo-flow-handler.js.map +1 -1
- package/dist/test/mocks/flow-handlers/mock-payment-flow-handlers.js.map +1 -1
- package/dist/test/mocks/mock-braintree-manager.js.map +1 -1
- package/dist/test/mocks/mock-donation-info.js.map +1 -1
- package/dist/test/mocks/mock-endpoint-manager.js.map +1 -1
- package/dist/test/mocks/mock-hosted-fields-config.js.map +1 -1
- package/dist/test/mocks/mock-hosted-fields-container.js.map +1 -1
- package/dist/test/mocks/mock-lazy-loader.js.map +1 -1
- package/dist/test/mocks/mock-modal-manager.js.map +1 -1
- package/dist/test/mocks/mock-payment-clients.js.map +1 -1
- package/dist/test/mocks/mock-paypal-button-renderer.js.map +1 -1
- package/dist/test/mocks/mock-recaptcha-manager.js.map +1 -1
- package/dist/test/mocks/models/mock-billing-info.js +2 -0
- package/dist/test/mocks/models/mock-billing-info.js.map +1 -1
- package/dist/test/mocks/models/mock-custom-fields.js.map +1 -1
- package/dist/test/mocks/models/mock-customer-info.js.map +1 -1
- package/dist/test/mocks/models/mock-donation-request.js.map +1 -1
- package/dist/test/mocks/models/mock-success-response.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-applepay-client.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-applepay-payment.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-applepay-paymentauthorizedevent.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-applepay-session.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-applepay-sessionmanager.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-applepay-validatemerchantevent.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-braintree-client.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-data-collector.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-googlepay-client.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-googlepay-library.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-grecaptcha.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-hostedfields-client.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-hostedfieldstateobject-generator.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-hostedfieldtokenizepayload.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-paypal-client.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-paypal-library.js.map +1 -1
- package/dist/test/mocks/payment-clients/mock-venmo-client.js.map +1 -1
- package/dist/test/mocks/payment-providers/individual-providers/mock-applepay-datasource-delegate.js.map +1 -1
- package/dist/test/mocks/payment-providers/individual-providers/mock-applepay-handler.js.map +1 -1
- package/dist/test/mocks/payment-providers/individual-providers/mock-creditcard-handler.js.map +1 -1
- package/dist/test/mocks/payment-providers/individual-providers/mock-googlepay-handler.js.map +1 -1
- package/dist/test/mocks/payment-providers/individual-providers/mock-paypal-button-datasource-delegate.js.map +1 -1
- package/dist/test/mocks/payment-providers/individual-providers/mock-paypal-button-datasource.js.map +1 -1
- package/dist/test/mocks/payment-providers/individual-providers/mock-paypal-handler.js.map +1 -1
- package/dist/test/mocks/payment-providers/individual-providers/mock-venmo-handler.js.map +1 -1
- package/dist/test/mocks/payment-providers/mock-payment-providers.js.map +1 -1
- package/dist/test/tests/braintree-manager.test.js.map +1 -1
- package/dist/test/tests/donation-form-controller.test.js +39 -39
- package/dist/test/tests/donation-form-controller.test.js.map +1 -1
- package/dist/test/tests/donation-form.test.js +4 -4
- package/dist/test/tests/donation-form.test.js.map +1 -1
- package/dist/test/tests/flow-handlers/donation-flow-modal-manager.test.js +16 -14
- package/dist/test/tests/flow-handlers/donation-flow-modal-manager.test.js.map +1 -1
- package/dist/test/tests/form-elements/donation-summary.test.js.map +1 -1
- package/dist/test/tests/form-elements/payment-selector.test.js.map +1 -1
- package/dist/test/tests/modals/error-modal-content.test.js +2 -2
- package/dist/test/tests/modals/error-modal-content.test.js.map +1 -1
- package/dist/test/tests/modals/upsell-modal-content.test.js +31 -31
- package/dist/test/tests/modals/upsell-modal-content.test.js.map +1 -1
- package/dist/test/tests/models/donation-payment-info.test.js.map +1 -1
- package/dist/test/tests/payment-clients.test.js.map +1 -1
- package/dist/test/tests/payment-providers/applepay-sessiondatasource.test.js.map +1 -1
- package/dist/test/tests/payment-providers/applepay-sessionmanager.test.js.map +1 -1
- package/dist/test/tests/payment-providers/applepay.test.js.map +1 -1
- package/dist/test/tests/payment-providers/creditcard.test.js.map +1 -1
- package/dist/test/tests/payment-providers/googlepay.test.js.map +1 -1
- package/dist/test/tests/payment-providers/payment-providers.test.js.map +1 -1
- package/dist/test/tests/payment-providers/paypal-button-datasource.test.js.map +1 -1
- package/dist/test/tests/payment-providers/paypal.test.js.map +1 -1
- package/dist/test/tests/payment-providers/venmo.test.js.map +1 -1
- package/dist/test/tests/recaptcha-manager.test.js.map +1 -1
- package/package.json +107 -107
- package/src/@types/analytics-handler/index.d.ts +8 -8
- package/src/@types/braintree-web/LICENSE +21 -21
- package/src/@types/braintree-web/index.d.ts +93 -93
- package/src/@types/braintree-web/modules/american-express.d.ts +50 -50
- package/src/@types/braintree-web/modules/apple-pay.d.ts +213 -213
- package/src/@types/braintree-web/modules/client.d.ts +103 -103
- package/src/@types/braintree-web/modules/core.d.ts +34 -34
- package/src/@types/braintree-web/modules/data-collector.d.ts +13 -13
- package/src/@types/braintree-web/modules/google-payment.d.ts +269 -269
- package/src/@types/braintree-web/modules/hosted-fields.d.ts +366 -366
- package/src/@types/braintree-web/modules/paypal-checkout.d.ts +262 -262
- package/src/@types/braintree-web/modules/paypal.d.ts +177 -177
- package/src/@types/braintree-web/modules/three-d-secure.d.ts +141 -141
- package/src/@types/braintree-web/modules/unionpay.d.ts +224 -224
- package/src/@types/braintree-web/modules/us-bank-account.d.ts +81 -81
- package/src/@types/braintree-web/modules/venmo.d.ts +110 -110
- package/src/@types/braintree-web/package.json +64 -64
- package/src/@types/paypal-checkout-components/LICENSE +21 -21
- package/src/@types/paypal-checkout-components/index.d.ts +67 -67
- package/src/@types/paypal-checkout-components/modules/button.d.ts +50 -50
- package/src/@types/paypal-checkout-components/modules/callback-data.d.ts +244 -244
- package/src/@types/paypal-checkout-components/modules/configuration.d.ts +114 -114
- package/src/@types/paypal-checkout-components/package.json +58 -58
- package/src/braintree-manager/braintree-interfaces.ts +172 -172
- package/src/braintree-manager/braintree-manager.ts +281 -281
- package/src/braintree-manager/payment-clients.ts +146 -146
- package/src/braintree-manager/payment-providers/apple-pay/apple-pay-interface.ts +13 -13
- package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-delegate.ts +8 -8
- package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-interface.ts +10 -10
- package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource.ts +119 -119
- package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-manager.ts +21 -21
- package/src/braintree-manager/payment-providers/apple-pay/apple-pay.ts +97 -97
- package/src/braintree-manager/payment-providers/credit-card/credit-card-interface.ts +21 -21
- package/src/braintree-manager/payment-providers/credit-card/credit-card.ts +130 -130
- package/src/braintree-manager/payment-providers/credit-card/hosted-field-configuration.ts +19 -19
- package/src/braintree-manager/payment-providers/credit-card/hosted-field-container.ts +85 -85
- package/src/braintree-manager/payment-providers/google-pay-interface.ts +8 -8
- package/src/braintree-manager/payment-providers/google-pay.ts +59 -59
- package/src/braintree-manager/payment-providers/paypal/paypal-button-datasource.ts +218 -218
- package/src/braintree-manager/payment-providers/paypal/paypal-interface.ts +13 -13
- package/src/braintree-manager/payment-providers/paypal/paypal.ts +78 -78
- package/src/braintree-manager/payment-providers/venmo-interface.ts +8 -8
- package/src/braintree-manager/payment-providers/venmo.ts +67 -67
- package/src/braintree-manager/payment-providers-interface.ts +25 -25
- package/src/braintree-manager/payment-providers.ts +147 -147
- package/src/donation-form-controller.ts +623 -623
- package/src/donation-form-error.ts +6 -6
- package/src/donation-form.ts +576 -576
- package/src/form-elements/badged-input.ts +109 -109
- package/src/form-elements/contact-form/autocomplete-field-options.ts +63 -63
- package/src/form-elements/contact-form/contact-form.ts +436 -434
- package/src/form-elements/contact-form/countries.ts +252 -252
- package/src/form-elements/header/donation-form-header.ts +98 -98
- package/src/form-elements/header/donation-summary.ts +61 -61
- package/src/form-elements/payment-selector.ts +365 -365
- package/src/form-elements/total-amount.ts +46 -46
- package/src/modals/confirm-donation-modal-content.ts +168 -168
- package/src/modals/error-modal-content.ts +48 -48
- package/src/modals/upsell-modal-content.ts +284 -284
- package/src/payment-flow-handlers/donation-flow-modal-manager.ts +439 -439
- package/src/payment-flow-handlers/handlers/applepay-flow-handler.ts +109 -109
- package/src/payment-flow-handlers/handlers/creditcard-flow-handler.ts +232 -232
- package/src/payment-flow-handlers/handlers/googlepay-flow-handler.ts +113 -111
- package/src/payment-flow-handlers/handlers/paypal-flow-handler.ts +333 -331
- package/src/payment-flow-handlers/handlers/venmo-flow-handler.ts +119 -119
- package/src/payment-flow-handlers/handlers/venmo-restoration-state-handler.ts +127 -127
- package/src/payment-flow-handlers/payment-flow-handlers.ts +218 -218
- package/src/recaptcha-manager/recaptcha-manager.ts +123 -123
- package/src/util/promisedSleep.ts +3 -3
package/src/donation-form.ts
CHANGED
|
@@ -1,576 +1,576 @@
|
|
|
1
|
-
import { LitElement, html, css, CSSResult, TemplateResult, PropertyValues } from 'lit';
|
|
2
|
-
import { customElement, property, query } from 'lit/decorators.js';
|
|
3
|
-
|
|
4
|
-
import lockImg from '@internetarchive/icon-lock/index.js';
|
|
5
|
-
|
|
6
|
-
// we have to import the registered component independently from the definition below
|
|
7
|
-
// because inside each of these files, we're registering the custom element inside
|
|
8
|
-
// these files and by simply importing the class name, you lose that behavior
|
|
9
|
-
// See https://github.com/microsoft/TypeScript/issues/9191 for more discussion
|
|
10
|
-
import './form-elements/payment-selector';
|
|
11
|
-
import './form-elements/header/donation-form-header';
|
|
12
|
-
|
|
13
|
-
import { DonationFormHeader } from './form-elements/header/donation-form-header';
|
|
14
|
-
import { PaymentSelector } from './form-elements/payment-selector';
|
|
15
|
-
|
|
16
|
-
import { BraintreeManagerInterface } from './braintree-manager/braintree-interfaces';
|
|
17
|
-
|
|
18
|
-
import {
|
|
19
|
-
DonationRequest,
|
|
20
|
-
DonationPaymentInfo,
|
|
21
|
-
PaymentProvider,
|
|
22
|
-
DonorContactInfo,
|
|
23
|
-
DonationType,
|
|
24
|
-
defaultDonationAmounts,
|
|
25
|
-
} from '@internetarchive/donation-form-data-models';
|
|
26
|
-
|
|
27
|
-
import { PaymentFlowHandlersInterface } from './payment-flow-handlers/payment-flow-handlers';
|
|
28
|
-
|
|
29
|
-
import {
|
|
30
|
-
EditDonationAmountSelectionLayout,
|
|
31
|
-
EditDonationFrequencySelectionMode,
|
|
32
|
-
} from '@internetarchive/donation-form-edit-donation';
|
|
33
|
-
|
|
34
|
-
import '@internetarchive/donation-form-section';
|
|
35
|
-
import {
|
|
36
|
-
DonationFormSection,
|
|
37
|
-
DonationFormSectionBadgeMode,
|
|
38
|
-
} from '@internetarchive/donation-form-section';
|
|
39
|
-
import { UpsellModalCTAMode } from './modals/upsell-modal-content';
|
|
40
|
-
import { ContactForm } from './form-elements/contact-form/contact-form';
|
|
41
|
-
import './form-elements/total-amount';
|
|
42
|
-
|
|
43
|
-
@customElement('donation-form')
|
|
44
|
-
export class DonationForm extends LitElement {
|
|
45
|
-
@property({ type: Object }) braintreeManager: BraintreeManagerInterface | undefined;
|
|
46
|
-
|
|
47
|
-
@property({ type: Object }) paymentFlowHandlers: PaymentFlowHandlersInterface | undefined;
|
|
48
|
-
|
|
49
|
-
@property({ type: Object }) donationRequest: DonationRequest | undefined;
|
|
50
|
-
|
|
51
|
-
@property({ type: Object }) donationInfo?: DonationPaymentInfo;
|
|
52
|
-
|
|
53
|
-
@property({ type: Object }) contactForm?: ContactForm;
|
|
54
|
-
|
|
55
|
-
@property({ type: Array }) amountOptions: number[] = defaultDonationAmounts;
|
|
56
|
-
|
|
57
|
-
@property({ type: String }) amountSelectionLayout: EditDonationAmountSelectionLayout =
|
|
58
|
-
EditDonationAmountSelectionLayout.MultiLine;
|
|
59
|
-
|
|
60
|
-
@property({ type: String }) frequencySelectionMode: EditDonationFrequencySelectionMode =
|
|
61
|
-
EditDonationFrequencySelectionMode.Button;
|
|
62
|
-
|
|
63
|
-
@property({ type: Boolean }) private creditCardVisible = false;
|
|
64
|
-
|
|
65
|
-
@property({ type: Boolean }) private contactFormVisible = false;
|
|
66
|
-
|
|
67
|
-
@property({ type: Boolean }) private donationInfoValid = true;
|
|
68
|
-
|
|
69
|
-
@property({ type: String }) private selectedPaymentProvider?: PaymentProvider;
|
|
70
|
-
|
|
71
|
-
@query('#contactFormSection') contactFormSection?: DonationFormSection;
|
|
72
|
-
|
|
73
|
-
@query('donation-form-header') donationFormHeader!: DonationFormHeader;
|
|
74
|
-
|
|
75
|
-
@query('payment-selector') paymentSelector!: PaymentSelector;
|
|
76
|
-
|
|
77
|
-
private paypalButtonNeedsRender = true;
|
|
78
|
-
|
|
79
|
-
/** @inheritdoc */
|
|
80
|
-
render(): TemplateResult {
|
|
81
|
-
return html`
|
|
82
|
-
<donation-form-header
|
|
83
|
-
.amountOptions=${this.amountOptions}
|
|
84
|
-
.amountSelectionLayout=${this.amountSelectionLayout}
|
|
85
|
-
.frequencySelectionMode=${this.frequencySelectionMode}
|
|
86
|
-
@donationInfoChanged=${this.donationInfoChanged}
|
|
87
|
-
@editDonationError=${this.editDonationError}
|
|
88
|
-
>
|
|
89
|
-
</donation-form-header>
|
|
90
|
-
|
|
91
|
-
<donation-form-section
|
|
92
|
-
.badgeMode=${DonationFormSectionBadgeMode.HideBadgeLeaveSpacing}
|
|
93
|
-
id="total-amount-section"
|
|
94
|
-
>
|
|
95
|
-
<donation-form-total-amount .donationInfo=${this.donationInfo}>
|
|
96
|
-
</donation-form-total-amount>
|
|
97
|
-
</donation-form-section>
|
|
98
|
-
|
|
99
|
-
<donation-form-section
|
|
100
|
-
.sectionBadge=${this.paymentSelectorNumberingStart}
|
|
101
|
-
headline="Choose a payment method"
|
|
102
|
-
>
|
|
103
|
-
<payment-selector
|
|
104
|
-
.paymentProviders=${this.braintreeManager?.paymentProviders}
|
|
105
|
-
@firstUpdated=${this.paymentSelectorFirstUpdated}
|
|
106
|
-
@creditCardSelected=${this.creditCardSelected}
|
|
107
|
-
@venmoSelected=${this.venmoSelected}
|
|
108
|
-
@applePaySelected=${this.applePaySelected}
|
|
109
|
-
@googlePaySelected=${this.googlePaySelected}
|
|
110
|
-
@paypalBlockerSelected=${this.paypalBlockerSelected}
|
|
111
|
-
@resetPaymentMethod=${async () => {
|
|
112
|
-
this.selectedPaymentProvider = undefined;
|
|
113
|
-
this.contactFormVisible = false;
|
|
114
|
-
this.requestUpdate();
|
|
115
|
-
}}
|
|
116
|
-
tabindex="0"
|
|
117
|
-
>
|
|
118
|
-
<slot name="paypal-button" slot="paypal-button"></slot>
|
|
119
|
-
</payment-selector>
|
|
120
|
-
</donation-form-section>
|
|
121
|
-
|
|
122
|
-
<div class="contact-form-section ${this.contactFormVisible ? '' : 'hidden'}">
|
|
123
|
-
${this.contactFormSectionTemplate}
|
|
124
|
-
</div>
|
|
125
|
-
<slot name="recaptcha"></slot>
|
|
126
|
-
`;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
async showConfirmationModalDev(options: {
|
|
130
|
-
donationType: DonationType;
|
|
131
|
-
amount: number;
|
|
132
|
-
currencyType: string;
|
|
133
|
-
cancelDonationCB: Function;
|
|
134
|
-
confirmDonationCB: Function;
|
|
135
|
-
}): Promise<void> {
|
|
136
|
-
this.paymentFlowHandlers?.showConfirmationStepModal(options);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* This is a developer convenience method that allows us to show the upsell modal without going
|
|
141
|
-
* through the purchasing flow. If it's showing the PayPal button, it will trigger
|
|
142
|
-
* the PayPal button render
|
|
143
|
-
*
|
|
144
|
-
* @param {{
|
|
145
|
-
* oneTimeAmount: number;
|
|
146
|
-
* ctaMode?: UpsellModalCTAMode;
|
|
147
|
-
* yesSelected?: (amount: number) => void;
|
|
148
|
-
* noSelected?: () => void;
|
|
149
|
-
* amountChanged?: (amount: number) => void;
|
|
150
|
-
* userClosedModalCallback?: () => void;
|
|
151
|
-
* }} options
|
|
152
|
-
* @returns {Promise<void>}
|
|
153
|
-
* @memberof DonationForm
|
|
154
|
-
*/
|
|
155
|
-
async showUpsellModalDev(options: {
|
|
156
|
-
oneTimeAmount: number;
|
|
157
|
-
ctaMode?: UpsellModalCTAMode;
|
|
158
|
-
yesSelected?: (amount: number) => void;
|
|
159
|
-
noSelected?: () => void;
|
|
160
|
-
amountChanged?: (amount: number) => void;
|
|
161
|
-
userClosedModalCallback?: () => void;
|
|
162
|
-
}): Promise<void> {
|
|
163
|
-
this.paymentFlowHandlers?.showUpsellModal(options);
|
|
164
|
-
|
|
165
|
-
if (options.ctaMode === UpsellModalCTAMode.PayPalUpsellSlot) {
|
|
166
|
-
const handler = await this.braintreeManager?.paymentProviders.paypalHandler.get();
|
|
167
|
-
const donationInfo = new DonationPaymentInfo({
|
|
168
|
-
amount: options.oneTimeAmount,
|
|
169
|
-
donationType: DonationType.OneTime,
|
|
170
|
-
coverFees: false,
|
|
171
|
-
});
|
|
172
|
-
handler?.renderPayPalButton({
|
|
173
|
-
selector: '#paypal-upsell-button',
|
|
174
|
-
style: {
|
|
175
|
-
color: 'blue' as paypal.ButtonColorOption,
|
|
176
|
-
label: 'paypal' as paypal.ButtonLabelOption,
|
|
177
|
-
shape: 'rect' as paypal.ButtonShapeOption,
|
|
178
|
-
size: 'responsive' as paypal.ButtonSizeOption,
|
|
179
|
-
tagline: false,
|
|
180
|
-
},
|
|
181
|
-
donationInfo: donationInfo,
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
get contactFormSectionTemplate(): TemplateResult {
|
|
187
|
-
const headline =
|
|
188
|
-
this.selectedPaymentProvider === PaymentProvider.Venmo
|
|
189
|
-
? 'Help us stay in touch'
|
|
190
|
-
: 'Enter payment information';
|
|
191
|
-
|
|
192
|
-
return html`
|
|
193
|
-
<donation-form-section
|
|
194
|
-
.sectionBadge=${this.paymentSelectorNumberingStart + 1}
|
|
195
|
-
headline=${headline}
|
|
196
|
-
id="contactFormSection"
|
|
197
|
-
>
|
|
198
|
-
<slot name="contact-form"></slot>
|
|
199
|
-
<div class="credit-card-fields" class="${this.creditCardVisible ? '' : 'hidden'}">
|
|
200
|
-
<slot name="braintree-hosted-fields"></slot>
|
|
201
|
-
</div>
|
|
202
|
-
</donation-form-section>
|
|
203
|
-
|
|
204
|
-
<donation-form-section .sectionBadge=${this.paymentSelectorNumberingStart + 2}>
|
|
205
|
-
<slot name="recaptcha"></slot>
|
|
206
|
-
<button id="donate-button" @click=${this.donateClicked}>Donate</button>
|
|
207
|
-
|
|
208
|
-
<div class="secure-process-note">${lockImg} Your payment will be securely processed</div>
|
|
209
|
-
</donation-form-section>
|
|
210
|
-
`;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Where to start the numbering of the payment selector
|
|
215
|
-
*
|
|
216
|
-
* - If we show the frequency selector in button mode, it becomes section 1, which makes
|
|
217
|
-
* the amount selection section 2, and the payment selector section 3.
|
|
218
|
-
* - If we show the frequency selector in checkbox mode, it is no longer section 1. The amount
|
|
219
|
-
* selector becomes section 1 and the payment selector becomes section 2.
|
|
220
|
-
*
|
|
221
|
-
* Visually:
|
|
222
|
-
*
|
|
223
|
-
* Button Mode:
|
|
224
|
-
* 1. Frequency selector
|
|
225
|
-
* 2. Amount selector
|
|
226
|
-
* 3. Payment selector
|
|
227
|
-
* 4. Contact info
|
|
228
|
-
* 5. Donate button
|
|
229
|
-
*
|
|
230
|
-
* Checkbox Mode:
|
|
231
|
-
* 1. Amount selector (including the monthly checkbox)
|
|
232
|
-
* 2. Payment selector <-- changes from 3 to 2
|
|
233
|
-
* 3. Contact info <-- changes from 4 to 3
|
|
234
|
-
* 4. Donate button <-- changes from 5 to 4
|
|
235
|
-
*
|
|
236
|
-
* @readonly
|
|
237
|
-
* @private
|
|
238
|
-
* @type {number}
|
|
239
|
-
* @memberof DonationForm
|
|
240
|
-
*/
|
|
241
|
-
private get paymentSelectorNumberingStart(): number {
|
|
242
|
-
return this.frequencySelectionMode === EditDonationFrequencySelectionMode.Button ? 3 : 2;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
private editDonationError(): void {
|
|
246
|
-
this.donationInfoValid = false;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
private paymentSelectorFirstUpdated(): void {
|
|
250
|
-
if (this.paymentFlowHandlers?.paypalHandler) {
|
|
251
|
-
this.renderPayPalButtonIfNeeded();
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
private applePaySelected(e: CustomEvent): void {
|
|
256
|
-
this.selectedPaymentProvider = PaymentProvider.ApplePay;
|
|
257
|
-
this.contactFormVisible = false;
|
|
258
|
-
this.creditCardVisible = false;
|
|
259
|
-
|
|
260
|
-
if (!this.donationInfoValid) {
|
|
261
|
-
this.showInvalidDonationInfoAlert();
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const originalEvent = e.detail.originalEvent;
|
|
266
|
-
if (this.donationInfo) {
|
|
267
|
-
this.paymentFlowHandlers?.applePayHandler?.paymentInitiated(this.donationInfo, originalEvent);
|
|
268
|
-
}
|
|
269
|
-
this.emitPaymentFlowStartedEvent();
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
private googlePaySelected(): void {
|
|
273
|
-
this.selectedPaymentProvider = PaymentProvider.GooglePay;
|
|
274
|
-
this.contactFormVisible = false;
|
|
275
|
-
this.creditCardVisible = false;
|
|
276
|
-
|
|
277
|
-
if (!this.donationInfoValid) {
|
|
278
|
-
this.showInvalidDonationInfoAlert();
|
|
279
|
-
} else {
|
|
280
|
-
if (this.donationInfo) {
|
|
281
|
-
this.paymentFlowHandlers?.googlePayHandler?.paymentInitiated(this.donationInfo);
|
|
282
|
-
}
|
|
283
|
-
this.emitPaymentFlowStartedEvent();
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
private async creditCardSelected(): Promise<void> {
|
|
288
|
-
if (!this.donationInfoValid) {
|
|
289
|
-
this.showInvalidDonationInfoAlert();
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
this.selectedPaymentProvider = PaymentProvider.CreditCard;
|
|
293
|
-
this.contactFormVisible = true;
|
|
294
|
-
this.creditCardVisible = true;
|
|
295
|
-
this.focusContactForm();
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
private async venmoSelected(): Promise<void> {
|
|
299
|
-
if (!this.donationInfoValid) {
|
|
300
|
-
this.showInvalidDonationInfoAlert();
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
this.selectedPaymentProvider = PaymentProvider.Venmo;
|
|
304
|
-
this.contactFormVisible = true;
|
|
305
|
-
this.creditCardVisible = false;
|
|
306
|
-
this.focusContactForm();
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
private paypalBlockerSelected(): void {
|
|
310
|
-
this.contactFormVisible = false;
|
|
311
|
-
this.creditCardVisible = false;
|
|
312
|
-
this.showInvalidDonationInfoAlert();
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
private async focusContactForm(): Promise<void> {
|
|
316
|
-
await this.updateComplete;
|
|
317
|
-
if (this.contactFormSection) {
|
|
318
|
-
this.contactForm?.focus();
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
private async donateClicked(): Promise<void> {
|
|
323
|
-
if (!this.contactForm) {
|
|
324
|
-
alert('Please enter contact info.');
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
if (!this.donationInfoValid || !this.donationInfo) {
|
|
328
|
-
this.showInvalidDonationInfoAlert();
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const contactInfo = this.contactForm.donorContactInfo;
|
|
333
|
-
|
|
334
|
-
switch (this.selectedPaymentProvider) {
|
|
335
|
-
case PaymentProvider.CreditCard:
|
|
336
|
-
this.handleCreditCardDonationFlow(contactInfo, this.donationInfo);
|
|
337
|
-
break;
|
|
338
|
-
case PaymentProvider.Venmo:
|
|
339
|
-
this.handleVenmoDonationFlow(contactInfo, this.donationInfo);
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
private async handleCreditCardDonationFlow(
|
|
345
|
-
contactInfo: DonorContactInfo,
|
|
346
|
-
donationInfo: DonationPaymentInfo,
|
|
347
|
-
): Promise<void> {
|
|
348
|
-
const creditCardFlowHandler = this.paymentFlowHandlers?.creditCardHandler;
|
|
349
|
-
const creditCardHandler = await this.braintreeManager?.paymentProviders.creditCardHandler.get();
|
|
350
|
-
creditCardHandler?.hideErrorMessage();
|
|
351
|
-
const valid = this.contactForm?.reportValidity();
|
|
352
|
-
const hostedFieldsResponse = await creditCardFlowHandler?.tokenizeFields();
|
|
353
|
-
|
|
354
|
-
if (!valid || hostedFieldsResponse === undefined) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
this.emitPaymentFlowStartedEvent();
|
|
359
|
-
creditCardFlowHandler?.paymentInitiated(hostedFieldsResponse, donationInfo, contactInfo);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
private async handleVenmoDonationFlow(
|
|
363
|
-
contactInfo: DonorContactInfo,
|
|
364
|
-
donationInfo: DonationPaymentInfo,
|
|
365
|
-
): Promise<void> {
|
|
366
|
-
const valid = this.contactForm?.reportValidity();
|
|
367
|
-
if (!valid) {
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
this.paymentFlowHandlers?.venmoHandler?.paymentInitiated(contactInfo, donationInfo);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
private emitPaymentFlowStartedEvent(): void {
|
|
374
|
-
if (!this.selectedPaymentProvider) {
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
const event = new CustomEvent('paymentFlowStarted', {
|
|
378
|
-
detail: { paymentProvider: this.selectedPaymentProvider },
|
|
379
|
-
});
|
|
380
|
-
this.dispatchEvent(event);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
private emitPaymentFlowConfirmedEvent(): void {
|
|
384
|
-
if (!this.selectedPaymentProvider) {
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
const event = new CustomEvent('paymentFlowConfirmed', {
|
|
388
|
-
detail: { paymentProvider: this.selectedPaymentProvider },
|
|
389
|
-
});
|
|
390
|
-
this.dispatchEvent(event);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
private emitPaymentFlowCancelledEvent(): void {
|
|
394
|
-
if (!this.selectedPaymentProvider) {
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
const event = new CustomEvent('paymentFlowCancelled', {
|
|
398
|
-
detail: { paymentProvider: this.selectedPaymentProvider },
|
|
399
|
-
});
|
|
400
|
-
this.dispatchEvent(event);
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
private emitPaymentFlowErrorEvent(error?: string): void {
|
|
404
|
-
if (!this.selectedPaymentProvider) {
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
const event = new CustomEvent('paymentFlowError', {
|
|
408
|
-
detail: { paymentProvider: this.selectedPaymentProvider, error: error },
|
|
409
|
-
});
|
|
410
|
-
this.dispatchEvent(event);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
private showInvalidDonationInfoAlert(): void {
|
|
414
|
-
alert('Please enter a valid donation amount.');
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
private async renderPayPalButtonIfNeeded(): Promise<void> {
|
|
418
|
-
if (!this.paypalButtonNeedsRender) {
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
this.paypalButtonNeedsRender = false;
|
|
422
|
-
if (this.donationInfo) {
|
|
423
|
-
await this.paymentFlowHandlers?.paypalHandler?.renderPayPalButton(this.donationInfo);
|
|
424
|
-
}
|
|
425
|
-
this.paymentSelector.showPaypalButton();
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
updated(changedProperties: PropertyValues): void {
|
|
429
|
-
if (changedProperties.has('donationInfo') && this.donationInfo) {
|
|
430
|
-
// The PayPal button has a standalone datasource since we don't initiate the payment
|
|
431
|
-
// through code so it has to have the donation info ready when the user taps the button.
|
|
432
|
-
this.paymentFlowHandlers?.paypalHandler?.updateDonationInfo(this.donationInfo);
|
|
433
|
-
this.donationFormHeader.donationInfo = this.donationInfo;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
if (
|
|
437
|
-
(changedProperties.has('paymentFlowHandlers') || changedProperties.has('donationInfo')) &&
|
|
438
|
-
this.donationInfo &&
|
|
439
|
-
this.paymentFlowHandlers
|
|
440
|
-
) {
|
|
441
|
-
this.setupFlowHandlers();
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
if (changedProperties.has('donationInfoValid')) {
|
|
445
|
-
this.paymentSelector.donationInfoValid = this.donationInfoValid;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
if (changedProperties.has('selectedPaymentProvider')) {
|
|
449
|
-
const event = new CustomEvent('paymentProviderSelected', {
|
|
450
|
-
detail: {
|
|
451
|
-
paymentProvider: this.selectedPaymentProvider,
|
|
452
|
-
previousPaymentProvider: changedProperties.get('selectedPaymentProvider'),
|
|
453
|
-
},
|
|
454
|
-
});
|
|
455
|
-
this.dispatchEvent(event);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
private flowHandlersConfigured = false;
|
|
460
|
-
|
|
461
|
-
private setupFlowHandlers(): void {
|
|
462
|
-
if (this.flowHandlersConfigured) {
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
this.flowHandlersConfigured = true;
|
|
466
|
-
this.bindFlowListenerEvents();
|
|
467
|
-
this.renderPayPalButtonIfNeeded();
|
|
468
|
-
if (this.donationInfo) {
|
|
469
|
-
this.paymentFlowHandlers?.paypalHandler?.updateDonationInfo(this.donationInfo);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
private flowHandlerListenersBound = false;
|
|
474
|
-
|
|
475
|
-
private bindFlowListenerEvents(): void {
|
|
476
|
-
if (this.flowHandlerListenersBound) {
|
|
477
|
-
return;
|
|
478
|
-
}
|
|
479
|
-
this.flowHandlerListenersBound = true;
|
|
480
|
-
|
|
481
|
-
this.paymentFlowHandlers?.paypalHandler?.on('payPalPaymentStarted', () => {
|
|
482
|
-
this.selectedPaymentProvider = PaymentProvider.PayPal;
|
|
483
|
-
this.emitPaymentFlowStartedEvent();
|
|
484
|
-
});
|
|
485
|
-
this.paymentFlowHandlers?.paypalHandler?.on('payPalPaymentConfirmed', () => {
|
|
486
|
-
this.selectedPaymentProvider = PaymentProvider.PayPal;
|
|
487
|
-
this.emitPaymentFlowConfirmedEvent();
|
|
488
|
-
});
|
|
489
|
-
this.paymentFlowHandlers?.paypalHandler?.on('payPalPaymentCancelled', () => {
|
|
490
|
-
this.selectedPaymentProvider = PaymentProvider.PayPal;
|
|
491
|
-
this.emitPaymentFlowCancelledEvent();
|
|
492
|
-
});
|
|
493
|
-
this.paymentFlowHandlers?.paypalHandler?.on('payPalPaymentError', (datasource, error) => {
|
|
494
|
-
this.selectedPaymentProvider = PaymentProvider.PayPal;
|
|
495
|
-
this.emitPaymentFlowErrorEvent(error);
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
this.paymentFlowHandlers?.googlePayHandler?.on('paymentCancelled', () => {
|
|
499
|
-
this.selectedPaymentProvider = PaymentProvider.GooglePay;
|
|
500
|
-
this.emitPaymentFlowCancelledEvent();
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
private donationInfoChanged(e: CustomEvent): void {
|
|
505
|
-
const donationInfo: DonationPaymentInfo = e.detail.donationInfo;
|
|
506
|
-
this.donationInfo = new DonationPaymentInfo({
|
|
507
|
-
amount: donationInfo.amount,
|
|
508
|
-
donationType: donationInfo.donationType,
|
|
509
|
-
coverFees: donationInfo.coverFees,
|
|
510
|
-
});
|
|
511
|
-
this.donationInfoValid = true;
|
|
512
|
-
const event = new CustomEvent('donationInfoChanged', { detail: { donationInfo } });
|
|
513
|
-
this.dispatchEvent(event);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
/** @inheritdoc */
|
|
517
|
-
static get styles(): CSSResult {
|
|
518
|
-
const donateButtonFontSize = css`var(--donateButtonFontSize, 2.6rem)`;
|
|
519
|
-
const donateButtonHeight = css`var(--donateButtonHeight, 4rem)`;
|
|
520
|
-
const donateButtonColor = css`var(--donateButtonColor, rgba(49, 164, 129, 1))`;
|
|
521
|
-
const donateButtonTextColor = css`var(--donateButtonTextColor, #fff)`;
|
|
522
|
-
const donateButtonHoverColor = css`var(--donateButtonHoverColor, rgba(39, 131, 103, 1))`;
|
|
523
|
-
const totalAmountTopMargin = css`var(--donateTotalAmountTopMargin, 1.5rem)`;
|
|
524
|
-
const totalAmountBottomMargin = css`var(--donateTotalAmountBottomMargin, 1.2rem)`;
|
|
525
|
-
|
|
526
|
-
return css`
|
|
527
|
-
h1 {
|
|
528
|
-
margin: 0;
|
|
529
|
-
padding: 0;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
.hidden {
|
|
533
|
-
display: none;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
.secure-process-note {
|
|
537
|
-
margin-top: 0.5em;
|
|
538
|
-
font-size: 0.75em;
|
|
539
|
-
text-align: center;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
.secure-process-note svg {
|
|
543
|
-
width: 1.2rem;
|
|
544
|
-
height: 1.5rem;
|
|
545
|
-
vertical-align: bottom;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
#donate-button {
|
|
549
|
-
width: 100%;
|
|
550
|
-
appearance: none;
|
|
551
|
-
-webkit-appearance: none;
|
|
552
|
-
font-size: ${donateButtonFontSize};
|
|
553
|
-
font-weight: bold;
|
|
554
|
-
text-align: center;
|
|
555
|
-
color: ${donateButtonTextColor};
|
|
556
|
-
cursor: pointer;
|
|
557
|
-
border: none;
|
|
558
|
-
border-radius: 5px;
|
|
559
|
-
background-color: ${donateButtonColor};
|
|
560
|
-
padding-top: 0.5rem;
|
|
561
|
-
padding-bottom: 0.5rem;
|
|
562
|
-
height: ${donateButtonHeight};
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
#donate-button:hover {
|
|
566
|
-
background-color: ${donateButtonHoverColor};
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
#total-amount-section {
|
|
570
|
-
display: block;
|
|
571
|
-
margin-top: ${totalAmountTopMargin};
|
|
572
|
-
margin-bottom: ${totalAmountBottomMargin};
|
|
573
|
-
}
|
|
574
|
-
`;
|
|
575
|
-
}
|
|
576
|
-
}
|
|
1
|
+
import { LitElement, html, css, CSSResult, TemplateResult, PropertyValues } from 'lit';
|
|
2
|
+
import { customElement, property, query } from 'lit/decorators.js';
|
|
3
|
+
|
|
4
|
+
import lockImg from '@internetarchive/icon-lock/index.js';
|
|
5
|
+
|
|
6
|
+
// we have to import the registered component independently from the definition below
|
|
7
|
+
// because inside each of these files, we're registering the custom element inside
|
|
8
|
+
// these files and by simply importing the class name, you lose that behavior
|
|
9
|
+
// See https://github.com/microsoft/TypeScript/issues/9191 for more discussion
|
|
10
|
+
import './form-elements/payment-selector';
|
|
11
|
+
import './form-elements/header/donation-form-header';
|
|
12
|
+
|
|
13
|
+
import { DonationFormHeader } from './form-elements/header/donation-form-header';
|
|
14
|
+
import { PaymentSelector } from './form-elements/payment-selector';
|
|
15
|
+
|
|
16
|
+
import { BraintreeManagerInterface } from './braintree-manager/braintree-interfaces';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
DonationRequest,
|
|
20
|
+
DonationPaymentInfo,
|
|
21
|
+
PaymentProvider,
|
|
22
|
+
DonorContactInfo,
|
|
23
|
+
DonationType,
|
|
24
|
+
defaultDonationAmounts,
|
|
25
|
+
} from '@internetarchive/donation-form-data-models';
|
|
26
|
+
|
|
27
|
+
import { PaymentFlowHandlersInterface } from './payment-flow-handlers/payment-flow-handlers';
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
EditDonationAmountSelectionLayout,
|
|
31
|
+
EditDonationFrequencySelectionMode,
|
|
32
|
+
} from '@internetarchive/donation-form-edit-donation';
|
|
33
|
+
|
|
34
|
+
import '@internetarchive/donation-form-section';
|
|
35
|
+
import {
|
|
36
|
+
DonationFormSection,
|
|
37
|
+
DonationFormSectionBadgeMode,
|
|
38
|
+
} from '@internetarchive/donation-form-section';
|
|
39
|
+
import { UpsellModalCTAMode } from './modals/upsell-modal-content';
|
|
40
|
+
import { ContactForm } from './form-elements/contact-form/contact-form';
|
|
41
|
+
import './form-elements/total-amount';
|
|
42
|
+
|
|
43
|
+
@customElement('donation-form')
|
|
44
|
+
export class DonationForm extends LitElement {
|
|
45
|
+
@property({ type: Object }) braintreeManager: BraintreeManagerInterface | undefined;
|
|
46
|
+
|
|
47
|
+
@property({ type: Object }) paymentFlowHandlers: PaymentFlowHandlersInterface | undefined;
|
|
48
|
+
|
|
49
|
+
@property({ type: Object }) donationRequest: DonationRequest | undefined;
|
|
50
|
+
|
|
51
|
+
@property({ type: Object }) donationInfo?: DonationPaymentInfo;
|
|
52
|
+
|
|
53
|
+
@property({ type: Object }) contactForm?: ContactForm;
|
|
54
|
+
|
|
55
|
+
@property({ type: Array }) amountOptions: number[] = defaultDonationAmounts;
|
|
56
|
+
|
|
57
|
+
@property({ type: String }) amountSelectionLayout: EditDonationAmountSelectionLayout =
|
|
58
|
+
EditDonationAmountSelectionLayout.MultiLine;
|
|
59
|
+
|
|
60
|
+
@property({ type: String }) frequencySelectionMode: EditDonationFrequencySelectionMode =
|
|
61
|
+
EditDonationFrequencySelectionMode.Button;
|
|
62
|
+
|
|
63
|
+
@property({ type: Boolean }) private creditCardVisible = false;
|
|
64
|
+
|
|
65
|
+
@property({ type: Boolean }) private contactFormVisible = false;
|
|
66
|
+
|
|
67
|
+
@property({ type: Boolean }) private donationInfoValid = true;
|
|
68
|
+
|
|
69
|
+
@property({ type: String }) private selectedPaymentProvider?: PaymentProvider;
|
|
70
|
+
|
|
71
|
+
@query('#contactFormSection') contactFormSection?: DonationFormSection;
|
|
72
|
+
|
|
73
|
+
@query('donation-form-header') donationFormHeader!: DonationFormHeader;
|
|
74
|
+
|
|
75
|
+
@query('payment-selector') paymentSelector!: PaymentSelector;
|
|
76
|
+
|
|
77
|
+
private paypalButtonNeedsRender = true;
|
|
78
|
+
|
|
79
|
+
/** @inheritdoc */
|
|
80
|
+
render(): TemplateResult {
|
|
81
|
+
return html`
|
|
82
|
+
<donation-form-header
|
|
83
|
+
.amountOptions=${this.amountOptions}
|
|
84
|
+
.amountSelectionLayout=${this.amountSelectionLayout}
|
|
85
|
+
.frequencySelectionMode=${this.frequencySelectionMode}
|
|
86
|
+
@donationInfoChanged=${this.donationInfoChanged}
|
|
87
|
+
@editDonationError=${this.editDonationError}
|
|
88
|
+
>
|
|
89
|
+
</donation-form-header>
|
|
90
|
+
|
|
91
|
+
<donation-form-section
|
|
92
|
+
.badgeMode=${DonationFormSectionBadgeMode.HideBadgeLeaveSpacing}
|
|
93
|
+
id="total-amount-section"
|
|
94
|
+
>
|
|
95
|
+
<donation-form-total-amount .donationInfo=${this.donationInfo}>
|
|
96
|
+
</donation-form-total-amount>
|
|
97
|
+
</donation-form-section>
|
|
98
|
+
|
|
99
|
+
<donation-form-section
|
|
100
|
+
.sectionBadge=${this.paymentSelectorNumberingStart}
|
|
101
|
+
headline="Choose a payment method"
|
|
102
|
+
>
|
|
103
|
+
<payment-selector
|
|
104
|
+
.paymentProviders=${this.braintreeManager?.paymentProviders}
|
|
105
|
+
@firstUpdated=${this.paymentSelectorFirstUpdated}
|
|
106
|
+
@creditCardSelected=${this.creditCardSelected}
|
|
107
|
+
@venmoSelected=${this.venmoSelected}
|
|
108
|
+
@applePaySelected=${this.applePaySelected}
|
|
109
|
+
@googlePaySelected=${this.googlePaySelected}
|
|
110
|
+
@paypalBlockerSelected=${this.paypalBlockerSelected}
|
|
111
|
+
@resetPaymentMethod=${async () => {
|
|
112
|
+
this.selectedPaymentProvider = undefined;
|
|
113
|
+
this.contactFormVisible = false;
|
|
114
|
+
this.requestUpdate();
|
|
115
|
+
}}
|
|
116
|
+
tabindex="0"
|
|
117
|
+
>
|
|
118
|
+
<slot name="paypal-button" slot="paypal-button"></slot>
|
|
119
|
+
</payment-selector>
|
|
120
|
+
</donation-form-section>
|
|
121
|
+
|
|
122
|
+
<div class="contact-form-section ${this.contactFormVisible ? '' : 'hidden'}">
|
|
123
|
+
${this.contactFormSectionTemplate}
|
|
124
|
+
</div>
|
|
125
|
+
<slot name="recaptcha"></slot>
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async showConfirmationModalDev(options: {
|
|
130
|
+
donationType: DonationType;
|
|
131
|
+
amount: number;
|
|
132
|
+
currencyType: string;
|
|
133
|
+
cancelDonationCB: Function;
|
|
134
|
+
confirmDonationCB: Function;
|
|
135
|
+
}): Promise<void> {
|
|
136
|
+
this.paymentFlowHandlers?.showConfirmationStepModal(options);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* This is a developer convenience method that allows us to show the upsell modal without going
|
|
141
|
+
* through the purchasing flow. If it's showing the PayPal button, it will trigger
|
|
142
|
+
* the PayPal button render
|
|
143
|
+
*
|
|
144
|
+
* @param {{
|
|
145
|
+
* oneTimeAmount: number;
|
|
146
|
+
* ctaMode?: UpsellModalCTAMode;
|
|
147
|
+
* yesSelected?: (amount: number) => void;
|
|
148
|
+
* noSelected?: () => void;
|
|
149
|
+
* amountChanged?: (amount: number) => void;
|
|
150
|
+
* userClosedModalCallback?: () => void;
|
|
151
|
+
* }} options
|
|
152
|
+
* @returns {Promise<void>}
|
|
153
|
+
* @memberof DonationForm
|
|
154
|
+
*/
|
|
155
|
+
async showUpsellModalDev(options: {
|
|
156
|
+
oneTimeAmount: number;
|
|
157
|
+
ctaMode?: UpsellModalCTAMode;
|
|
158
|
+
yesSelected?: (amount: number) => void;
|
|
159
|
+
noSelected?: () => void;
|
|
160
|
+
amountChanged?: (amount: number) => void;
|
|
161
|
+
userClosedModalCallback?: () => void;
|
|
162
|
+
}): Promise<void> {
|
|
163
|
+
this.paymentFlowHandlers?.showUpsellModal(options);
|
|
164
|
+
|
|
165
|
+
if (options.ctaMode === UpsellModalCTAMode.PayPalUpsellSlot) {
|
|
166
|
+
const handler = await this.braintreeManager?.paymentProviders.paypalHandler.get();
|
|
167
|
+
const donationInfo = new DonationPaymentInfo({
|
|
168
|
+
amount: options.oneTimeAmount,
|
|
169
|
+
donationType: DonationType.OneTime,
|
|
170
|
+
coverFees: false,
|
|
171
|
+
});
|
|
172
|
+
handler?.renderPayPalButton({
|
|
173
|
+
selector: '#paypal-upsell-button',
|
|
174
|
+
style: {
|
|
175
|
+
color: 'blue' as paypal.ButtonColorOption,
|
|
176
|
+
label: 'paypal' as paypal.ButtonLabelOption,
|
|
177
|
+
shape: 'rect' as paypal.ButtonShapeOption,
|
|
178
|
+
size: 'responsive' as paypal.ButtonSizeOption,
|
|
179
|
+
tagline: false,
|
|
180
|
+
},
|
|
181
|
+
donationInfo: donationInfo,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
get contactFormSectionTemplate(): TemplateResult {
|
|
187
|
+
const headline =
|
|
188
|
+
this.selectedPaymentProvider === PaymentProvider.Venmo
|
|
189
|
+
? 'Help us stay in touch'
|
|
190
|
+
: 'Enter payment information';
|
|
191
|
+
|
|
192
|
+
return html`
|
|
193
|
+
<donation-form-section
|
|
194
|
+
.sectionBadge=${this.paymentSelectorNumberingStart + 1}
|
|
195
|
+
headline=${headline}
|
|
196
|
+
id="contactFormSection"
|
|
197
|
+
>
|
|
198
|
+
<slot name="contact-form"></slot>
|
|
199
|
+
<div class="credit-card-fields" class="${this.creditCardVisible ? '' : 'hidden'}">
|
|
200
|
+
<slot name="braintree-hosted-fields"></slot>
|
|
201
|
+
</div>
|
|
202
|
+
</donation-form-section>
|
|
203
|
+
|
|
204
|
+
<donation-form-section .sectionBadge=${this.paymentSelectorNumberingStart + 2}>
|
|
205
|
+
<slot name="recaptcha"></slot>
|
|
206
|
+
<button id="donate-button" @click=${this.donateClicked}>Donate</button>
|
|
207
|
+
|
|
208
|
+
<div class="secure-process-note">${lockImg} Your payment will be securely processed</div>
|
|
209
|
+
</donation-form-section>
|
|
210
|
+
`;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Where to start the numbering of the payment selector
|
|
215
|
+
*
|
|
216
|
+
* - If we show the frequency selector in button mode, it becomes section 1, which makes
|
|
217
|
+
* the amount selection section 2, and the payment selector section 3.
|
|
218
|
+
* - If we show the frequency selector in checkbox mode, it is no longer section 1. The amount
|
|
219
|
+
* selector becomes section 1 and the payment selector becomes section 2.
|
|
220
|
+
*
|
|
221
|
+
* Visually:
|
|
222
|
+
*
|
|
223
|
+
* Button Mode:
|
|
224
|
+
* 1. Frequency selector
|
|
225
|
+
* 2. Amount selector
|
|
226
|
+
* 3. Payment selector
|
|
227
|
+
* 4. Contact info
|
|
228
|
+
* 5. Donate button
|
|
229
|
+
*
|
|
230
|
+
* Checkbox Mode:
|
|
231
|
+
* 1. Amount selector (including the monthly checkbox)
|
|
232
|
+
* 2. Payment selector <-- changes from 3 to 2
|
|
233
|
+
* 3. Contact info <-- changes from 4 to 3
|
|
234
|
+
* 4. Donate button <-- changes from 5 to 4
|
|
235
|
+
*
|
|
236
|
+
* @readonly
|
|
237
|
+
* @private
|
|
238
|
+
* @type {number}
|
|
239
|
+
* @memberof DonationForm
|
|
240
|
+
*/
|
|
241
|
+
private get paymentSelectorNumberingStart(): number {
|
|
242
|
+
return this.frequencySelectionMode === EditDonationFrequencySelectionMode.Button ? 3 : 2;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private editDonationError(): void {
|
|
246
|
+
this.donationInfoValid = false;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private paymentSelectorFirstUpdated(): void {
|
|
250
|
+
if (this.paymentFlowHandlers?.paypalHandler) {
|
|
251
|
+
this.renderPayPalButtonIfNeeded();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private applePaySelected(e: CustomEvent): void {
|
|
256
|
+
this.selectedPaymentProvider = PaymentProvider.ApplePay;
|
|
257
|
+
this.contactFormVisible = false;
|
|
258
|
+
this.creditCardVisible = false;
|
|
259
|
+
|
|
260
|
+
if (!this.donationInfoValid) {
|
|
261
|
+
this.showInvalidDonationInfoAlert();
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const originalEvent = e.detail.originalEvent;
|
|
266
|
+
if (this.donationInfo) {
|
|
267
|
+
this.paymentFlowHandlers?.applePayHandler?.paymentInitiated(this.donationInfo, originalEvent);
|
|
268
|
+
}
|
|
269
|
+
this.emitPaymentFlowStartedEvent();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private googlePaySelected(): void {
|
|
273
|
+
this.selectedPaymentProvider = PaymentProvider.GooglePay;
|
|
274
|
+
this.contactFormVisible = false;
|
|
275
|
+
this.creditCardVisible = false;
|
|
276
|
+
|
|
277
|
+
if (!this.donationInfoValid) {
|
|
278
|
+
this.showInvalidDonationInfoAlert();
|
|
279
|
+
} else {
|
|
280
|
+
if (this.donationInfo) {
|
|
281
|
+
this.paymentFlowHandlers?.googlePayHandler?.paymentInitiated(this.donationInfo);
|
|
282
|
+
}
|
|
283
|
+
this.emitPaymentFlowStartedEvent();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
private async creditCardSelected(): Promise<void> {
|
|
288
|
+
if (!this.donationInfoValid) {
|
|
289
|
+
this.showInvalidDonationInfoAlert();
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
this.selectedPaymentProvider = PaymentProvider.CreditCard;
|
|
293
|
+
this.contactFormVisible = true;
|
|
294
|
+
this.creditCardVisible = true;
|
|
295
|
+
this.focusContactForm();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private async venmoSelected(): Promise<void> {
|
|
299
|
+
if (!this.donationInfoValid) {
|
|
300
|
+
this.showInvalidDonationInfoAlert();
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
this.selectedPaymentProvider = PaymentProvider.Venmo;
|
|
304
|
+
this.contactFormVisible = true;
|
|
305
|
+
this.creditCardVisible = false;
|
|
306
|
+
this.focusContactForm();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private paypalBlockerSelected(): void {
|
|
310
|
+
this.contactFormVisible = false;
|
|
311
|
+
this.creditCardVisible = false;
|
|
312
|
+
this.showInvalidDonationInfoAlert();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private async focusContactForm(): Promise<void> {
|
|
316
|
+
await this.updateComplete;
|
|
317
|
+
if (this.contactFormSection) {
|
|
318
|
+
this.contactForm?.focus();
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private async donateClicked(): Promise<void> {
|
|
323
|
+
if (!this.contactForm) {
|
|
324
|
+
alert('Please enter contact info.');
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (!this.donationInfoValid || !this.donationInfo) {
|
|
328
|
+
this.showInvalidDonationInfoAlert();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const contactInfo = this.contactForm.donorContactInfo;
|
|
333
|
+
|
|
334
|
+
switch (this.selectedPaymentProvider) {
|
|
335
|
+
case PaymentProvider.CreditCard:
|
|
336
|
+
this.handleCreditCardDonationFlow(contactInfo, this.donationInfo);
|
|
337
|
+
break;
|
|
338
|
+
case PaymentProvider.Venmo:
|
|
339
|
+
this.handleVenmoDonationFlow(contactInfo, this.donationInfo);
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private async handleCreditCardDonationFlow(
|
|
345
|
+
contactInfo: DonorContactInfo,
|
|
346
|
+
donationInfo: DonationPaymentInfo,
|
|
347
|
+
): Promise<void> {
|
|
348
|
+
const creditCardFlowHandler = this.paymentFlowHandlers?.creditCardHandler;
|
|
349
|
+
const creditCardHandler = await this.braintreeManager?.paymentProviders.creditCardHandler.get();
|
|
350
|
+
creditCardHandler?.hideErrorMessage();
|
|
351
|
+
const valid = this.contactForm?.reportValidity();
|
|
352
|
+
const hostedFieldsResponse = await creditCardFlowHandler?.tokenizeFields();
|
|
353
|
+
|
|
354
|
+
if (!valid || hostedFieldsResponse === undefined) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
this.emitPaymentFlowStartedEvent();
|
|
359
|
+
creditCardFlowHandler?.paymentInitiated(hostedFieldsResponse, donationInfo, contactInfo);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
private async handleVenmoDonationFlow(
|
|
363
|
+
contactInfo: DonorContactInfo,
|
|
364
|
+
donationInfo: DonationPaymentInfo,
|
|
365
|
+
): Promise<void> {
|
|
366
|
+
const valid = this.contactForm?.reportValidity();
|
|
367
|
+
if (!valid) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
this.paymentFlowHandlers?.venmoHandler?.paymentInitiated(contactInfo, donationInfo);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
private emitPaymentFlowStartedEvent(): void {
|
|
374
|
+
if (!this.selectedPaymentProvider) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const event = new CustomEvent('paymentFlowStarted', {
|
|
378
|
+
detail: { paymentProvider: this.selectedPaymentProvider },
|
|
379
|
+
});
|
|
380
|
+
this.dispatchEvent(event);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
private emitPaymentFlowConfirmedEvent(): void {
|
|
384
|
+
if (!this.selectedPaymentProvider) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const event = new CustomEvent('paymentFlowConfirmed', {
|
|
388
|
+
detail: { paymentProvider: this.selectedPaymentProvider },
|
|
389
|
+
});
|
|
390
|
+
this.dispatchEvent(event);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
private emitPaymentFlowCancelledEvent(): void {
|
|
394
|
+
if (!this.selectedPaymentProvider) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const event = new CustomEvent('paymentFlowCancelled', {
|
|
398
|
+
detail: { paymentProvider: this.selectedPaymentProvider },
|
|
399
|
+
});
|
|
400
|
+
this.dispatchEvent(event);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
private emitPaymentFlowErrorEvent(error?: string): void {
|
|
404
|
+
if (!this.selectedPaymentProvider) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const event = new CustomEvent('paymentFlowError', {
|
|
408
|
+
detail: { paymentProvider: this.selectedPaymentProvider, error: error },
|
|
409
|
+
});
|
|
410
|
+
this.dispatchEvent(event);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
private showInvalidDonationInfoAlert(): void {
|
|
414
|
+
alert('Please enter a valid donation amount.');
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
private async renderPayPalButtonIfNeeded(): Promise<void> {
|
|
418
|
+
if (!this.paypalButtonNeedsRender) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
this.paypalButtonNeedsRender = false;
|
|
422
|
+
if (this.donationInfo) {
|
|
423
|
+
await this.paymentFlowHandlers?.paypalHandler?.renderPayPalButton(this.donationInfo);
|
|
424
|
+
}
|
|
425
|
+
this.paymentSelector.showPaypalButton();
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
updated(changedProperties: PropertyValues): void {
|
|
429
|
+
if (changedProperties.has('donationInfo') && this.donationInfo) {
|
|
430
|
+
// The PayPal button has a standalone datasource since we don't initiate the payment
|
|
431
|
+
// through code so it has to have the donation info ready when the user taps the button.
|
|
432
|
+
this.paymentFlowHandlers?.paypalHandler?.updateDonationInfo(this.donationInfo);
|
|
433
|
+
this.donationFormHeader.donationInfo = this.donationInfo;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (
|
|
437
|
+
(changedProperties.has('paymentFlowHandlers') || changedProperties.has('donationInfo')) &&
|
|
438
|
+
this.donationInfo &&
|
|
439
|
+
this.paymentFlowHandlers
|
|
440
|
+
) {
|
|
441
|
+
this.setupFlowHandlers();
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (changedProperties.has('donationInfoValid')) {
|
|
445
|
+
this.paymentSelector.donationInfoValid = this.donationInfoValid;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (changedProperties.has('selectedPaymentProvider')) {
|
|
449
|
+
const event = new CustomEvent('paymentProviderSelected', {
|
|
450
|
+
detail: {
|
|
451
|
+
paymentProvider: this.selectedPaymentProvider,
|
|
452
|
+
previousPaymentProvider: changedProperties.get('selectedPaymentProvider'),
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
this.dispatchEvent(event);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private flowHandlersConfigured = false;
|
|
460
|
+
|
|
461
|
+
private setupFlowHandlers(): void {
|
|
462
|
+
if (this.flowHandlersConfigured) {
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
this.flowHandlersConfigured = true;
|
|
466
|
+
this.bindFlowListenerEvents();
|
|
467
|
+
this.renderPayPalButtonIfNeeded();
|
|
468
|
+
if (this.donationInfo) {
|
|
469
|
+
this.paymentFlowHandlers?.paypalHandler?.updateDonationInfo(this.donationInfo);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
private flowHandlerListenersBound = false;
|
|
474
|
+
|
|
475
|
+
private bindFlowListenerEvents(): void {
|
|
476
|
+
if (this.flowHandlerListenersBound) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
this.flowHandlerListenersBound = true;
|
|
480
|
+
|
|
481
|
+
this.paymentFlowHandlers?.paypalHandler?.on('payPalPaymentStarted', () => {
|
|
482
|
+
this.selectedPaymentProvider = PaymentProvider.PayPal;
|
|
483
|
+
this.emitPaymentFlowStartedEvent();
|
|
484
|
+
});
|
|
485
|
+
this.paymentFlowHandlers?.paypalHandler?.on('payPalPaymentConfirmed', () => {
|
|
486
|
+
this.selectedPaymentProvider = PaymentProvider.PayPal;
|
|
487
|
+
this.emitPaymentFlowConfirmedEvent();
|
|
488
|
+
});
|
|
489
|
+
this.paymentFlowHandlers?.paypalHandler?.on('payPalPaymentCancelled', () => {
|
|
490
|
+
this.selectedPaymentProvider = PaymentProvider.PayPal;
|
|
491
|
+
this.emitPaymentFlowCancelledEvent();
|
|
492
|
+
});
|
|
493
|
+
this.paymentFlowHandlers?.paypalHandler?.on('payPalPaymentError', (datasource, error) => {
|
|
494
|
+
this.selectedPaymentProvider = PaymentProvider.PayPal;
|
|
495
|
+
this.emitPaymentFlowErrorEvent(error);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
this.paymentFlowHandlers?.googlePayHandler?.on('paymentCancelled', () => {
|
|
499
|
+
this.selectedPaymentProvider = PaymentProvider.GooglePay;
|
|
500
|
+
this.emitPaymentFlowCancelledEvent();
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
private donationInfoChanged(e: CustomEvent): void {
|
|
505
|
+
const donationInfo: DonationPaymentInfo = e.detail.donationInfo;
|
|
506
|
+
this.donationInfo = new DonationPaymentInfo({
|
|
507
|
+
amount: donationInfo.amount,
|
|
508
|
+
donationType: donationInfo.donationType,
|
|
509
|
+
coverFees: donationInfo.coverFees,
|
|
510
|
+
});
|
|
511
|
+
this.donationInfoValid = true;
|
|
512
|
+
const event = new CustomEvent('donationInfoChanged', { detail: { donationInfo } });
|
|
513
|
+
this.dispatchEvent(event);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/** @inheritdoc */
|
|
517
|
+
static get styles(): CSSResult {
|
|
518
|
+
const donateButtonFontSize = css`var(--donateButtonFontSize, 2.6rem)`;
|
|
519
|
+
const donateButtonHeight = css`var(--donateButtonHeight, 4rem)`;
|
|
520
|
+
const donateButtonColor = css`var(--donateButtonColor, rgba(49, 164, 129, 1))`;
|
|
521
|
+
const donateButtonTextColor = css`var(--donateButtonTextColor, #fff)`;
|
|
522
|
+
const donateButtonHoverColor = css`var(--donateButtonHoverColor, rgba(39, 131, 103, 1))`;
|
|
523
|
+
const totalAmountTopMargin = css`var(--donateTotalAmountTopMargin, 1.5rem)`;
|
|
524
|
+
const totalAmountBottomMargin = css`var(--donateTotalAmountBottomMargin, 1.2rem)`;
|
|
525
|
+
|
|
526
|
+
return css`
|
|
527
|
+
h1 {
|
|
528
|
+
margin: 0;
|
|
529
|
+
padding: 0;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
.hidden {
|
|
533
|
+
display: none;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.secure-process-note {
|
|
537
|
+
margin-top: 0.5em;
|
|
538
|
+
font-size: 0.75em;
|
|
539
|
+
text-align: center;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.secure-process-note svg {
|
|
543
|
+
width: 1.2rem;
|
|
544
|
+
height: 1.5rem;
|
|
545
|
+
vertical-align: bottom;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
#donate-button {
|
|
549
|
+
width: 100%;
|
|
550
|
+
appearance: none;
|
|
551
|
+
-webkit-appearance: none;
|
|
552
|
+
font-size: ${donateButtonFontSize};
|
|
553
|
+
font-weight: bold;
|
|
554
|
+
text-align: center;
|
|
555
|
+
color: ${donateButtonTextColor};
|
|
556
|
+
cursor: pointer;
|
|
557
|
+
border: none;
|
|
558
|
+
border-radius: 5px;
|
|
559
|
+
background-color: ${donateButtonColor};
|
|
560
|
+
padding-top: 0.5rem;
|
|
561
|
+
padding-bottom: 0.5rem;
|
|
562
|
+
height: ${donateButtonHeight};
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
#donate-button:hover {
|
|
566
|
+
background-color: ${donateButtonHoverColor};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
#total-amount-section {
|
|
570
|
+
display: block;
|
|
571
|
+
margin-top: ${totalAmountTopMargin};
|
|
572
|
+
margin-bottom: ${totalAmountBottomMargin};
|
|
573
|
+
}
|
|
574
|
+
`;
|
|
575
|
+
}
|
|
576
|
+
}
|