@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.
Files changed (210) hide show
  1. package/LICENSE +661 -661
  2. package/README.md +115 -115
  3. package/dist/demo/braintree-endpoint-manager.js.map +1 -1
  4. package/dist/demo/demo-analytics-handler.js.map +1 -1
  5. package/dist/demo/submit-form-with.js.map +1 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/src/braintree-manager/braintree-interfaces.js.map +1 -1
  8. package/dist/src/braintree-manager/braintree-manager.js.map +1 -1
  9. package/dist/src/braintree-manager/payment-clients.js.map +1 -1
  10. package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay-interface.js.map +1 -1
  11. package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-delegate.js.map +1 -1
  12. package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-interface.js.map +1 -1
  13. package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource.js.map +1 -1
  14. package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-manager.js.map +1 -1
  15. package/dist/src/braintree-manager/payment-providers/apple-pay/apple-pay.js.map +1 -1
  16. package/dist/src/braintree-manager/payment-providers/credit-card/credit-card-interface.js.map +1 -1
  17. package/dist/src/braintree-manager/payment-providers/credit-card/credit-card.js.map +1 -1
  18. package/dist/src/braintree-manager/payment-providers/credit-card/hosted-field-configuration.js.map +1 -1
  19. package/dist/src/braintree-manager/payment-providers/credit-card/hosted-field-container.js.map +1 -1
  20. package/dist/src/braintree-manager/payment-providers/google-pay-interface.js.map +1 -1
  21. package/dist/src/braintree-manager/payment-providers/google-pay.js.map +1 -1
  22. package/dist/src/braintree-manager/payment-providers/paypal/paypal-button-datasource.js.map +1 -1
  23. package/dist/src/braintree-manager/payment-providers/paypal/paypal-interface.js.map +1 -1
  24. package/dist/src/braintree-manager/payment-providers/paypal/paypal.js.map +1 -1
  25. package/dist/src/braintree-manager/payment-providers/venmo-interface.js.map +1 -1
  26. package/dist/src/braintree-manager/payment-providers/venmo.js.map +1 -1
  27. package/dist/src/braintree-manager/payment-providers-interface.js.map +1 -1
  28. package/dist/src/braintree-manager/payment-providers.js.map +1 -1
  29. package/dist/src/donation-form-controller.js +123 -123
  30. package/dist/src/donation-form-controller.js.map +1 -1
  31. package/dist/src/donation-form-error.js.map +1 -1
  32. package/dist/src/donation-form.js +107 -107
  33. package/dist/src/donation-form.js.map +1 -1
  34. package/dist/src/form-elements/badged-input.js +47 -47
  35. package/dist/src/form-elements/badged-input.js.map +1 -1
  36. package/dist/src/form-elements/contact-form/autocomplete-field-options.js.map +1 -1
  37. package/dist/src/form-elements/contact-form/contact-form.js +159 -157
  38. package/dist/src/form-elements/contact-form/contact-form.js.map +1 -1
  39. package/dist/src/form-elements/contact-form/countries.js.map +1 -1
  40. package/dist/src/form-elements/header/donation-form-header.js +14 -14
  41. package/dist/src/form-elements/header/donation-form-header.js.map +1 -1
  42. package/dist/src/form-elements/header/donation-summary.js +15 -15
  43. package/dist/src/form-elements/header/donation-summary.js.map +1 -1
  44. package/dist/src/form-elements/payment-selector.js +164 -164
  45. package/dist/src/form-elements/payment-selector.js.map +1 -1
  46. package/dist/src/form-elements/total-amount.js +16 -16
  47. package/dist/src/form-elements/total-amount.js.map +1 -1
  48. package/dist/src/modals/confirm-donation-modal-content.js +51 -51
  49. package/dist/src/modals/confirm-donation-modal-content.js.map +1 -1
  50. package/dist/src/modals/error-modal-content.js +22 -22
  51. package/dist/src/modals/error-modal-content.js.map +1 -1
  52. package/dist/src/modals/upsell-modal-content.js +182 -182
  53. package/dist/src/modals/upsell-modal-content.js.map +1 -1
  54. package/dist/src/payment-flow-handlers/donation-flow-modal-manager.js +20 -20
  55. package/dist/src/payment-flow-handlers/donation-flow-modal-manager.js.map +1 -1
  56. package/dist/src/payment-flow-handlers/handlers/applepay-flow-handler.js.map +1 -1
  57. package/dist/src/payment-flow-handlers/handlers/creditcard-flow-handler.js.map +1 -1
  58. package/dist/src/payment-flow-handlers/handlers/googlepay-flow-handler.js +2 -0
  59. package/dist/src/payment-flow-handlers/handlers/googlepay-flow-handler.js.map +1 -1
  60. package/dist/src/payment-flow-handlers/handlers/paypal-flow-handler.js +2 -0
  61. package/dist/src/payment-flow-handlers/handlers/paypal-flow-handler.js.map +1 -1
  62. package/dist/src/payment-flow-handlers/handlers/venmo-flow-handler.js.map +1 -1
  63. package/dist/src/payment-flow-handlers/handlers/venmo-restoration-state-handler.js.map +1 -1
  64. package/dist/src/payment-flow-handlers/payment-flow-handlers.js.map +1 -1
  65. package/dist/src/recaptcha-manager/recaptcha-manager.js.map +1 -1
  66. package/dist/src/util/promisedSleep.js.map +1 -1
  67. package/dist/test/helpers/fillInContactForm.js.map +1 -1
  68. package/dist/test/mocks/flow-handlers/individual-handlers/mock-applepay-flow-handler.js.map +1 -1
  69. package/dist/test/mocks/flow-handlers/individual-handlers/mock-creditcard-flow-handler.js.map +1 -1
  70. package/dist/test/mocks/flow-handlers/individual-handlers/mock-googlepay-flow-handler.js.map +1 -1
  71. package/dist/test/mocks/flow-handlers/individual-handlers/mock-paypal-flow-handler.js.map +1 -1
  72. package/dist/test/mocks/flow-handlers/individual-handlers/mock-venmo-flow-handler.js.map +1 -1
  73. package/dist/test/mocks/flow-handlers/mock-payment-flow-handlers.js.map +1 -1
  74. package/dist/test/mocks/mock-braintree-manager.js.map +1 -1
  75. package/dist/test/mocks/mock-donation-info.js.map +1 -1
  76. package/dist/test/mocks/mock-endpoint-manager.js.map +1 -1
  77. package/dist/test/mocks/mock-hosted-fields-config.js.map +1 -1
  78. package/dist/test/mocks/mock-hosted-fields-container.js.map +1 -1
  79. package/dist/test/mocks/mock-lazy-loader.js.map +1 -1
  80. package/dist/test/mocks/mock-modal-manager.js.map +1 -1
  81. package/dist/test/mocks/mock-payment-clients.js.map +1 -1
  82. package/dist/test/mocks/mock-paypal-button-renderer.js.map +1 -1
  83. package/dist/test/mocks/mock-recaptcha-manager.js.map +1 -1
  84. package/dist/test/mocks/models/mock-billing-info.js +2 -0
  85. package/dist/test/mocks/models/mock-billing-info.js.map +1 -1
  86. package/dist/test/mocks/models/mock-custom-fields.js.map +1 -1
  87. package/dist/test/mocks/models/mock-customer-info.js.map +1 -1
  88. package/dist/test/mocks/models/mock-donation-request.js.map +1 -1
  89. package/dist/test/mocks/models/mock-success-response.js.map +1 -1
  90. package/dist/test/mocks/payment-clients/mock-applepay-client.js.map +1 -1
  91. package/dist/test/mocks/payment-clients/mock-applepay-payment.js.map +1 -1
  92. package/dist/test/mocks/payment-clients/mock-applepay-paymentauthorizedevent.js.map +1 -1
  93. package/dist/test/mocks/payment-clients/mock-applepay-session.js.map +1 -1
  94. package/dist/test/mocks/payment-clients/mock-applepay-sessionmanager.js.map +1 -1
  95. package/dist/test/mocks/payment-clients/mock-applepay-validatemerchantevent.js.map +1 -1
  96. package/dist/test/mocks/payment-clients/mock-braintree-client.js.map +1 -1
  97. package/dist/test/mocks/payment-clients/mock-data-collector.js.map +1 -1
  98. package/dist/test/mocks/payment-clients/mock-googlepay-client.js.map +1 -1
  99. package/dist/test/mocks/payment-clients/mock-googlepay-library.js.map +1 -1
  100. package/dist/test/mocks/payment-clients/mock-grecaptcha.js.map +1 -1
  101. package/dist/test/mocks/payment-clients/mock-hostedfields-client.js.map +1 -1
  102. package/dist/test/mocks/payment-clients/mock-hostedfieldstateobject-generator.js.map +1 -1
  103. package/dist/test/mocks/payment-clients/mock-hostedfieldtokenizepayload.js.map +1 -1
  104. package/dist/test/mocks/payment-clients/mock-paypal-client.js.map +1 -1
  105. package/dist/test/mocks/payment-clients/mock-paypal-library.js.map +1 -1
  106. package/dist/test/mocks/payment-clients/mock-venmo-client.js.map +1 -1
  107. package/dist/test/mocks/payment-providers/individual-providers/mock-applepay-datasource-delegate.js.map +1 -1
  108. package/dist/test/mocks/payment-providers/individual-providers/mock-applepay-handler.js.map +1 -1
  109. package/dist/test/mocks/payment-providers/individual-providers/mock-creditcard-handler.js.map +1 -1
  110. package/dist/test/mocks/payment-providers/individual-providers/mock-googlepay-handler.js.map +1 -1
  111. package/dist/test/mocks/payment-providers/individual-providers/mock-paypal-button-datasource-delegate.js.map +1 -1
  112. package/dist/test/mocks/payment-providers/individual-providers/mock-paypal-button-datasource.js.map +1 -1
  113. package/dist/test/mocks/payment-providers/individual-providers/mock-paypal-handler.js.map +1 -1
  114. package/dist/test/mocks/payment-providers/individual-providers/mock-venmo-handler.js.map +1 -1
  115. package/dist/test/mocks/payment-providers/mock-payment-providers.js.map +1 -1
  116. package/dist/test/tests/braintree-manager.test.js.map +1 -1
  117. package/dist/test/tests/donation-form-controller.test.js +39 -39
  118. package/dist/test/tests/donation-form-controller.test.js.map +1 -1
  119. package/dist/test/tests/donation-form.test.js +4 -4
  120. package/dist/test/tests/donation-form.test.js.map +1 -1
  121. package/dist/test/tests/flow-handlers/donation-flow-modal-manager.test.js +16 -14
  122. package/dist/test/tests/flow-handlers/donation-flow-modal-manager.test.js.map +1 -1
  123. package/dist/test/tests/form-elements/donation-summary.test.js.map +1 -1
  124. package/dist/test/tests/form-elements/payment-selector.test.js.map +1 -1
  125. package/dist/test/tests/modals/error-modal-content.test.js +2 -2
  126. package/dist/test/tests/modals/error-modal-content.test.js.map +1 -1
  127. package/dist/test/tests/modals/upsell-modal-content.test.js +31 -31
  128. package/dist/test/tests/modals/upsell-modal-content.test.js.map +1 -1
  129. package/dist/test/tests/models/donation-payment-info.test.js.map +1 -1
  130. package/dist/test/tests/payment-clients.test.js.map +1 -1
  131. package/dist/test/tests/payment-providers/applepay-sessiondatasource.test.js.map +1 -1
  132. package/dist/test/tests/payment-providers/applepay-sessionmanager.test.js.map +1 -1
  133. package/dist/test/tests/payment-providers/applepay.test.js.map +1 -1
  134. package/dist/test/tests/payment-providers/creditcard.test.js.map +1 -1
  135. package/dist/test/tests/payment-providers/googlepay.test.js.map +1 -1
  136. package/dist/test/tests/payment-providers/payment-providers.test.js.map +1 -1
  137. package/dist/test/tests/payment-providers/paypal-button-datasource.test.js.map +1 -1
  138. package/dist/test/tests/payment-providers/paypal.test.js.map +1 -1
  139. package/dist/test/tests/payment-providers/venmo.test.js.map +1 -1
  140. package/dist/test/tests/recaptcha-manager.test.js.map +1 -1
  141. package/package.json +107 -107
  142. package/src/@types/analytics-handler/index.d.ts +8 -8
  143. package/src/@types/braintree-web/LICENSE +21 -21
  144. package/src/@types/braintree-web/index.d.ts +93 -93
  145. package/src/@types/braintree-web/modules/american-express.d.ts +50 -50
  146. package/src/@types/braintree-web/modules/apple-pay.d.ts +213 -213
  147. package/src/@types/braintree-web/modules/client.d.ts +103 -103
  148. package/src/@types/braintree-web/modules/core.d.ts +34 -34
  149. package/src/@types/braintree-web/modules/data-collector.d.ts +13 -13
  150. package/src/@types/braintree-web/modules/google-payment.d.ts +269 -269
  151. package/src/@types/braintree-web/modules/hosted-fields.d.ts +366 -366
  152. package/src/@types/braintree-web/modules/paypal-checkout.d.ts +262 -262
  153. package/src/@types/braintree-web/modules/paypal.d.ts +177 -177
  154. package/src/@types/braintree-web/modules/three-d-secure.d.ts +141 -141
  155. package/src/@types/braintree-web/modules/unionpay.d.ts +224 -224
  156. package/src/@types/braintree-web/modules/us-bank-account.d.ts +81 -81
  157. package/src/@types/braintree-web/modules/venmo.d.ts +110 -110
  158. package/src/@types/braintree-web/package.json +64 -64
  159. package/src/@types/paypal-checkout-components/LICENSE +21 -21
  160. package/src/@types/paypal-checkout-components/index.d.ts +67 -67
  161. package/src/@types/paypal-checkout-components/modules/button.d.ts +50 -50
  162. package/src/@types/paypal-checkout-components/modules/callback-data.d.ts +244 -244
  163. package/src/@types/paypal-checkout-components/modules/configuration.d.ts +114 -114
  164. package/src/@types/paypal-checkout-components/package.json +58 -58
  165. package/src/braintree-manager/braintree-interfaces.ts +172 -172
  166. package/src/braintree-manager/braintree-manager.ts +281 -281
  167. package/src/braintree-manager/payment-clients.ts +146 -146
  168. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-interface.ts +13 -13
  169. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-delegate.ts +8 -8
  170. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-interface.ts +10 -10
  171. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource.ts +119 -119
  172. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-manager.ts +21 -21
  173. package/src/braintree-manager/payment-providers/apple-pay/apple-pay.ts +97 -97
  174. package/src/braintree-manager/payment-providers/credit-card/credit-card-interface.ts +21 -21
  175. package/src/braintree-manager/payment-providers/credit-card/credit-card.ts +130 -130
  176. package/src/braintree-manager/payment-providers/credit-card/hosted-field-configuration.ts +19 -19
  177. package/src/braintree-manager/payment-providers/credit-card/hosted-field-container.ts +85 -85
  178. package/src/braintree-manager/payment-providers/google-pay-interface.ts +8 -8
  179. package/src/braintree-manager/payment-providers/google-pay.ts +59 -59
  180. package/src/braintree-manager/payment-providers/paypal/paypal-button-datasource.ts +218 -218
  181. package/src/braintree-manager/payment-providers/paypal/paypal-interface.ts +13 -13
  182. package/src/braintree-manager/payment-providers/paypal/paypal.ts +78 -78
  183. package/src/braintree-manager/payment-providers/venmo-interface.ts +8 -8
  184. package/src/braintree-manager/payment-providers/venmo.ts +67 -67
  185. package/src/braintree-manager/payment-providers-interface.ts +25 -25
  186. package/src/braintree-manager/payment-providers.ts +147 -147
  187. package/src/donation-form-controller.ts +623 -623
  188. package/src/donation-form-error.ts +6 -6
  189. package/src/donation-form.ts +576 -576
  190. package/src/form-elements/badged-input.ts +109 -109
  191. package/src/form-elements/contact-form/autocomplete-field-options.ts +63 -63
  192. package/src/form-elements/contact-form/contact-form.ts +436 -434
  193. package/src/form-elements/contact-form/countries.ts +252 -252
  194. package/src/form-elements/header/donation-form-header.ts +98 -98
  195. package/src/form-elements/header/donation-summary.ts +61 -61
  196. package/src/form-elements/payment-selector.ts +365 -365
  197. package/src/form-elements/total-amount.ts +46 -46
  198. package/src/modals/confirm-donation-modal-content.ts +168 -168
  199. package/src/modals/error-modal-content.ts +48 -48
  200. package/src/modals/upsell-modal-content.ts +284 -284
  201. package/src/payment-flow-handlers/donation-flow-modal-manager.ts +439 -439
  202. package/src/payment-flow-handlers/handlers/applepay-flow-handler.ts +109 -109
  203. package/src/payment-flow-handlers/handlers/creditcard-flow-handler.ts +232 -232
  204. package/src/payment-flow-handlers/handlers/googlepay-flow-handler.ts +113 -111
  205. package/src/payment-flow-handlers/handlers/paypal-flow-handler.ts +333 -331
  206. package/src/payment-flow-handlers/handlers/venmo-flow-handler.ts +119 -119
  207. package/src/payment-flow-handlers/handlers/venmo-restoration-state-handler.ts +127 -127
  208. package/src/payment-flow-handlers/payment-flow-handlers.ts +218 -218
  209. package/src/recaptcha-manager/recaptcha-manager.ts +123 -123
  210. package/src/util/promisedSleep.ts +3 -3
