@internetarchive/donation-form 1.0.3-alpha-webdev7960.1 → 1.0.3-webdev-8114.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 (211) 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.d.ts +1 -1
  38. package/dist/src/form-elements/contact-form/contact-form.js +174 -179
  39. package/dist/src/form-elements/contact-form/contact-form.js.map +1 -1
  40. package/dist/src/form-elements/contact-form/countries.js.map +1 -1
  41. package/dist/src/form-elements/header/donation-form-header.js +14 -14
  42. package/dist/src/form-elements/header/donation-form-header.js.map +1 -1
  43. package/dist/src/form-elements/header/donation-summary.js +15 -15
  44. package/dist/src/form-elements/header/donation-summary.js.map +1 -1
  45. package/dist/src/form-elements/payment-selector.js +164 -164
  46. package/dist/src/form-elements/payment-selector.js.map +1 -1
  47. package/dist/src/form-elements/total-amount.js +16 -16
  48. package/dist/src/form-elements/total-amount.js.map +1 -1
  49. package/dist/src/modals/confirm-donation-modal-content.js +51 -51
  50. package/dist/src/modals/confirm-donation-modal-content.js.map +1 -1
  51. package/dist/src/modals/error-modal-content.js +22 -22
  52. package/dist/src/modals/error-modal-content.js.map +1 -1
  53. package/dist/src/modals/upsell-modal-content.js +182 -182
  54. package/dist/src/modals/upsell-modal-content.js.map +1 -1
  55. package/dist/src/payment-flow-handlers/donation-flow-modal-manager.js +20 -20
  56. package/dist/src/payment-flow-handlers/donation-flow-modal-manager.js.map +1 -1
  57. package/dist/src/payment-flow-handlers/handlers/applepay-flow-handler.js.map +1 -1
  58. package/dist/src/payment-flow-handlers/handlers/creditcard-flow-handler.js.map +1 -1
  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.map +1 -1
  61. package/dist/src/payment-flow-handlers/handlers/venmo-flow-handler.js.map +1 -1
  62. package/dist/src/payment-flow-handlers/handlers/venmo-restoration-state-handler.js.map +1 -1
  63. package/dist/src/payment-flow-handlers/payment-flow-handlers.js.map +1 -1
  64. package/dist/src/recaptcha-manager/recaptcha-manager.js.map +1 -1
  65. package/dist/src/util/promisedSleep.js.map +1 -1
  66. package/dist/test/helpers/fillInContactForm.js.map +1 -1
  67. package/dist/test/mocks/flow-handlers/individual-handlers/mock-applepay-flow-handler.js.map +1 -1
  68. package/dist/test/mocks/flow-handlers/individual-handlers/mock-creditcard-flow-handler.js.map +1 -1
  69. package/dist/test/mocks/flow-handlers/individual-handlers/mock-googlepay-flow-handler.js.map +1 -1
  70. package/dist/test/mocks/flow-handlers/individual-handlers/mock-paypal-flow-handler.js.map +1 -1
  71. package/dist/test/mocks/flow-handlers/individual-handlers/mock-venmo-flow-handler.js.map +1 -1
  72. package/dist/test/mocks/flow-handlers/mock-payment-flow-handlers.js.map +1 -1
  73. package/dist/test/mocks/mock-braintree-manager.js.map +1 -1
  74. package/dist/test/mocks/mock-donation-info.js.map +1 -1
  75. package/dist/test/mocks/mock-endpoint-manager.js.map +1 -1
  76. package/dist/test/mocks/mock-hosted-fields-config.js.map +1 -1
  77. package/dist/test/mocks/mock-hosted-fields-container.js.map +1 -1
  78. package/dist/test/mocks/mock-lazy-loader.js.map +1 -1
  79. package/dist/test/mocks/mock-modal-manager.js.map +1 -1
  80. package/dist/test/mocks/mock-payment-clients.js.map +1 -1
  81. package/dist/test/mocks/mock-paypal-button-renderer.js.map +1 -1
  82. package/dist/test/mocks/mock-recaptcha-manager.js.map +1 -1
  83. package/dist/test/mocks/models/mock-billing-info.js.map +1 -1
  84. package/dist/test/mocks/models/mock-custom-fields.js.map +1 -1
  85. package/dist/test/mocks/models/mock-customer-info.js.map +1 -1
  86. package/dist/test/mocks/models/mock-donation-request.js.map +1 -1
  87. package/dist/test/mocks/models/mock-success-response.js.map +1 -1
  88. package/dist/test/mocks/payment-clients/mock-applepay-client.js.map +1 -1
  89. package/dist/test/mocks/payment-clients/mock-applepay-payment.js.map +1 -1
  90. package/dist/test/mocks/payment-clients/mock-applepay-paymentauthorizedevent.js.map +1 -1
  91. package/dist/test/mocks/payment-clients/mock-applepay-session.js.map +1 -1
  92. package/dist/test/mocks/payment-clients/mock-applepay-sessionmanager.js.map +1 -1
  93. package/dist/test/mocks/payment-clients/mock-applepay-validatemerchantevent.js.map +1 -1
  94. package/dist/test/mocks/payment-clients/mock-braintree-client.js.map +1 -1
  95. package/dist/test/mocks/payment-clients/mock-data-collector.js.map +1 -1
  96. package/dist/test/mocks/payment-clients/mock-googlepay-client.js.map +1 -1
  97. package/dist/test/mocks/payment-clients/mock-googlepay-library.js.map +1 -1
  98. package/dist/test/mocks/payment-clients/mock-grecaptcha.js.map +1 -1
  99. package/dist/test/mocks/payment-clients/mock-hostedfields-client.js.map +1 -1
  100. package/dist/test/mocks/payment-clients/mock-hostedfieldstateobject-generator.js.map +1 -1
  101. package/dist/test/mocks/payment-clients/mock-hostedfieldtokenizepayload.js.map +1 -1
  102. package/dist/test/mocks/payment-clients/mock-paypal-client.js.map +1 -1
  103. package/dist/test/mocks/payment-clients/mock-paypal-library.js.map +1 -1
  104. package/dist/test/mocks/payment-clients/mock-venmo-client.js.map +1 -1
  105. package/dist/test/mocks/payment-providers/individual-providers/mock-applepay-datasource-delegate.js.map +1 -1
  106. package/dist/test/mocks/payment-providers/individual-providers/mock-applepay-handler.js.map +1 -1
  107. package/dist/test/mocks/payment-providers/individual-providers/mock-creditcard-handler.js.map +1 -1
  108. package/dist/test/mocks/payment-providers/individual-providers/mock-googlepay-handler.js.map +1 -1
  109. package/dist/test/mocks/payment-providers/individual-providers/mock-paypal-button-datasource-delegate.js.map +1 -1
  110. package/dist/test/mocks/payment-providers/individual-providers/mock-paypal-button-datasource.js.map +1 -1
  111. package/dist/test/mocks/payment-providers/individual-providers/mock-paypal-handler.js.map +1 -1
  112. package/dist/test/mocks/payment-providers/individual-providers/mock-venmo-handler.js.map +1 -1
  113. package/dist/test/mocks/payment-providers/mock-payment-providers.js.map +1 -1
  114. package/dist/test/tests/braintree-manager.test.js.map +1 -1
  115. package/dist/test/tests/donation-form-controller.test.js +39 -39
  116. package/dist/test/tests/donation-form-controller.test.js.map +1 -1
  117. package/dist/test/tests/donation-form.test.js +4 -4
  118. package/dist/test/tests/donation-form.test.js.map +1 -1
  119. package/dist/test/tests/flow-handlers/donation-flow-modal-manager.test.js +14 -14
  120. package/dist/test/tests/flow-handlers/donation-flow-modal-manager.test.js.map +1 -1
  121. package/dist/test/tests/form-elements/contact-form.test.d.ts +1 -0
  122. package/dist/test/tests/form-elements/contact-form.test.js +132 -0
  123. package/dist/test/tests/form-elements/contact-form.test.js.map +1 -0
  124. package/dist/test/tests/form-elements/donation-summary.test.js.map +1 -1
  125. package/dist/test/tests/form-elements/payment-selector.test.js.map +1 -1
  126. package/dist/test/tests/modals/error-modal-content.test.js +2 -2
  127. package/dist/test/tests/modals/error-modal-content.test.js.map +1 -1
  128. package/dist/test/tests/modals/upsell-modal-content.test.js +31 -31
  129. package/dist/test/tests/modals/upsell-modal-content.test.js.map +1 -1
  130. package/dist/test/tests/models/donation-payment-info.test.js.map +1 -1
  131. package/dist/test/tests/payment-clients.test.js.map +1 -1
  132. package/dist/test/tests/payment-providers/applepay-sessiondatasource.test.js.map +1 -1
  133. package/dist/test/tests/payment-providers/applepay-sessionmanager.test.js.map +1 -1
  134. package/dist/test/tests/payment-providers/applepay.test.js.map +1 -1
  135. package/dist/test/tests/payment-providers/creditcard.test.js.map +1 -1
  136. package/dist/test/tests/payment-providers/googlepay.test.js.map +1 -1
  137. package/dist/test/tests/payment-providers/payment-providers.test.js.map +1 -1
  138. package/dist/test/tests/payment-providers/paypal-button-datasource.test.js.map +1 -1
  139. package/dist/test/tests/payment-providers/paypal.test.js.map +1 -1
  140. package/dist/test/tests/payment-providers/venmo.test.js.map +1 -1
  141. package/dist/test/tests/recaptcha-manager.test.js.map +1 -1
  142. package/package.json +107 -107
  143. package/src/@types/analytics-handler/index.d.ts +8 -8
  144. package/src/@types/braintree-web/LICENSE +21 -21
  145. package/src/@types/braintree-web/index.d.ts +93 -93
  146. package/src/@types/braintree-web/modules/american-express.d.ts +50 -50
  147. package/src/@types/braintree-web/modules/apple-pay.d.ts +213 -213
  148. package/src/@types/braintree-web/modules/client.d.ts +103 -103
  149. package/src/@types/braintree-web/modules/core.d.ts +34 -34
  150. package/src/@types/braintree-web/modules/data-collector.d.ts +13 -13
  151. package/src/@types/braintree-web/modules/google-payment.d.ts +269 -269
  152. package/src/@types/braintree-web/modules/hosted-fields.d.ts +366 -366
  153. package/src/@types/braintree-web/modules/paypal-checkout.d.ts +262 -262
  154. package/src/@types/braintree-web/modules/paypal.d.ts +177 -177
  155. package/src/@types/braintree-web/modules/three-d-secure.d.ts +141 -141
  156. package/src/@types/braintree-web/modules/unionpay.d.ts +224 -224
  157. package/src/@types/braintree-web/modules/us-bank-account.d.ts +81 -81
  158. package/src/@types/braintree-web/modules/venmo.d.ts +110 -110
  159. package/src/@types/braintree-web/package.json +64 -64
  160. package/src/@types/paypal-checkout-components/LICENSE +21 -21
  161. package/src/@types/paypal-checkout-components/index.d.ts +67 -67
  162. package/src/@types/paypal-checkout-components/modules/button.d.ts +50 -50
  163. package/src/@types/paypal-checkout-components/modules/callback-data.d.ts +244 -244
  164. package/src/@types/paypal-checkout-components/modules/configuration.d.ts +114 -114
  165. package/src/@types/paypal-checkout-components/package.json +58 -58
  166. package/src/braintree-manager/braintree-interfaces.ts +172 -172
  167. package/src/braintree-manager/braintree-manager.ts +281 -281
  168. package/src/braintree-manager/payment-clients.ts +146 -146
  169. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-interface.ts +13 -13
  170. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-delegate.ts +8 -8
  171. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-interface.ts +10 -10
  172. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource.ts +119 -119
  173. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-manager.ts +21 -21
  174. package/src/braintree-manager/payment-providers/apple-pay/apple-pay.ts +97 -97
  175. package/src/braintree-manager/payment-providers/credit-card/credit-card-interface.ts +21 -21
  176. package/src/braintree-manager/payment-providers/credit-card/credit-card.ts +130 -130
  177. package/src/braintree-manager/payment-providers/credit-card/hosted-field-configuration.ts +19 -19
  178. package/src/braintree-manager/payment-providers/credit-card/hosted-field-container.ts +85 -85
  179. package/src/braintree-manager/payment-providers/google-pay-interface.ts +8 -8
  180. package/src/braintree-manager/payment-providers/google-pay.ts +59 -59
  181. package/src/braintree-manager/payment-providers/paypal/paypal-button-datasource.ts +218 -218
  182. package/src/braintree-manager/payment-providers/paypal/paypal-interface.ts +13 -13
  183. package/src/braintree-manager/payment-providers/paypal/paypal.ts +78 -78
  184. package/src/braintree-manager/payment-providers/venmo-interface.ts +8 -8
  185. package/src/braintree-manager/payment-providers/venmo.ts +67 -67
  186. package/src/braintree-manager/payment-providers-interface.ts +25 -25
  187. package/src/braintree-manager/payment-providers.ts +147 -147
  188. package/src/donation-form-controller.ts +623 -623
  189. package/src/donation-form-error.ts +6 -6
  190. package/src/donation-form.ts +576 -576
  191. package/src/form-elements/badged-input.ts +109 -109
  192. package/src/form-elements/contact-form/autocomplete-field-options.ts +63 -63
  193. package/src/form-elements/contact-form/contact-form.ts +432 -434
  194. package/src/form-elements/contact-form/countries.ts +252 -252
  195. package/src/form-elements/header/donation-form-header.ts +98 -98
  196. package/src/form-elements/header/donation-summary.ts +61 -61
  197. package/src/form-elements/payment-selector.ts +365 -365
  198. package/src/form-elements/total-amount.ts +46 -46
  199. package/src/modals/confirm-donation-modal-content.ts +168 -168
  200. package/src/modals/error-modal-content.ts +48 -48
  201. package/src/modals/upsell-modal-content.ts +284 -284
  202. package/src/payment-flow-handlers/donation-flow-modal-manager.ts +439 -439
  203. package/src/payment-flow-handlers/handlers/applepay-flow-handler.ts +109 -109
  204. package/src/payment-flow-handlers/handlers/creditcard-flow-handler.ts +232 -232
  205. package/src/payment-flow-handlers/handlers/googlepay-flow-handler.ts +111 -111
  206. package/src/payment-flow-handlers/handlers/paypal-flow-handler.ts +331 -331
  207. package/src/payment-flow-handlers/handlers/venmo-flow-handler.ts +119 -119
  208. package/src/payment-flow-handlers/handlers/venmo-restoration-state-handler.ts +127 -127
  209. package/src/payment-flow-handlers/payment-flow-handlers.ts +218 -218
  210. package/src/recaptcha-manager/recaptcha-manager.ts +123 -123
  211. 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
+ }