@internetarchive/donation-form 1.0.2 → 1.0.3-alpha-webdev7960.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +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.map +1 -1
  127. package/dist/test/tests/payment-clients.test.js.map +1 -1
  128. package/dist/test/tests/payment-providers/applepay-sessiondatasource.test.js.map +1 -1
  129. package/dist/test/tests/payment-providers/applepay-sessionmanager.test.js.map +1 -1
  130. package/dist/test/tests/payment-providers/applepay.test.js.map +1 -1
  131. package/dist/test/tests/payment-providers/creditcard.test.js.map +1 -1
  132. package/dist/test/tests/payment-providers/googlepay.test.js.map +1 -1
  133. package/dist/test/tests/payment-providers/payment-providers.test.js.map +1 -1
  134. package/dist/test/tests/payment-providers/paypal-button-datasource.test.js.map +1 -1
  135. package/dist/test/tests/payment-providers/paypal.test.js.map +1 -1
  136. package/dist/test/tests/payment-providers/venmo.test.js.map +1 -1
  137. package/dist/test/tests/recaptcha-manager.test.js.map +1 -1
  138. package/package.json +107 -107
  139. package/src/@types/analytics-handler/index.d.ts +8 -8
  140. package/src/@types/braintree-web/LICENSE +21 -21
  141. package/src/@types/braintree-web/index.d.ts +93 -93
  142. package/src/@types/braintree-web/modules/american-express.d.ts +50 -50
  143. package/src/@types/braintree-web/modules/apple-pay.d.ts +213 -213
  144. package/src/@types/braintree-web/modules/client.d.ts +103 -103
  145. package/src/@types/braintree-web/modules/core.d.ts +34 -34
  146. package/src/@types/braintree-web/modules/data-collector.d.ts +13 -13
  147. package/src/@types/braintree-web/modules/google-payment.d.ts +269 -269
  148. package/src/@types/braintree-web/modules/hosted-fields.d.ts +366 -366
  149. package/src/@types/braintree-web/modules/paypal-checkout.d.ts +262 -262
  150. package/src/@types/braintree-web/modules/paypal.d.ts +177 -177
  151. package/src/@types/braintree-web/modules/three-d-secure.d.ts +141 -141
  152. package/src/@types/braintree-web/modules/unionpay.d.ts +224 -224
  153. package/src/@types/braintree-web/modules/us-bank-account.d.ts +81 -81
  154. package/src/@types/braintree-web/modules/venmo.d.ts +110 -110
  155. package/src/@types/braintree-web/package.json +64 -64
  156. package/src/@types/paypal-checkout-components/LICENSE +21 -21
  157. package/src/@types/paypal-checkout-components/index.d.ts +67 -67
  158. package/src/@types/paypal-checkout-components/modules/button.d.ts +50 -50
  159. package/src/@types/paypal-checkout-components/modules/callback-data.d.ts +244 -244
  160. package/src/@types/paypal-checkout-components/modules/configuration.d.ts +114 -114
  161. package/src/@types/paypal-checkout-components/package.json +58 -58
  162. package/src/braintree-manager/braintree-interfaces.ts +172 -172
  163. package/src/braintree-manager/braintree-manager.ts +281 -281
  164. package/src/braintree-manager/payment-clients.ts +146 -146
  165. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-interface.ts +13 -13
  166. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-delegate.ts +8 -8
  167. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-interface.ts +10 -10
  168. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource.ts +119 -119
  169. package/src/braintree-manager/payment-providers/apple-pay/apple-pay-session-manager.ts +21 -21
  170. package/src/braintree-manager/payment-providers/apple-pay/apple-pay.ts +97 -97
  171. package/src/braintree-manager/payment-providers/credit-card/credit-card-interface.ts +21 -21
  172. package/src/braintree-manager/payment-providers/credit-card/credit-card.ts +130 -130
  173. package/src/braintree-manager/payment-providers/credit-card/hosted-field-configuration.ts +19 -19
  174. package/src/braintree-manager/payment-providers/credit-card/hosted-field-container.ts +85 -85
  175. package/src/braintree-manager/payment-providers/google-pay-interface.ts +8 -8
  176. package/src/braintree-manager/payment-providers/google-pay.ts +59 -59
  177. package/src/braintree-manager/payment-providers/paypal/paypal-button-datasource.ts +218 -218
  178. package/src/braintree-manager/payment-providers/paypal/paypal-interface.ts +13 -13
  179. package/src/braintree-manager/payment-providers/paypal/paypal.ts +78 -78
  180. package/src/braintree-manager/payment-providers/venmo-interface.ts +8 -8
  181. package/src/braintree-manager/payment-providers/venmo.ts +67 -67
  182. package/src/braintree-manager/payment-providers-interface.ts +25 -25
  183. package/src/braintree-manager/payment-providers.ts +147 -147
  184. package/src/donation-form-controller.ts +623 -623
  185. package/src/donation-form-error.ts +6 -6
  186. package/src/donation-form.ts +576 -576
  187. package/src/form-elements/badged-input.ts +109 -109
  188. package/src/form-elements/contact-form/autocomplete-field-options.ts +63 -63
  189. package/src/form-elements/contact-form/contact-form.ts +434 -434
  190. package/src/form-elements/contact-form/countries.ts +252 -252
  191. package/src/form-elements/header/donation-form-header.ts +98 -98
  192. package/src/form-elements/header/donation-summary.ts +61 -61
  193. package/src/form-elements/payment-selector.ts +365 -365
  194. package/src/form-elements/total-amount.ts +46 -46
  195. package/src/modals/confirm-donation-modal-content.ts +168 -168
  196. package/src/modals/error-modal-content.ts +48 -48
  197. package/src/modals/upsell-modal-content.ts +284 -284
  198. package/src/payment-flow-handlers/donation-flow-modal-manager.ts +439 -439
  199. package/src/payment-flow-handlers/handlers/applepay-flow-handler.ts +109 -109
  200. package/src/payment-flow-handlers/handlers/creditcard-flow-handler.ts +232 -232
  201. package/src/payment-flow-handlers/handlers/googlepay-flow-handler.ts +111 -111
  202. package/src/payment-flow-handlers/handlers/paypal-flow-handler.ts +331 -331
  203. package/src/payment-flow-handlers/handlers/venmo-flow-handler.ts +119 -119
  204. package/src/payment-flow-handlers/handlers/venmo-restoration-state-handler.ts +127 -127
  205. package/src/payment-flow-handlers/payment-flow-handlers.ts +218 -218
  206. package/src/recaptcha-manager/recaptcha-manager.ts +123 -123
  207. package/src/util/promisedSleep.ts +3 -3
  208. package/dist/demo/app-root.d.ts +0 -0
  209. package/dist/demo/app-root.js +0 -2
  210. 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
+ }