@@ -1,232 +1,232 @@
1
- import { createNanoEvents, Emitter, Unsubscribe } from 'nanoevents';
2
-
3
- import { BraintreeManagerInterface } from '../../braintree-manager/braintree-interfaces';
4
- import { RecaptchaManagerInterface } from '../../recaptcha-manager/recaptcha-manager';
5
-
6
- import {
7
- DonorContactInfo,
8
- DonationPaymentInfo,
9
- PaymentProvider,
10
- } from '@internetarchive/donation-form-data-models';
11
- import { DonationFlowModalManagerInterface } from '../donation-flow-modal-manager';
12
- import { HostedFieldName } from '../../braintree-manager/payment-providers/credit-card/hosted-field-container';
13
- import { BadgedInput } from '../../form-elements/badged-input';
14
- import { BraintreeError } from '../../@types/braintree-web';
15
-
16
- export interface CreditCardFlowHandlerInterface {
17
- /**
18
- * Set up the hosted fields with event bindings
19
- *
20
- * @returns {Promise<void>}
21
- * @memberof CreditCardFlowHandlerInterface
22
- */
23
- startup(): Promise<void>;
24
-
25
- /**
26
- * Tokenize the hosted fields.
27
- *
28
- * This also performs validation so we can call this before initiating the payment to
29
- * display any error messaging.
30
- *
31
- * @returns {(Promise<braintree.HostedFieldsTokenizePayload | undefined>)}
32
- * @memberof CreditCardFlowHandlerInterface
33
- */
34
- tokenizeFields(): Promise<braintree.HostedFieldsTokenizePayload | undefined>;
35
-
36
- /**
37
- * Initiate the payment flow.
38
- *
39
- * You must get the response from `tokenizeFields()` first before this to validate the hosted fields.
40
- *
41
- * @param {braintree.HostedFieldsTokenizePayload} hostedFieldsResponse
42
- * @param {DonationPaymentInfo} donationInfo
43
- * @param {DonorContactInfo} donorContactInfo
44
- * @returns {Promise<void>}
45
- * @memberof CreditCardFlowHandlerInterface
46
- */
47
- paymentInitiated(
48
- hostedFieldsResponse: braintree.HostedFieldsTokenizePayload,
49
- donationInfo: DonationPaymentInfo,
50
- donorContactInfo: DonorContactInfo,
51
- ): Promise<void>;
52
-
53
- /**
54
- * Bind to receive credit card flow handler events
55
- *
56
- * @template E
57
- * @param {E} event
58
- * @param {CreditCardFlowHandlerEvents[E]} callback
59
- * @returns {Unsubscribe}
60
- * @memberof CreditCardFlowHandlerInterface
61
- */
62
- on<E extends keyof CreditCardFlowHandlerEvents>(
63
- event: E,
64
- callback: CreditCardFlowHandlerEvents[E],
65
- ): Unsubscribe;
66
- }
67
-
68
- export interface CreditCardFlowHandlerEvents {
69
- validityChanged: (isValid: boolean) => void;
70
- }
71
-
72
- export class CreditCardFlowHandler implements CreditCardFlowHandlerInterface {
73
- private donationFlowModalManager: DonationFlowModalManagerInterface;
74
-
75
- private braintreeManager: BraintreeManagerInterface;
76
-
77
- private recaptchaManager: RecaptchaManagerInterface;
78
-
79
- private emitter: Emitter<CreditCardFlowHandlerEvents>;
80
-
81
- constructor(options: {
82
- braintreeManager: BraintreeManagerInterface;
83
- donationFlowModalManager: DonationFlowModalManagerInterface;
84
- recaptchaManager: RecaptchaManagerInterface;
85
- }) {
86
- this.braintreeManager = options.braintreeManager;
87
- this.donationFlowModalManager = options.donationFlowModalManager;
88
- this.recaptchaManager = options.recaptchaManager;
89
- this.emitter = createNanoEvents<CreditCardFlowHandlerEvents>();
90
- }
91
-
92
- /** @inheritdoc */
93
- on<E extends keyof CreditCardFlowHandlerEvents>(
94
- event: E,
95
- callback: CreditCardFlowHandlerEvents[E],
96
- ): Unsubscribe {
97
- return this.emitter.on(event, callback);
98
- }
99
-
100
- private started = false;
101
-
102
- /** @inheritdoc */
103
- async startup(): Promise<void> {
104
- if (this.started) {
105
- return;
106
- }
107
- this.started = true;
108
-
109
- const handler = await this.braintreeManager?.paymentProviders.creditCardHandler.get();
110
- const instance = await handler?.instance.get();
111
-
112
- // NOTE: The `focus` and `blur` callback logic must work in conjunction with
113
- // the `HostedFieldContainer` class. We use the `HostedFieldContainer` for
114
- // managing the hosted field error state in other parts of the form, but
115
- // since we can only get event callbacks from the hosted fields like this,
116
- // this has to operate independently and modify the CSS styles by itself
117
- instance?.on('focus', (event: braintree.HostedFieldsStateObject): void => {
118
- const { emittedBy, fields } = event;
119
- const fieldInFocus = fields[emittedBy];
120
- const { container } = fieldInFocus;
121
- (container.parentElement as BadgedInput).error = false;
122
- handler.hideErrorMessage();
123
- });
124
-
125
- instance?.on('blur', (event: braintree.HostedFieldsStateObject): void => {
126
- const { emittedBy, fields } = event;
127
- const fieldInFocus = fields[emittedBy];
128
- const { container, isEmpty, isValid } = fieldInFocus;
129
- if (isEmpty || !isValid) {
130
- (container.parentElement as BadgedInput).error = true;
131
- }
132
- });
133
-
134
- instance?.on('validityChange', (event: braintree.HostedFieldsStateObject): void => {
135
- const { fields } = event;
136
- const isValid = fields.cvv.isValid && fields.expirationDate.isValid && fields.number.isValid;
137
- this.emitter.emit('validityChanged', isValid);
138
- });
139
- }
140
-
141
- /** @inheritdoc */
142
- async tokenizeFields(): Promise<braintree.HostedFieldsTokenizePayload | undefined> {
143
- let hostedFieldsResponse: braintree.HostedFieldsTokenizePayload | undefined;
144
-
145
- const handler = await this.braintreeManager.paymentProviders.creditCardHandler.get();
146
-
147
- try {
148
- hostedFieldsResponse = await handler?.tokenizeHostedFields();
149
- } catch (error) {
150
- this.handleHostedFieldTokenizationError(error as BraintreeError);
151
- return;
152
- }
153
-
154
- return hostedFieldsResponse;
155
- }
156
-
157
- /** @inheritdoc */
158
- async paymentInitiated(
159
- hostedFieldsResponse: braintree.HostedFieldsTokenizePayload,
160
- donationInfo: DonationPaymentInfo,
161
- donorContactInfo: DonorContactInfo,
162
- ): Promise<void> {
163
- let recaptchaToken: string | undefined;
164
-
165
- try {
166
- recaptchaToken = await this.recaptchaManager.execute();
167
- } catch (error) {
168
- this.donationFlowModalManager.showErrorModal({
169
- message: `Recaptcha failure`,
170
- });
171
- return;
172
- }
173
-
174
- this.donationFlowModalManager.startDonationSubmissionFlow({
175
- nonce: hostedFieldsResponse.nonce,
176
- paymentProvider: PaymentProvider.CreditCard,
177
- recaptchaToken: recaptchaToken,
178
- bin: hostedFieldsResponse.details.bin,
179
- donationInfo: donationInfo,
180
- customerInfo: donorContactInfo.customer,
181
- billingInfo: donorContactInfo.billing,
182
- });
183
- }
184
-
185
- private async handleHostedFieldTokenizationError(error: braintree.BraintreeError): Promise<void> {
186
- const handler = await this.braintreeManager.paymentProviders.creditCardHandler.get();
187
-
188
- handler.showErrorMessage();
189
-
190
- switch (error.code) {
191
- case 'HOSTED_FIELDS_FIELDS_EMPTY':
192
- // occurs when none of the fields are filled in
193
- handler.markFieldErrors([
194
- HostedFieldName.Number,
195
- HostedFieldName.CVV,
196
- HostedFieldName.ExpirationDate,
197
- ]);
198
- break;
199
- case 'HOSTED_FIELDS_FIELDS_INVALID':
200
- // occurs when certain fields do not pass client side validation
201
- Object.keys(error.details.invalidFields).forEach(key => {
202
- handler.markFieldErrors([key as HostedFieldName]);
203
- });
204
- break;
205
- case 'HOSTED_FIELDS_TOKENIZATION_FAIL_ON_DUPLICATE':
206
- // occurs when:
207
- // * the client token used for client authorization was generated
208
- // with a customer ID and the fail on duplicate payment method
209
- // option is set to true
210
- // * the card being tokenized has previously been vaulted (with any customer)
211
- break;
212
- case 'HOSTED_FIELDS_TOKENIZATION_CVV_VERIFICATION_FAILED':
213
- // occurs when:
214
- // * the client token used for client authorization was generated
215
- // with a customer ID and the verify card option is set to true
216
- // and you have credit card verification turned on in the Braintree
217
- // control panel
218
- // * the cvv does not pass verfication
219
- handler.markFieldErrors([HostedFieldName.CVV]);
220
- break;
221
- case 'HOSTED_FIELDS_FAILED_TOKENIZATION':
222
- // occurs for any other tokenization error on the server
223
- break;
224
- case 'HOSTED_FIELDS_TOKENIZATION_NETWORK_ERROR':
225
- // occurs when the Braintree gateway cannot be contacted
226
- break;
227
- default:
228
- // something else happened
229
- break;
230
- }
231
- }
232
- }
1
+ import { createNanoEvents, Emitter, Unsubscribe } from 'nanoevents';
2
+
3
+ import { BraintreeManagerInterface } from '../../braintree-manager/braintree-interfaces';
4
+ import { RecaptchaManagerInterface } from '../../recaptcha-manager/recaptcha-manager';
5
+
6
+ import {
7
+ DonorContactInfo,
8
+ DonationPaymentInfo,
9
+ PaymentProvider,
10
+ } from '@internetarchive/donation-form-data-models';
11
+ import { DonationFlowModalManagerInterface } from '../donation-flow-modal-manager';
12
+ import { HostedFieldName } from '../../braintree-manager/payment-providers/credit-card/hosted-field-container';
13
+ import { BadgedInput } from '../../form-elements/badged-input';
14
+ import { BraintreeError } from '../../@types/braintree-web';
15
+
16
+ export interface CreditCardFlowHandlerInterface {
17
+ /**
18
+ * Set up the hosted fields with event bindings
19
+ *
20
+ * @returns {Promise<void>}
21
+ * @memberof CreditCardFlowHandlerInterface
22
+ */
23
+ startup(): Promise<void>;
24
+
25
+ /**
26
+ * Tokenize the hosted fields.
27
+ *
28
+ * This also performs validation so we can call this before initiating the payment to
29
+ * display any error messaging.
30
+ *
31
+ * @returns {(Promise<braintree.HostedFieldsTokenizePayload | undefined>)}
32
+ * @memberof CreditCardFlowHandlerInterface
33
+ */
34
+ tokenizeFields(): Promise<braintree.HostedFieldsTokenizePayload | undefined>;
35
+
36
+ /**
37
+ * Initiate the payment flow.
38
+ *
39
+ * You must get the response from `tokenizeFields()` first before this to validate the hosted fields.
40
+ *
41
+ * @param {braintree.HostedFieldsTokenizePayload} hostedFieldsResponse
42
+ * @param {DonationPaymentInfo} donationInfo
43
+ * @param {DonorContactInfo} donorContactInfo
44
+ * @returns {Promise<void>}
45
+ * @memberof CreditCardFlowHandlerInterface
46
+ */
47
+ paymentInitiated(
48
+ hostedFieldsResponse: braintree.HostedFieldsTokenizePayload,
49
+ donationInfo: DonationPaymentInfo,
50
+ donorContactInfo: DonorContactInfo,
51
+ ): Promise<void>;
52
+
53
+ /**
54
+ * Bind to receive credit card flow handler events
55
+ *
56
+ * @template E
57
+ * @param {E} event
58
+ * @param {CreditCardFlowHandlerEvents[E]} callback
59
+ * @returns {Unsubscribe}
60
+ * @memberof CreditCardFlowHandlerInterface
61
+ */
62
+ on<E extends keyof CreditCardFlowHandlerEvents>(
63
+ event: E,
64
+ callback: CreditCardFlowHandlerEvents[E],
65
+ ): Unsubscribe;
66
+ }
67
+
68
+ export interface CreditCardFlowHandlerEvents {
69
+ validityChanged: (isValid: boolean) => void;
70
+ }
71
+
72
+ export class CreditCardFlowHandler implements CreditCardFlowHandlerInterface {
73
+ private donationFlowModalManager: DonationFlowModalManagerInterface;
74
+
75
+ private braintreeManager: BraintreeManagerInterface;
76
+
77
+ private recaptchaManager: RecaptchaManagerInterface;
78
+
79
+ private emitter: Emitter<CreditCardFlowHandlerEvents>;
80
+
81
+ constructor(options: {
82
+ braintreeManager: BraintreeManagerInterface;
83
+ donationFlowModalManager: DonationFlowModalManagerInterface;
84
+ recaptchaManager: RecaptchaManagerInterface;
85
+ }) {
86
+ this.braintreeManager = options.braintreeManager;
87
+ this.donationFlowModalManager = options.donationFlowModalManager;
88
+ this.recaptchaManager = options.recaptchaManager;
89
+ this.emitter = createNanoEvents<CreditCardFlowHandlerEvents>();
90
+ }
91
+
92
+ /** @inheritdoc */
93
+ on<E extends keyof CreditCardFlowHandlerEvents>(
94
+ event: E,
95
+ callback: CreditCardFlowHandlerEvents[E],
96
+ ): Unsubscribe {
97
+ return this.emitter.on(event, callback);
98
+ }
99
+
100
+ private started = false;
101
+
102
+ /** @inheritdoc */
103
+ async startup(): Promise<void> {
104
+ if (this.started) {
105
+ return;
106
+ }
107
+ this.started = true;
108
+
109
+ const handler = await this.braintreeManager?.paymentProviders.creditCardHandler.get();
110
+ const instance = await handler?.instance.get();
111
+
112
+ // NOTE: The `focus` and `blur` callback logic must work in conjunction with
113
+ // the `HostedFieldContainer` class. We use the `HostedFieldContainer` for
114
+ // managing the hosted field error state in other parts of the form, but
115
+ // since we can only get event callbacks from the hosted fields like this,
116
+ // this has to operate independently and modify the CSS styles by itself
117
+ instance?.on('focus', (event: braintree.HostedFieldsStateObject): void => {
118
+ const { emittedBy, fields } = event;
119
+ const fieldInFocus = fields[emittedBy];
120
+ const { container } = fieldInFocus;
121
+ (container.parentElement as BadgedInput).error = false;
122
+ handler.hideErrorMessage();
123
+ });
124
+
125
+ instance?.on('blur', (event: braintree.HostedFieldsStateObject): void => {
126
+ const { emittedBy, fields } = event;
127
+ const fieldInFocus = fields[emittedBy];
128
+ const { container, isEmpty, isValid } = fieldInFocus;
129
+ if (isEmpty || !isValid) {
130
+ (container.parentElement as BadgedInput).error = true;
131
+ }
132
+ });
133
+
134
+ instance?.on('validityChange', (event: braintree.HostedFieldsStateObject): void => {
135
+ const { fields } = event;
136
+ const isValid = fields.cvv.isValid && fields.expirationDate.isValid && fields.number.isValid;
137
+ this.emitter.emit('validityChanged', isValid);
138
+ });
139
+ }
140
+
141
+ /** @inheritdoc */
142
+ async tokenizeFields(): Promise<braintree.HostedFieldsTokenizePayload | undefined> {
143
+ let hostedFieldsResponse: braintree.HostedFieldsTokenizePayload | undefined;
144
+
145
+ const handler = await this.braintreeManager.paymentProviders.creditCardHandler.get();
146
+
147
+ try {
148
+ hostedFieldsResponse = await handler?.tokenizeHostedFields();
149
+ } catch (error) {
150
+ this.handleHostedFieldTokenizationError(error as BraintreeError);
151
+ return;
152
+ }
153
+
154
+ return hostedFieldsResponse;
155
+ }
156
+
157
+ /** @inheritdoc */
158
+ async paymentInitiated(
159
+ hostedFieldsResponse: braintree.HostedFieldsTokenizePayload,
160
+ donationInfo: DonationPaymentInfo,
161
+ donorContactInfo: DonorContactInfo,
162
+ ): Promise<void> {
163
+ let recaptchaToken: string | undefined;
164
+
165
+ try {
166
+ recaptchaToken = await this.recaptchaManager.execute();
167
+ } catch (error) {
168
+ this.donationFlowModalManager.showErrorModal({
169
+ message: `Recaptcha failure`,
170
+ });
171
+ return;
172
+ }
173
+
174
+ this.donationFlowModalManager.startDonationSubmissionFlow({
175
+ nonce: hostedFieldsResponse.nonce,
176
+ paymentProvider: PaymentProvider.CreditCard,
177
+ recaptchaToken: recaptchaToken,
178
+ bin: hostedFieldsResponse.details.bin,
179
+ donationInfo: donationInfo,
180
+ customerInfo: donorContactInfo.customer,
181
+ billingInfo: donorContactInfo.billing,
182
+ });
183
+ }
184
+
185
+ private async handleHostedFieldTokenizationError(error: braintree.BraintreeError): Promise<void> {
186
+ const handler = await this.braintreeManager.paymentProviders.creditCardHandler.get();
187
+
188
+ handler.showErrorMessage();
189
+
190
+ switch (error.code) {
191
+ case 'HOSTED_FIELDS_FIELDS_EMPTY':
192
+ // occurs when none of the fields are filled in
193
+ handler.markFieldErrors([
194
+ HostedFieldName.Number,
195
+ HostedFieldName.CVV,
196
+ HostedFieldName.ExpirationDate,
197
+ ]);
198
+ break;
199
+ case 'HOSTED_FIELDS_FIELDS_INVALID':
200
+ // occurs when certain fields do not pass client side validation
201
+ Object.keys(error.details.invalidFields).forEach(key => {
202
+ handler.markFieldErrors([key as HostedFieldName]);
203
+ });
204
+ break;
205
+ case 'HOSTED_FIELDS_TOKENIZATION_FAIL_ON_DUPLICATE':
206
+ // occurs when:
207
+ // * the client token used for client authorization was generated
208
+ // with a customer ID and the fail on duplicate payment method
209
+ // option is set to true
210
+ // * the card being tokenized has previously been vaulted (with any customer)
211
+ break;
212
+ case 'HOSTED_FIELDS_TOKENIZATION_CVV_VERIFICATION_FAILED':
213
+ // occurs when:
214
+ // * the client token used for client authorization was generated
215
+ // with a customer ID and the verify card option is set to true
216
+ // and you have credit card verification turned on in the Braintree
217
+ // control panel
218
+ // * the cvv does not pass verfication
219
+ handler.markFieldErrors([HostedFieldName.CVV]);
220
+ break;
221
+ case 'HOSTED_FIELDS_FAILED_TOKENIZATION':
222
+ // occurs for any other tokenization error on the server
223
+ break;
224
+ case 'HOSTED_FIELDS_TOKENIZATION_NETWORK_ERROR':
225
+ // occurs when the Braintree gateway cannot be contacted
226
+ break;
227
+ default:
228
+ // something else happened
229
+ break;
230
+ }
231
+ }
232
+ }