@internetarchive/donation-form 1.0.2 → 1.0.3-alpha-webdev7960.1
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 +157 -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.map +1 -1
- 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.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 +14 -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 +434 -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 +111 -111
- package/src/payment-flow-handlers/handlers/paypal-flow-handler.ts +331 -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/dist/demo/app-root.d.ts +0 -0
- package/dist/demo/app-root.js +0 -2
- package/dist/demo/app-root.js.map +0 -1
|
@@ -1,281 +1,281 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DonationResponse,
|
|
3
|
-
DonationRequest,
|
|
4
|
-
DonationRequestCustomFields,
|
|
5
|
-
DonationType,
|
|
6
|
-
CustomerInfo,
|
|
7
|
-
BillingInfo,
|
|
8
|
-
DonationPaymentInfo,
|
|
9
|
-
PaymentProvider,
|
|
10
|
-
SuccessResponse,
|
|
11
|
-
} from '@internetarchive/donation-form-data-models';
|
|
12
|
-
|
|
13
|
-
import { PaymentProviders } from './payment-providers';
|
|
14
|
-
import { PaymentClientsInterface } from './payment-clients';
|
|
15
|
-
import {
|
|
16
|
-
BraintreeManagerInterface,
|
|
17
|
-
BraintreeEndpointManagerInterface,
|
|
18
|
-
HostingEnvironment,
|
|
19
|
-
BraintreeManagerEvents,
|
|
20
|
-
} from './braintree-interfaces';
|
|
21
|
-
import { HostedFieldConfiguration } from './payment-providers/credit-card/hosted-field-configuration';
|
|
22
|
-
import { PromisedSingleton } from '@internetarchive/promised-singleton';
|
|
23
|
-
import { PaymentProvidersInterface } from './payment-providers-interface';
|
|
24
|
-
import { createNanoEvents, Unsubscribe } from 'nanoevents';
|
|
25
|
-
|
|
26
|
-
/** @inheritdoc */
|
|
27
|
-
export class BraintreeManager implements BraintreeManagerInterface {
|
|
28
|
-
private referrer?: string;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* The origin is made up of campaign / ABTest information that the user originated from.
|
|
32
|
-
*
|
|
33
|
-
* The field is a freeform string so it can be anything, but make sure it's something
|
|
34
|
-
* identifiable so it can be queried in CiviCRM.
|
|
35
|
-
*
|
|
36
|
-
* For instance, we use this format for the Donation Banner:
|
|
37
|
-
* - `{Source}-{Test Name}-{Variant Name}`, eg:
|
|
38
|
-
* - `DonateBanner-Campaign Start 2020-IADefault`
|
|
39
|
-
* - `DonateBanner-Mid Campaign-IAThermometer`
|
|
40
|
-
*
|
|
41
|
-
* For additional specificity, you could add additional info, ie.
|
|
42
|
-
* - `DonateBanner-MidJuly2020 Campaign-VariantA-Button1`
|
|
43
|
-
*
|
|
44
|
-
* @private
|
|
45
|
-
* @type {string}
|
|
46
|
-
* @memberof BraintreeManager
|
|
47
|
-
*/
|
|
48
|
-
private origin?: string;
|
|
49
|
-
|
|
50
|
-
private loggedInUser?: string;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* The Device Data token generated by the DataCollector.
|
|
54
|
-
*
|
|
55
|
-
* This gets submitted for several of the payment providers as an anti-fraud mechanism.
|
|
56
|
-
*
|
|
57
|
-
* @private
|
|
58
|
-
* @type {string}
|
|
59
|
-
* @memberof BraintreeManager
|
|
60
|
-
*/
|
|
61
|
-
private deviceData?: string;
|
|
62
|
-
|
|
63
|
-
private emitter = createNanoEvents<BraintreeManagerEvents>();
|
|
64
|
-
|
|
65
|
-
on<E extends keyof BraintreeManagerEvents>(
|
|
66
|
-
event: E,
|
|
67
|
-
callback: BraintreeManagerEvents[E],
|
|
68
|
-
): Unsubscribe {
|
|
69
|
-
return this.emitter.on(event, callback);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** @inheritdoc */
|
|
73
|
-
paymentProviders: PaymentProvidersInterface;
|
|
74
|
-
|
|
75
|
-
/** @inheritdoc */
|
|
76
|
-
async startup(): Promise<void> {
|
|
77
|
-
return this.collectDeviceData();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** @inheritdoc */
|
|
81
|
-
instance = new PromisedSingleton<braintree.Client>({
|
|
82
|
-
generator: async (): Promise<braintree.Client> => {
|
|
83
|
-
const client = await this.paymentClients.braintreeClient.get();
|
|
84
|
-
return client?.create({ authorization: this.authorizationToken });
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
/** @inheritdoc */
|
|
89
|
-
async submitDonation(options: {
|
|
90
|
-
nonce: string;
|
|
91
|
-
paymentProvider: PaymentProvider;
|
|
92
|
-
donationInfo: DonationPaymentInfo;
|
|
93
|
-
billingInfo: BillingInfo;
|
|
94
|
-
customerInfo: CustomerInfo;
|
|
95
|
-
upsellOnetimeTransactionId?: string;
|
|
96
|
-
customerId?: string;
|
|
97
|
-
recaptchaToken?: string;
|
|
98
|
-
bin?: string; // first 6 digits of CC
|
|
99
|
-
binName?: string; // credit card bank name
|
|
100
|
-
}): Promise<DonationResponse> {
|
|
101
|
-
const customFields = new DonationRequestCustomFields();
|
|
102
|
-
customFields.fee_amount_covered = options.donationInfo.feeAmountCovered;
|
|
103
|
-
customFields.logged_in_user = this.loggedInUser;
|
|
104
|
-
customFields.referrer = this.referrer;
|
|
105
|
-
customFields.origin = this.origin;
|
|
106
|
-
|
|
107
|
-
// This is interesting and applies only to Venmo, but will work for other providers as well.
|
|
108
|
-
// In Safari, `donationInfo` actually comes through as a DonationPaymentInfo object,
|
|
109
|
-
// but in Chrome, it comes through as a plain object so you can't call `.total()` on it to
|
|
110
|
-
// get the total amount and instead have to calculate the total
|
|
111
|
-
const total = DonationPaymentInfo.calculateTotal(
|
|
112
|
-
options.donationInfo.amount,
|
|
113
|
-
options.donationInfo.coverFees,
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
const donationRequest = new DonationRequest({
|
|
117
|
-
deviceData: this.deviceData,
|
|
118
|
-
paymentProvider: options.paymentProvider,
|
|
119
|
-
paymentMethodNonce: options.nonce,
|
|
120
|
-
amount: total,
|
|
121
|
-
donationType: options.donationInfo.donationType,
|
|
122
|
-
customer: options.customerInfo,
|
|
123
|
-
billing: options.billingInfo,
|
|
124
|
-
customFields: customFields,
|
|
125
|
-
upsellOnetimeTransactionId: options.upsellOnetimeTransactionId,
|
|
126
|
-
customerId: options.customerId,
|
|
127
|
-
recaptchaToken: options.recaptchaToken,
|
|
128
|
-
bin: options.bin,
|
|
129
|
-
binName: options.binName,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const jsonResponse = await this.endpointManager.submitData(donationRequest);
|
|
133
|
-
const modeledResponse = new DonationResponse(jsonResponse);
|
|
134
|
-
return modeledResponse;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/** @inheritdoc */
|
|
138
|
-
async submitUpsellDonation(options: {
|
|
139
|
-
oneTimeDonationResponse: SuccessResponse;
|
|
140
|
-
amount: number;
|
|
141
|
-
}): Promise<DonationResponse> {
|
|
142
|
-
const response = options.oneTimeDonationResponse;
|
|
143
|
-
|
|
144
|
-
const donationInfo = new DonationPaymentInfo({
|
|
145
|
-
amount: options.amount,
|
|
146
|
-
donationType: DonationType.Upsell,
|
|
147
|
-
coverFees: false,
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
return this.submitDonation({
|
|
151
|
-
nonce: response.paymentMethodNonce,
|
|
152
|
-
paymentProvider: response.paymentProvider,
|
|
153
|
-
customerId: response.customer_id,
|
|
154
|
-
donationInfo: donationInfo,
|
|
155
|
-
customerInfo: response.customer,
|
|
156
|
-
billingInfo: response.billing,
|
|
157
|
-
upsellOnetimeTransactionId: response.transaction_id,
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/** @inheritdoc */
|
|
162
|
-
donationSuccessful(options: {
|
|
163
|
-
successResponse: SuccessResponse;
|
|
164
|
-
upsellSuccessResponse?: SuccessResponse;
|
|
165
|
-
}): void {
|
|
166
|
-
this.endpointManager.donationSuccessful(options);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private deviceDataCollectionStarted = false;
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Collect Braintree device data. This is used to help fraud detection.
|
|
173
|
-
*
|
|
174
|
-
* @private
|
|
175
|
-
* @returns {Promise<void>}
|
|
176
|
-
* @memberof BraintreeManager
|
|
177
|
-
*/
|
|
178
|
-
private async collectDeviceData(): Promise<void> {
|
|
179
|
-
if (this.deviceDataCollectionStarted) {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
this.deviceDataCollectionStarted = true;
|
|
183
|
-
|
|
184
|
-
const instance = await this.instance.get();
|
|
185
|
-
if (!instance) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return this.paymentClients.dataCollector
|
|
190
|
-
.get()
|
|
191
|
-
.then((collector?: braintree.DataCollector) => {
|
|
192
|
-
return collector?.create({ client: instance, kount: false, paypal: true });
|
|
193
|
-
})
|
|
194
|
-
.then(instance => {
|
|
195
|
-
this.deviceData = instance?.deviceData;
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Braintree Authorization Token
|
|
201
|
-
*
|
|
202
|
-
* @private
|
|
203
|
-
* @type {string}
|
|
204
|
-
* @memberof BraintreeManager
|
|
205
|
-
*/
|
|
206
|
-
private authorizationToken: string;
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* The endpoint manager for network communications
|
|
210
|
-
*
|
|
211
|
-
* @private
|
|
212
|
-
* @type {BraintreeEndpointManagerInterface}
|
|
213
|
-
* @memberof BraintreeManager
|
|
214
|
-
*/
|
|
215
|
-
private endpointManager: BraintreeEndpointManagerInterface;
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* The payment clients container containing the braintree, paypal, and google clients
|
|
219
|
-
*
|
|
220
|
-
* @private
|
|
221
|
-
* @type {PaymentClientsInterface}
|
|
222
|
-
* @memberof BraintreeManager
|
|
223
|
-
*/
|
|
224
|
-
private paymentClients: PaymentClientsInterface;
|
|
225
|
-
|
|
226
|
-
private hostingEnvironment: HostingEnvironment = HostingEnvironment.Development;
|
|
227
|
-
|
|
228
|
-
constructor(options: {
|
|
229
|
-
authorizationToken: string;
|
|
230
|
-
paymentClients: PaymentClientsInterface;
|
|
231
|
-
endpointManager: BraintreeEndpointManagerInterface;
|
|
232
|
-
hostedFieldConfig: HostedFieldConfiguration;
|
|
233
|
-
hostingEnvironment: HostingEnvironment;
|
|
234
|
-
venmoProfileId?: string;
|
|
235
|
-
googlePayMerchantId?: string;
|
|
236
|
-
referrer?: string;
|
|
237
|
-
loggedInUser?: string;
|
|
238
|
-
origin?: string;
|
|
239
|
-
}) {
|
|
240
|
-
this.authorizationToken = options.authorizationToken;
|
|
241
|
-
this.endpointManager = options.endpointManager;
|
|
242
|
-
this.hostingEnvironment = options.hostingEnvironment;
|
|
243
|
-
this.paymentClients = options.paymentClients;
|
|
244
|
-
|
|
245
|
-
this.referrer = options.referrer;
|
|
246
|
-
this.loggedInUser = options.loggedInUser;
|
|
247
|
-
this.origin = options.origin;
|
|
248
|
-
|
|
249
|
-
this.paymentProviders = new PaymentProviders({
|
|
250
|
-
braintreeManager: this,
|
|
251
|
-
paymentClients: this.paymentClients,
|
|
252
|
-
venmoProfileId: options.venmoProfileId,
|
|
253
|
-
googlePayMerchantId: options.googlePayMerchantId,
|
|
254
|
-
hostingEnvironment: options.hostingEnvironment,
|
|
255
|
-
hostedFieldConfig: options.hostedFieldConfig,
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
this.paymentProviders.on('hostedFieldsRetry', (retryNumber: number) => {
|
|
259
|
-
this.emitter.emit('paymentProvidersHostedFieldsRetry', retryNumber);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
this.paymentProviders.on('hostedFieldsFailed', (error: unknown) => {
|
|
263
|
-
this.emitter.emit('paymentProvidersHostedFieldsFailed', error);
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/** @inheritdoc */
|
|
268
|
-
setReferrer(referrer: string): void {
|
|
269
|
-
this.referrer = referrer;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/** @inheritdoc */
|
|
273
|
-
setLoggedInUser(loggedInUser: string): void {
|
|
274
|
-
this.loggedInUser = loggedInUser;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/** @inheritdoc */
|
|
278
|
-
setOrigin(origin: string): void {
|
|
279
|
-
this.origin = origin;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
DonationResponse,
|
|
3
|
+
DonationRequest,
|
|
4
|
+
DonationRequestCustomFields,
|
|
5
|
+
DonationType,
|
|
6
|
+
CustomerInfo,
|
|
7
|
+
BillingInfo,
|
|
8
|
+
DonationPaymentInfo,
|
|
9
|
+
PaymentProvider,
|
|
10
|
+
SuccessResponse,
|
|
11
|
+
} from '@internetarchive/donation-form-data-models';
|
|
12
|
+
|
|
13
|
+
import { PaymentProviders } from './payment-providers';
|
|
14
|
+
import { PaymentClientsInterface } from './payment-clients';
|
|
15
|
+
import {
|
|
16
|
+
BraintreeManagerInterface,
|
|
17
|
+
BraintreeEndpointManagerInterface,
|
|
18
|
+
HostingEnvironment,
|
|
19
|
+
BraintreeManagerEvents,
|
|
20
|
+
} from './braintree-interfaces';
|
|
21
|
+
import { HostedFieldConfiguration } from './payment-providers/credit-card/hosted-field-configuration';
|
|
22
|
+
import { PromisedSingleton } from '@internetarchive/promised-singleton';
|
|
23
|
+
import { PaymentProvidersInterface } from './payment-providers-interface';
|
|
24
|
+
import { createNanoEvents, Unsubscribe } from 'nanoevents';
|
|
25
|
+
|
|
26
|
+
/** @inheritdoc */
|
|
27
|
+
export class BraintreeManager implements BraintreeManagerInterface {
|
|
28
|
+
private referrer?: string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The origin is made up of campaign / ABTest information that the user originated from.
|
|
32
|
+
*
|
|
33
|
+
* The field is a freeform string so it can be anything, but make sure it's something
|
|
34
|
+
* identifiable so it can be queried in CiviCRM.
|
|
35
|
+
*
|
|
36
|
+
* For instance, we use this format for the Donation Banner:
|
|
37
|
+
* - `{Source}-{Test Name}-{Variant Name}`, eg:
|
|
38
|
+
* - `DonateBanner-Campaign Start 2020-IADefault`
|
|
39
|
+
* - `DonateBanner-Mid Campaign-IAThermometer`
|
|
40
|
+
*
|
|
41
|
+
* For additional specificity, you could add additional info, ie.
|
|
42
|
+
* - `DonateBanner-MidJuly2020 Campaign-VariantA-Button1`
|
|
43
|
+
*
|
|
44
|
+
* @private
|
|
45
|
+
* @type {string}
|
|
46
|
+
* @memberof BraintreeManager
|
|
47
|
+
*/
|
|
48
|
+
private origin?: string;
|
|
49
|
+
|
|
50
|
+
private loggedInUser?: string;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The Device Data token generated by the DataCollector.
|
|
54
|
+
*
|
|
55
|
+
* This gets submitted for several of the payment providers as an anti-fraud mechanism.
|
|
56
|
+
*
|
|
57
|
+
* @private
|
|
58
|
+
* @type {string}
|
|
59
|
+
* @memberof BraintreeManager
|
|
60
|
+
*/
|
|
61
|
+
private deviceData?: string;
|
|
62
|
+
|
|
63
|
+
private emitter = createNanoEvents<BraintreeManagerEvents>();
|
|
64
|
+
|
|
65
|
+
on<E extends keyof BraintreeManagerEvents>(
|
|
66
|
+
event: E,
|
|
67
|
+
callback: BraintreeManagerEvents[E],
|
|
68
|
+
): Unsubscribe {
|
|
69
|
+
return this.emitter.on(event, callback);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** @inheritdoc */
|
|
73
|
+
paymentProviders: PaymentProvidersInterface;
|
|
74
|
+
|
|
75
|
+
/** @inheritdoc */
|
|
76
|
+
async startup(): Promise<void> {
|
|
77
|
+
return this.collectDeviceData();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** @inheritdoc */
|
|
81
|
+
instance = new PromisedSingleton<braintree.Client>({
|
|
82
|
+
generator: async (): Promise<braintree.Client> => {
|
|
83
|
+
const client = await this.paymentClients.braintreeClient.get();
|
|
84
|
+
return client?.create({ authorization: this.authorizationToken });
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
/** @inheritdoc */
|
|
89
|
+
async submitDonation(options: {
|
|
90
|
+
nonce: string;
|
|
91
|
+
paymentProvider: PaymentProvider;
|
|
92
|
+
donationInfo: DonationPaymentInfo;
|
|
93
|
+
billingInfo: BillingInfo;
|
|
94
|
+
customerInfo: CustomerInfo;
|
|
95
|
+
upsellOnetimeTransactionId?: string;
|
|
96
|
+
customerId?: string;
|
|
97
|
+
recaptchaToken?: string;
|
|
98
|
+
bin?: string; // first 6 digits of CC
|
|
99
|
+
binName?: string; // credit card bank name
|
|
100
|
+
}): Promise<DonationResponse> {
|
|
101
|
+
const customFields = new DonationRequestCustomFields();
|
|
102
|
+
customFields.fee_amount_covered = options.donationInfo.feeAmountCovered;
|
|
103
|
+
customFields.logged_in_user = this.loggedInUser;
|
|
104
|
+
customFields.referrer = this.referrer;
|
|
105
|
+
customFields.origin = this.origin;
|
|
106
|
+
|
|
107
|
+
// This is interesting and applies only to Venmo, but will work for other providers as well.
|
|
108
|
+
// In Safari, `donationInfo` actually comes through as a DonationPaymentInfo object,
|
|
109
|
+
// but in Chrome, it comes through as a plain object so you can't call `.total()` on it to
|
|
110
|
+
// get the total amount and instead have to calculate the total
|
|
111
|
+
const total = DonationPaymentInfo.calculateTotal(
|
|
112
|
+
options.donationInfo.amount,
|
|
113
|
+
options.donationInfo.coverFees,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const donationRequest = new DonationRequest({
|
|
117
|
+
deviceData: this.deviceData,
|
|
118
|
+
paymentProvider: options.paymentProvider,
|
|
119
|
+
paymentMethodNonce: options.nonce,
|
|
120
|
+
amount: total,
|
|
121
|
+
donationType: options.donationInfo.donationType,
|
|
122
|
+
customer: options.customerInfo,
|
|
123
|
+
billing: options.billingInfo,
|
|
124
|
+
customFields: customFields,
|
|
125
|
+
upsellOnetimeTransactionId: options.upsellOnetimeTransactionId,
|
|
126
|
+
customerId: options.customerId,
|
|
127
|
+
recaptchaToken: options.recaptchaToken,
|
|
128
|
+
bin: options.bin,
|
|
129
|
+
binName: options.binName,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const jsonResponse = await this.endpointManager.submitData(donationRequest);
|
|
133
|
+
const modeledResponse = new DonationResponse(jsonResponse);
|
|
134
|
+
return modeledResponse;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** @inheritdoc */
|
|
138
|
+
async submitUpsellDonation(options: {
|
|
139
|
+
oneTimeDonationResponse: SuccessResponse;
|
|
140
|
+
amount: number;
|
|
141
|
+
}): Promise<DonationResponse> {
|
|
142
|
+
const response = options.oneTimeDonationResponse;
|
|
143
|
+
|
|
144
|
+
const donationInfo = new DonationPaymentInfo({
|
|
145
|
+
amount: options.amount,
|
|
146
|
+
donationType: DonationType.Upsell,
|
|
147
|
+
coverFees: false,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return this.submitDonation({
|
|
151
|
+
nonce: response.paymentMethodNonce,
|
|
152
|
+
paymentProvider: response.paymentProvider,
|
|
153
|
+
customerId: response.customer_id,
|
|
154
|
+
donationInfo: donationInfo,
|
|
155
|
+
customerInfo: response.customer,
|
|
156
|
+
billingInfo: response.billing,
|
|
157
|
+
upsellOnetimeTransactionId: response.transaction_id,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** @inheritdoc */
|
|
162
|
+
donationSuccessful(options: {
|
|
163
|
+
successResponse: SuccessResponse;
|
|
164
|
+
upsellSuccessResponse?: SuccessResponse;
|
|
165
|
+
}): void {
|
|
166
|
+
this.endpointManager.donationSuccessful(options);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private deviceDataCollectionStarted = false;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Collect Braintree device data. This is used to help fraud detection.
|
|
173
|
+
*
|
|
174
|
+
* @private
|
|
175
|
+
* @returns {Promise<void>}
|
|
176
|
+
* @memberof BraintreeManager
|
|
177
|
+
*/
|
|
178
|
+
private async collectDeviceData(): Promise<void> {
|
|
179
|
+
if (this.deviceDataCollectionStarted) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
this.deviceDataCollectionStarted = true;
|
|
183
|
+
|
|
184
|
+
const instance = await this.instance.get();
|
|
185
|
+
if (!instance) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return this.paymentClients.dataCollector
|
|
190
|
+
.get()
|
|
191
|
+
.then((collector?: braintree.DataCollector) => {
|
|
192
|
+
return collector?.create({ client: instance, kount: false, paypal: true });
|
|
193
|
+
})
|
|
194
|
+
.then(instance => {
|
|
195
|
+
this.deviceData = instance?.deviceData;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Braintree Authorization Token
|
|
201
|
+
*
|
|
202
|
+
* @private
|
|
203
|
+
* @type {string}
|
|
204
|
+
* @memberof BraintreeManager
|
|
205
|
+
*/
|
|
206
|
+
private authorizationToken: string;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* The endpoint manager for network communications
|
|
210
|
+
*
|
|
211
|
+
* @private
|
|
212
|
+
* @type {BraintreeEndpointManagerInterface}
|
|
213
|
+
* @memberof BraintreeManager
|
|
214
|
+
*/
|
|
215
|
+
private endpointManager: BraintreeEndpointManagerInterface;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The payment clients container containing the braintree, paypal, and google clients
|
|
219
|
+
*
|
|
220
|
+
* @private
|
|
221
|
+
* @type {PaymentClientsInterface}
|
|
222
|
+
* @memberof BraintreeManager
|
|
223
|
+
*/
|
|
224
|
+
private paymentClients: PaymentClientsInterface;
|
|
225
|
+
|
|
226
|
+
private hostingEnvironment: HostingEnvironment = HostingEnvironment.Development;
|
|
227
|
+
|
|
228
|
+
constructor(options: {
|
|
229
|
+
authorizationToken: string;
|
|
230
|
+
paymentClients: PaymentClientsInterface;
|
|
231
|
+
endpointManager: BraintreeEndpointManagerInterface;
|
|
232
|
+
hostedFieldConfig: HostedFieldConfiguration;
|
|
233
|
+
hostingEnvironment: HostingEnvironment;
|
|
234
|
+
venmoProfileId?: string;
|
|
235
|
+
googlePayMerchantId?: string;
|
|
236
|
+
referrer?: string;
|
|
237
|
+
loggedInUser?: string;
|
|
238
|
+
origin?: string;
|
|
239
|
+
}) {
|
|
240
|
+
this.authorizationToken = options.authorizationToken;
|
|
241
|
+
this.endpointManager = options.endpointManager;
|
|
242
|
+
this.hostingEnvironment = options.hostingEnvironment;
|
|
243
|
+
this.paymentClients = options.paymentClients;
|
|
244
|
+
|
|
245
|
+
this.referrer = options.referrer;
|
|
246
|
+
this.loggedInUser = options.loggedInUser;
|
|
247
|
+
this.origin = options.origin;
|
|
248
|
+
|
|
249
|
+
this.paymentProviders = new PaymentProviders({
|
|
250
|
+
braintreeManager: this,
|
|
251
|
+
paymentClients: this.paymentClients,
|
|
252
|
+
venmoProfileId: options.venmoProfileId,
|
|
253
|
+
googlePayMerchantId: options.googlePayMerchantId,
|
|
254
|
+
hostingEnvironment: options.hostingEnvironment,
|
|
255
|
+
hostedFieldConfig: options.hostedFieldConfig,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
this.paymentProviders.on('hostedFieldsRetry', (retryNumber: number) => {
|
|
259
|
+
this.emitter.emit('paymentProvidersHostedFieldsRetry', retryNumber);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
this.paymentProviders.on('hostedFieldsFailed', (error: unknown) => {
|
|
263
|
+
this.emitter.emit('paymentProvidersHostedFieldsFailed', error);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** @inheritdoc */
|
|
268
|
+
setReferrer(referrer: string): void {
|
|
269
|
+
this.referrer = referrer;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** @inheritdoc */
|
|
273
|
+
setLoggedInUser(loggedInUser: string): void {
|
|
274
|
+
this.loggedInUser = loggedInUser;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** @inheritdoc */
|
|
278
|
+
setOrigin(origin: string): void {
|
|
279
|
+
this.origin = origin;
|
|
280
|
+
}
|
|
281
|
+
}
|