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