@fantastic.dev/better-stripe 0.7.0 → 0.8.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 (359) hide show
  1. package/CHANGELOG.md +29 -18
  2. package/README.md +123 -91
  3. package/dist/client/billing/checkout.d.ts +1 -1
  4. package/dist/client/billing/checkout.d.ts.map +1 -1
  5. package/dist/client/billing/checkout.js +7 -2
  6. package/dist/client/billing/checkout.js.map +1 -1
  7. package/dist/client/connect/disputes.d.ts +1 -1
  8. package/dist/client/connect/disputes.d.ts.map +1 -1
  9. package/dist/client/connect/disputes.js +12 -6
  10. package/dist/client/connect/disputes.js.map +1 -1
  11. package/dist/client/connect/paymentMethods.d.ts.map +1 -1
  12. package/dist/client/connect/paymentMethods.js.map +1 -1
  13. package/dist/client/connect/refundActor.d.ts.map +1 -1
  14. package/dist/client/connect/refundActor.js.map +1 -1
  15. package/dist/client/connect/refunds.d.ts.map +1 -1
  16. package/dist/client/connect/refunds.js.map +1 -1
  17. package/dist/client/connect/transfers.d.ts.map +1 -1
  18. package/dist/client/connect/transfers.js +15 -4
  19. package/dist/client/connect/transfers.js.map +1 -1
  20. package/dist/client/core/accountDefaults.d.ts +6 -0
  21. package/dist/client/core/accountDefaults.d.ts.map +1 -0
  22. package/dist/client/core/accountDefaults.js +15 -0
  23. package/dist/client/core/accountDefaults.js.map +1 -0
  24. package/dist/client/core/accounts.d.ts +1 -5
  25. package/dist/client/core/accounts.d.ts.map +1 -1
  26. package/dist/client/core/accounts.js +2 -14
  27. package/dist/client/core/accounts.js.map +1 -1
  28. package/dist/client/core/fees.d.ts.map +1 -1
  29. package/dist/client/core/fees.js +7 -2
  30. package/dist/client/core/fees.js.map +1 -1
  31. package/dist/client/index.d.ts +1 -1
  32. package/dist/client/index.d.ts.map +1 -1
  33. package/dist/client/products/prices.d.ts.map +1 -1
  34. package/dist/client/products/prices.js.map +1 -1
  35. package/dist/client/products/products.d.ts.map +1 -1
  36. package/dist/client/products/products.js +3 -1
  37. package/dist/client/products/products.js.map +1 -1
  38. package/dist/client/utils/owner.d.ts.map +1 -1
  39. package/dist/client/utils/owner.js +3 -1
  40. package/dist/client/utils/owner.js.map +1 -1
  41. package/dist/client/utils/stripeDashboardUrl.d.ts.map +1 -1
  42. package/dist/client/utils/stripeDashboardUrl.js.map +1 -1
  43. package/dist/client/webhooks/helpers.d.ts +10 -0
  44. package/dist/client/webhooks/helpers.d.ts.map +1 -1
  45. package/dist/client/webhooks/helpers.js +18 -0
  46. package/dist/client/webhooks/helpers.js.map +1 -1
  47. package/dist/client/webhooks/processors.d.ts.map +1 -1
  48. package/dist/client/webhooks/processors.js +1 -19
  49. package/dist/client/webhooks/processors.js.map +1 -1
  50. package/dist/component/connect/mutations.d.ts.map +1 -1
  51. package/dist/component/connect/mutations.js +4 -33
  52. package/dist/component/connect/mutations.js.map +1 -1
  53. package/dist/component/connect/schema.d.ts.map +1 -1
  54. package/dist/component/connect/schema.js.map +1 -1
  55. package/dist/component/lib/paymentSeller.d.ts +3 -0
  56. package/dist/component/lib/paymentSeller.d.ts.map +1 -0
  57. package/dist/component/lib/paymentSeller.js +10 -0
  58. package/dist/component/lib/paymentSeller.js.map +1 -0
  59. package/dist/component/lib/reversals.d.ts +10 -0
  60. package/dist/component/lib/reversals.d.ts.map +1 -1
  61. package/dist/component/lib/reversals.js +17 -0
  62. package/dist/component/lib/reversals.js.map +1 -1
  63. package/dist/react/components/ConnectProvider.d.ts +1 -1
  64. package/dist/react/components/ConnectProvider.d.ts.map +1 -1
  65. package/dist/react/components/ConnectProvider.js +18 -4
  66. package/dist/react/components/ConnectProvider.js.map +1 -1
  67. package/dist/react/components/ConnectStatusBadge.d.ts.map +1 -1
  68. package/dist/react/components/ConnectStatusBadge.js.map +1 -1
  69. package/dist/react/components/DisputeDetail.d.ts +4 -1
  70. package/dist/react/components/DisputeDetail.d.ts.map +1 -1
  71. package/dist/react/components/DisputeDetail.js +12 -6
  72. package/dist/react/components/DisputeDetail.js.map +1 -1
  73. package/dist/react/components/DisputesList.d.ts.map +1 -1
  74. package/dist/react/components/DisputesList.js +2 -1
  75. package/dist/react/components/DisputesList.js.map +1 -1
  76. package/dist/react/components/EmbeddedDisputes.d.ts +1 -1
  77. package/dist/react/components/EmbeddedDisputes.d.ts.map +1 -1
  78. package/dist/react/components/EmbeddedDisputes.js +1 -1
  79. package/dist/react/components/EmbeddedDisputes.js.map +1 -1
  80. package/dist/react/components/SplitBreakdown.d.ts.map +1 -1
  81. package/dist/react/components/SplitBreakdown.js +12 -2
  82. package/dist/react/components/SplitBreakdown.js.map +1 -1
  83. package/dist/react/hooks/useCheckoutSession.d.ts.map +1 -1
  84. package/dist/react/hooks/useCheckoutSession.js.map +1 -1
  85. package/dist/react/hooks/useConfirmPayment.d.ts.map +1 -1
  86. package/dist/react/hooks/useConfirmPayment.js.map +1 -1
  87. package/dist/react/index.d.ts +2 -1
  88. package/dist/react/index.d.ts.map +1 -1
  89. package/dist/react/index.js +3 -1
  90. package/dist/react/index.js.map +1 -1
  91. package/dist/react/workflows/Account.d.ts +67 -0
  92. package/dist/react/workflows/Account.d.ts.map +1 -0
  93. package/dist/react/workflows/Account.js +74 -0
  94. package/dist/react/workflows/Account.js.map +1 -0
  95. package/dist/react/workflows/Billing.d.ts +60 -0
  96. package/dist/react/workflows/Billing.d.ts.map +1 -0
  97. package/dist/react/workflows/Billing.js +84 -0
  98. package/dist/react/workflows/Billing.js.map +1 -0
  99. package/dist/react/workflows/BillingPlans.d.ts +45 -0
  100. package/dist/react/workflows/BillingPlans.d.ts.map +1 -0
  101. package/dist/react/workflows/BillingPlans.js +51 -0
  102. package/dist/react/workflows/BillingPlans.js.map +1 -0
  103. package/dist/react/workflows/Checkout.d.ts +46 -0
  104. package/dist/react/workflows/Checkout.d.ts.map +1 -0
  105. package/dist/react/workflows/Checkout.js +61 -0
  106. package/dist/react/workflows/Checkout.js.map +1 -0
  107. package/dist/react/workflows/CheckoutChooser.d.ts +20 -0
  108. package/dist/react/workflows/CheckoutChooser.d.ts.map +1 -0
  109. package/dist/react/workflows/CheckoutChooser.js +24 -0
  110. package/dist/react/workflows/CheckoutChooser.js.map +1 -0
  111. package/dist/react/workflows/CheckoutForms.d.ts +26 -0
  112. package/dist/react/workflows/CheckoutForms.d.ts.map +1 -0
  113. package/dist/react/workflows/CheckoutForms.js +126 -0
  114. package/dist/react/workflows/CheckoutForms.js.map +1 -0
  115. package/dist/react/workflows/ClipboardButton.d.ts +17 -0
  116. package/dist/react/workflows/ClipboardButton.d.ts.map +1 -0
  117. package/dist/react/workflows/ClipboardButton.js +35 -0
  118. package/dist/react/workflows/ClipboardButton.js.map +1 -0
  119. package/dist/react/workflows/Collection.d.ts +30 -0
  120. package/dist/react/workflows/Collection.d.ts.map +1 -0
  121. package/dist/react/workflows/Collection.js +25 -0
  122. package/dist/react/workflows/Collection.js.map +1 -0
  123. package/dist/react/workflows/Collections.d.ts +56 -0
  124. package/dist/react/workflows/Collections.d.ts.map +1 -0
  125. package/dist/react/workflows/Collections.js +111 -0
  126. package/dist/react/workflows/Collections.js.map +1 -0
  127. package/dist/react/workflows/Connect.d.ts +19 -0
  128. package/dist/react/workflows/Connect.d.ts.map +1 -0
  129. package/dist/react/workflows/Connect.js +43 -0
  130. package/dist/react/workflows/Connect.js.map +1 -0
  131. package/dist/react/workflows/Costs.d.ts +48 -0
  132. package/dist/react/workflows/Costs.d.ts.map +1 -0
  133. package/dist/react/workflows/Costs.js +66 -0
  134. package/dist/react/workflows/Costs.js.map +1 -0
  135. package/dist/react/workflows/Disputes.d.ts +36 -0
  136. package/dist/react/workflows/Disputes.d.ts.map +1 -0
  137. package/dist/react/workflows/Disputes.js +74 -0
  138. package/dist/react/workflows/Disputes.js.map +1 -0
  139. package/dist/react/workflows/Earnings.d.ts +42 -0
  140. package/dist/react/workflows/Earnings.d.ts.map +1 -0
  141. package/dist/react/workflows/Earnings.js +38 -0
  142. package/dist/react/workflows/Earnings.js.map +1 -0
  143. package/dist/react/workflows/Financials.d.ts +43 -0
  144. package/dist/react/workflows/Financials.d.ts.map +1 -0
  145. package/dist/react/workflows/Financials.js +57 -0
  146. package/dist/react/workflows/Financials.js.map +1 -0
  147. package/dist/react/workflows/IntegrationSwitch.d.ts +23 -0
  148. package/dist/react/workflows/IntegrationSwitch.d.ts.map +1 -0
  149. package/dist/react/workflows/IntegrationSwitch.js +31 -0
  150. package/dist/react/workflows/IntegrationSwitch.js.map +1 -0
  151. package/dist/react/workflows/Onboarding.d.ts +56 -0
  152. package/dist/react/workflows/Onboarding.d.ts.map +1 -0
  153. package/dist/react/workflows/Onboarding.js +86 -0
  154. package/dist/react/workflows/Onboarding.js.map +1 -0
  155. package/dist/react/workflows/Overview.d.ts +51 -0
  156. package/dist/react/workflows/Overview.d.ts.map +1 -0
  157. package/dist/react/workflows/Overview.js +63 -0
  158. package/dist/react/workflows/Overview.js.map +1 -0
  159. package/dist/react/workflows/PaymentMethods.d.ts +35 -0
  160. package/dist/react/workflows/PaymentMethods.d.ts.map +1 -0
  161. package/dist/react/workflows/PaymentMethods.js +63 -0
  162. package/dist/react/workflows/PaymentMethods.js.map +1 -0
  163. package/dist/react/workflows/PaymentReceipt.d.ts +20 -0
  164. package/dist/react/workflows/PaymentReceipt.d.ts.map +1 -0
  165. package/dist/react/workflows/PaymentReceipt.js +24 -0
  166. package/dist/react/workflows/PaymentReceipt.js.map +1 -0
  167. package/dist/react/workflows/Payouts.d.ts +48 -0
  168. package/dist/react/workflows/Payouts.d.ts.map +1 -0
  169. package/dist/react/workflows/Payouts.js +88 -0
  170. package/dist/react/workflows/Payouts.js.map +1 -0
  171. package/dist/react/workflows/Products.d.ts +92 -0
  172. package/dist/react/workflows/Products.d.ts.map +1 -0
  173. package/dist/react/workflows/Products.js +179 -0
  174. package/dist/react/workflows/Products.js.map +1 -0
  175. package/dist/react/workflows/ReferralLinks.d.ts +26 -0
  176. package/dist/react/workflows/ReferralLinks.d.ts.map +1 -0
  177. package/dist/react/workflows/ReferralLinks.js +30 -0
  178. package/dist/react/workflows/ReferralLinks.js.map +1 -0
  179. package/dist/react/workflows/Refunds.d.ts +72 -0
  180. package/dist/react/workflows/Refunds.d.ts.map +1 -0
  181. package/dist/react/workflows/Refunds.js +95 -0
  182. package/dist/react/workflows/Refunds.js.map +1 -0
  183. package/dist/react/workflows/Setup.d.ts +50 -0
  184. package/dist/react/workflows/Setup.d.ts.map +1 -0
  185. package/dist/react/workflows/Setup.js +59 -0
  186. package/dist/react/workflows/Setup.js.map +1 -0
  187. package/dist/react/workflows/Storefront.d.ts +53 -0
  188. package/dist/react/workflows/Storefront.d.ts.map +1 -0
  189. package/dist/react/workflows/Storefront.js +44 -0
  190. package/dist/react/workflows/Storefront.js.map +1 -0
  191. package/dist/react/workflows/SubscriptionOverview.d.ts +13 -0
  192. package/dist/react/workflows/SubscriptionOverview.d.ts.map +1 -0
  193. package/dist/react/workflows/SubscriptionOverview.js +26 -0
  194. package/dist/react/workflows/SubscriptionOverview.js.map +1 -0
  195. package/dist/react/workflows/Subscriptions.d.ts +92 -0
  196. package/dist/react/workflows/Subscriptions.d.ts.map +1 -0
  197. package/dist/react/workflows/Subscriptions.js +149 -0
  198. package/dist/react/workflows/Subscriptions.js.map +1 -0
  199. package/dist/react/workflows/Tasks.d.ts +40 -0
  200. package/dist/react/workflows/Tasks.d.ts.map +1 -0
  201. package/dist/react/workflows/Tasks.js +113 -0
  202. package/dist/react/workflows/Tasks.js.map +1 -0
  203. package/dist/react/workflows/checkout-options.d.ts +37 -0
  204. package/dist/react/workflows/checkout-options.d.ts.map +1 -0
  205. package/dist/react/workflows/checkout-options.js +43 -0
  206. package/dist/react/workflows/checkout-options.js.map +1 -0
  207. package/dist/react/workflows/current-subscription.d.ts +11 -0
  208. package/dist/react/workflows/current-subscription.d.ts.map +1 -0
  209. package/dist/react/workflows/current-subscription.js +14 -0
  210. package/dist/react/workflows/current-subscription.js.map +1 -0
  211. package/dist/react/workflows/filters.d.ts +17 -0
  212. package/dist/react/workflows/filters.d.ts.map +1 -0
  213. package/dist/react/workflows/filters.js +23 -0
  214. package/dist/react/workflows/filters.js.map +1 -0
  215. package/dist/react/workflows/index.d.ts +70 -0
  216. package/dist/react/workflows/index.d.ts.map +1 -0
  217. package/dist/react/workflows/index.js +38 -0
  218. package/dist/react/workflows/index.js.map +1 -0
  219. package/dist/react/workflows/useWorkflowAction.d.ts +11 -0
  220. package/dist/react/workflows/useWorkflowAction.d.ts.map +1 -0
  221. package/dist/react/workflows/useWorkflowAction.js +68 -0
  222. package/dist/react/workflows/useWorkflowAction.js.map +1 -0
  223. package/dist/react/workflows/useWorkflowResource.d.ts +9 -0
  224. package/dist/react/workflows/useWorkflowResource.d.ts.map +1 -0
  225. package/dist/react/workflows/useWorkflowResource.js +67 -0
  226. package/dist/react/workflows/useWorkflowResource.js.map +1 -0
  227. package/docs/react-workflows-audit.md +88 -0
  228. package/docs/react-workflows.md +234 -0
  229. package/package.json +19 -3
  230. package/src/client/billing/checkout-ui-modes.test.ts +49 -0
  231. package/src/client/billing/checkout.ts +8 -3
  232. package/src/client/billing/invoices.test.ts +12 -6
  233. package/src/client/connect/disputes.test.ts +15 -0
  234. package/src/client/connect/disputes.ts +13 -7
  235. package/src/client/connect/paymentMethods.test.ts +3 -1
  236. package/src/client/connect/paymentMethods.ts +4 -1
  237. package/src/client/connect/refundActor.ts +1 -2
  238. package/src/client/connect/refunds.test.ts +35 -10
  239. package/src/client/connect/refunds.ts +4 -1
  240. package/src/client/connect/transfers.test.ts +66 -12
  241. package/src/client/connect/transfers.ts +32 -8
  242. package/src/client/core/accountDefaults.ts +15 -0
  243. package/src/client/core/accounts.ts +14 -17
  244. package/src/client/core/config.test.ts +2 -1
  245. package/src/client/core/descriptors.test.ts +6 -4
  246. package/src/client/core/fees.test.ts +20 -28
  247. package/src/client/core/fees.ts +9 -2
  248. package/src/client/index.test.ts +22 -22
  249. package/src/client/index.ts +1 -1
  250. package/src/client/products/prices.test.ts +8 -2
  251. package/src/client/products/prices.ts +4 -1
  252. package/src/client/products/products.test.ts +61 -20
  253. package/src/client/products/products.ts +3 -1
  254. package/src/client/utils/data.test.ts +3 -1
  255. package/src/client/utils/owner.test.ts +4 -1
  256. package/src/client/utils/owner.ts +5 -1
  257. package/src/client/utils/stripeDashboardUrl.ts +1 -4
  258. package/src/client/webhooks/handler.test.ts +16 -19
  259. package/src/client/webhooks/helpers.test.ts +26 -13
  260. package/src/client/webhooks/helpers.ts +23 -0
  261. package/src/client/webhooks/hooks.test.ts +1 -2
  262. package/src/client/webhooks/processors.test.ts +18 -34
  263. package/src/client/webhooks/processors.ts +1 -23
  264. package/src/client/webhooks.test.ts +1 -2
  265. package/src/component/_generated/api.ts +2 -0
  266. package/src/component/connect/mutations.ts +5 -46
  267. package/src/component/connect/schema.ts +4 -3
  268. package/src/component/connect.test.ts +1 -5
  269. package/src/component/lib/paymentSeller.ts +15 -0
  270. package/src/component/lib/reversals.ts +30 -2
  271. package/src/component/subscription-scoping.test.ts +5 -1
  272. package/src/component/triggers.test.ts +7 -4
  273. package/src/react/components/BuyerBillingView.render.test.tsx +7 -2
  274. package/src/react/components/ConnectProvider.live.test.tsx +61 -0
  275. package/src/react/components/ConnectProvider.tsx +18 -4
  276. package/src/react/components/ConnectStatusBadge.tsx +1 -4
  277. package/src/react/components/DisputeDetail.render.test.tsx +5 -1
  278. package/src/react/components/DisputeDetail.tsx +14 -5
  279. package/src/react/components/DisputesList.render.test.tsx +21 -0
  280. package/src/react/components/DisputesList.tsx +2 -1
  281. package/src/react/components/EarningsSummary.render.test.tsx +2 -6
  282. package/src/react/components/EmbeddedDisputes.render.test.tsx +7 -5
  283. package/src/react/components/EmbeddedDisputes.tsx +4 -1
  284. package/src/react/components/EvidenceForm.render.test.tsx +3 -10
  285. package/src/react/components/SplitBreakdown.render.test.tsx +28 -5
  286. package/src/react/components/SplitBreakdown.tsx +12 -2
  287. package/src/react/hooks/useCheckoutSession.ts +1 -2
  288. package/src/react/hooks/useConfirmPayment.ts +1 -2
  289. package/src/react/hooks/useEarnings.test.ts +43 -8
  290. package/src/react/hooks/useStripeMode.test.ts +5 -8
  291. package/src/react/index.ts +7 -1
  292. package/src/react/workflows/Account.test.tsx +31 -0
  293. package/src/react/workflows/Account.tsx +183 -0
  294. package/src/react/workflows/Billing.test.tsx +45 -0
  295. package/src/react/workflows/Billing.tsx +213 -0
  296. package/src/react/workflows/BillingPlans.test.tsx +31 -0
  297. package/src/react/workflows/BillingPlans.tsx +130 -0
  298. package/src/react/workflows/Checkout.test.tsx +118 -0
  299. package/src/react/workflows/Checkout.tsx +135 -0
  300. package/src/react/workflows/CheckoutChooser.test.tsx +44 -0
  301. package/src/react/workflows/CheckoutChooser.tsx +77 -0
  302. package/src/react/workflows/CheckoutForm.test.tsx +66 -0
  303. package/src/react/workflows/CheckoutForms.test.tsx +123 -0
  304. package/src/react/workflows/CheckoutForms.tsx +247 -0
  305. package/src/react/workflows/ClipboardButton.test.tsx +34 -0
  306. package/src/react/workflows/ClipboardButton.tsx +67 -0
  307. package/src/react/workflows/Collection.tsx +76 -0
  308. package/src/react/workflows/Collections.test.tsx +86 -0
  309. package/src/react/workflows/Collections.tsx +213 -0
  310. package/src/react/workflows/Connect.test.tsx +50 -0
  311. package/src/react/workflows/Connect.tsx +107 -0
  312. package/src/react/workflows/Costs.test.tsx +41 -0
  313. package/src/react/workflows/Costs.tsx +133 -0
  314. package/src/react/workflows/Disputes.test.tsx +64 -0
  315. package/src/react/workflows/Disputes.tsx +173 -0
  316. package/src/react/workflows/Earnings.test.ts +19 -0
  317. package/src/react/workflows/Earnings.tsx +84 -0
  318. package/src/react/workflows/Financials.test.tsx +35 -0
  319. package/src/react/workflows/Financials.tsx +117 -0
  320. package/src/react/workflows/IntegrationSwitch.test.tsx +36 -0
  321. package/src/react/workflows/IntegrationSwitch.tsx +63 -0
  322. package/src/react/workflows/Onboarding.test.tsx +75 -0
  323. package/src/react/workflows/Onboarding.tsx +171 -0
  324. package/src/react/workflows/Overview.test.tsx +57 -0
  325. package/src/react/workflows/Overview.tsx +123 -0
  326. package/src/react/workflows/PaymentMethods.test.tsx +60 -0
  327. package/src/react/workflows/PaymentMethods.tsx +117 -0
  328. package/src/react/workflows/PaymentReceipt.test.tsx +24 -0
  329. package/src/react/workflows/PaymentReceipt.tsx +46 -0
  330. package/src/react/workflows/Payouts.test.tsx +112 -0
  331. package/src/react/workflows/Payouts.tsx +215 -0
  332. package/src/react/workflows/Products.test.tsx +90 -0
  333. package/src/react/workflows/Products.tsx +377 -0
  334. package/src/react/workflows/ReferralLinks.test.tsx +39 -0
  335. package/src/react/workflows/ReferralLinks.tsx +75 -0
  336. package/src/react/workflows/Refunds.test.tsx +75 -0
  337. package/src/react/workflows/Refunds.tsx +223 -0
  338. package/src/react/workflows/Setup.test.tsx +25 -0
  339. package/src/react/workflows/Setup.tsx +166 -0
  340. package/src/react/workflows/Storefront.test.tsx +82 -0
  341. package/src/react/workflows/Storefront.tsx +138 -0
  342. package/src/react/workflows/SubscriptionOverview.test.tsx +27 -0
  343. package/src/react/workflows/SubscriptionOverview.tsx +48 -0
  344. package/src/react/workflows/Subscriptions.test.tsx +61 -0
  345. package/src/react/workflows/Subscriptions.tsx +282 -0
  346. package/src/react/workflows/Tasks.test.tsx +23 -0
  347. package/src/react/workflows/Tasks.tsx +199 -0
  348. package/src/react/workflows/checkout-options.ts +42 -0
  349. package/src/react/workflows/current-subscription.test.ts +29 -0
  350. package/src/react/workflows/current-subscription.ts +25 -0
  351. package/src/react/workflows/filters.test.ts +12 -0
  352. package/src/react/workflows/filters.ts +22 -0
  353. package/src/react/workflows/index.ts +238 -0
  354. package/src/react/workflows/native-interactions.test.tsx +73 -0
  355. package/src/react/workflows/public-workflows.test.tsx +216 -0
  356. package/src/react/workflows/useWorkflowAction.test.tsx +54 -0
  357. package/src/react/workflows/useWorkflowAction.ts +75 -0
  358. package/src/react/workflows/useWorkflowResource.test.tsx +41 -0
  359. package/src/react/workflows/useWorkflowResource.ts +78 -0
@@ -163,7 +163,10 @@ export type {
163
163
  DisputesListRow,
164
164
  DisputesListRowContext,
165
165
  } from "./components/DisputesList.js";
166
- export { DisputeDetail } from "./components/DisputeDetail.js";
166
+ export {
167
+ DisputeDetail,
168
+ canRespondToDispute,
169
+ } from "./components/DisputeDetail.js";
167
170
  export type {
168
171
  DisputeDetailProps,
169
172
  DisputeDetailRenderProps,
@@ -277,3 +280,6 @@ export {
277
280
  getRequirementKey,
278
281
  getRequirementLabel,
279
282
  } from "./lib/connect-requirement-keys.js";
283
+
284
+ // Complete unstyled workflows
285
+ export * from "./workflows/index.js";
@@ -0,0 +1,31 @@
1
+ // @vitest-environment jsdom
2
+ import { act, cleanup, renderHook } from "@testing-library/react";
3
+ import { afterEach, expect, it, vi } from "vitest";
4
+ import { useAccountManager } from "./Account.js";
5
+ afterEach(cleanup);
6
+ it("opens an authorized dashboard link and exposes configuration failures", async () => {
7
+ const navigate = vi.fn();
8
+ const configure = vi
9
+ .fn()
10
+ .mockRejectedValue(new Error("Capability unavailable"));
11
+ const { result } = renderHook(() =>
12
+ useAccountManager({
13
+ scopeKey: "acct_one",
14
+ createDashboardLink: async () => ({
15
+ url: "https://connect.stripe.com/dashboard",
16
+ }),
17
+ configure,
18
+ onNavigate: navigate,
19
+ }),
20
+ );
21
+ await act(async () => {
22
+ await result.current.openDashboard();
23
+ });
24
+ expect(navigate).toHaveBeenCalledWith("https://connect.stripe.com/dashboard");
25
+ await act(async () => {
26
+ await result.current.configure("merchant");
27
+ });
28
+ expect(configure).toHaveBeenCalledWith("merchant");
29
+ expect(result.current.error).toBe("Capability unavailable");
30
+ expect(result.current.lastConfiguration).toBe("merchant");
31
+ });
@@ -0,0 +1,183 @@
1
+ "use client";
2
+ import { useState, type ReactNode } from "react";
3
+ import { useWorkflowAction } from "./useWorkflowAction.js";
4
+ import { Connect, type ConnectProps } from "./Connect.js";
5
+ export type AccountConfiguration = "customer" | "recipient" | "merchant";
6
+ export type AccountManagerOptions = {
7
+ scopeKey: string;
8
+ createDashboardLink?: () => Promise<{ url: string }>;
9
+ configure?: (configuration: AccountConfiguration) => Promise<unknown>;
10
+ onNavigate?: (url: string) => void;
11
+ };
12
+ export function useAccountManager(props: AccountManagerOptions) {
13
+ const [configuration, setConfiguration] =
14
+ useState<AccountConfiguration | null>(null);
15
+ const action = useWorkflowAction(
16
+ async (
17
+ command:
18
+ | { type: "login" }
19
+ | { type: "configure"; configuration: AccountConfiguration },
20
+ ) => {
21
+ if (command.type === "login") {
22
+ if (!props.createDashboardLink)
23
+ throw new Error("Dashboard access is not configured.");
24
+ const result = await props.createDashboardLink();
25
+ if (!result.url)
26
+ throw new Error("Stripe did not return a dashboard URL.");
27
+ return { type: "login" as const, url: result.url };
28
+ }
29
+ setConfiguration(command.configuration);
30
+ if (!props.configure)
31
+ throw new Error("Account configuration is not supported.");
32
+ await props.configure(command.configuration);
33
+ return {
34
+ type: "configure" as const,
35
+ configuration: command.configuration,
36
+ };
37
+ },
38
+ props.scopeKey,
39
+ );
40
+ return {
41
+ pendingConfiguration: action.isPending ? configuration : null,
42
+ lastConfiguration: configuration,
43
+ isPending: action.isPending,
44
+ error: action.error,
45
+ result: action.result,
46
+ openDashboard: async () => {
47
+ const result = await action.run({ type: "login" });
48
+ if (result?.type === "login")
49
+ (props.onNavigate ?? ((url) => window.location.assign(url)))(
50
+ result.url,
51
+ );
52
+ },
53
+ configure: (configuration: AccountConfiguration) =>
54
+ action.run({ type: "configure", configuration }),
55
+ };
56
+ }
57
+ export type AccountSummary = {
58
+ stripeAccountId: string;
59
+ email?: string;
60
+ country?: string;
61
+ onboardingStatus?: string;
62
+ configurations?: string[];
63
+ missingRequirements?: string[];
64
+ };
65
+ export type HeadlessAccountProps = AccountManagerOptions & {
66
+ presentation?: "headless";
67
+ account: AccountSummary | null | undefined;
68
+ children?: (
69
+ state: ReturnType<typeof useAccountManager> & {
70
+ account: AccountSummary | null | undefined;
71
+ },
72
+ ) => ReactNode;
73
+ };
74
+ export type AccountProps =
75
+ | HeadlessAccountProps
76
+ | (Omit<ConnectProps, "component"> & { presentation: "embedded" });
77
+ export function Account(props: AccountProps) {
78
+ return props.presentation === "embedded" ? (
79
+ <Connect {...props} component="account" />
80
+ ) : (
81
+ <AccountBody key={props.scopeKey} {...props} />
82
+ );
83
+ }
84
+ function AccountBody(props: HeadlessAccountProps) {
85
+ const state = useAccountManager(props);
86
+ if (props.children)
87
+ return <>{props.children({ ...state, account: props.account })}</>;
88
+ if (props.account === undefined) return <p role="status">Loading account…</p>;
89
+ if (!props.account) return <p>No Stripe account has been set up.</p>;
90
+ return (
91
+ <section data-better-stripe="account" aria-busy={state.isPending}>
92
+ <h2>Account</h2>
93
+ <dl>
94
+ <dt>Account ID</dt>
95
+ <dd>{props.account.stripeAccountId}</dd>
96
+ <dt>Email</dt>
97
+ <dd>{props.account.email ?? "Not supplied"}</dd>
98
+ <dt>Country</dt>
99
+ <dd>{props.account.country ?? "Not supplied"}</dd>
100
+ <dt>Status</dt>
101
+ <dd>{props.account.onboardingStatus ?? "pending"}</dd>
102
+ </dl>
103
+ {state.error && <p role="alert">{state.error}</p>}
104
+ {props.createDashboardLink && (
105
+ <button
106
+ type="button"
107
+ disabled={state.isPending}
108
+ onClick={() => {
109
+ void state.openDashboard();
110
+ }}
111
+ >
112
+ {state.isPending ? "Opening…" : "Open Stripe dashboard"}
113
+ </button>
114
+ )}
115
+ <h3>Configurations</h3>
116
+ {props.account.configurations?.length ? (
117
+ <ul>
118
+ {props.account.configurations.map((value) => (
119
+ <li key={value}>{value}</li>
120
+ ))}
121
+ </ul>
122
+ ) : (
123
+ <p>No configurations yet.</p>
124
+ )}
125
+ {props.configure &&
126
+ (["customer", "recipient", "merchant"] as const)
127
+ .filter((value) => !props.account!.configurations?.includes(value))
128
+ .map((value) => (
129
+ <button
130
+ key={value}
131
+ type="button"
132
+ disabled={state.isPending}
133
+ onClick={() => {
134
+ void state.configure(value);
135
+ }}
136
+ >
137
+ Add {value} configuration
138
+ </button>
139
+ ))}
140
+ {!!props.account.missingRequirements?.length && (
141
+ <>
142
+ <h3>Requirements</h3>
143
+ <ul>
144
+ {props.account.missingRequirements.map((value) => (
145
+ <li key={value}>{value}</li>
146
+ ))}
147
+ </ul>
148
+ </>
149
+ )}
150
+ </section>
151
+ );
152
+ }
153
+ export type AccountConfigurationsProps = {
154
+ configurations: string[];
155
+ children?: (state: {
156
+ items: { key: string; label: string }[];
157
+ isEmpty: boolean;
158
+ }) => ReactNode;
159
+ };
160
+ export function AccountConfigurations({
161
+ configurations,
162
+ children,
163
+ }: AccountConfigurationsProps) {
164
+ const labels: Record<string, string> = {
165
+ recipient: "Recipient (payouts)",
166
+ customer: "Customer (billable)",
167
+ merchant: "Merchant (card payments)",
168
+ };
169
+ const items = configurations.map((key) => ({
170
+ key,
171
+ label: labels[key] ?? key,
172
+ }));
173
+ if (children) return <>{children({ items, isEmpty: !items.length })}</>;
174
+ return items.length ? (
175
+ <ul data-better-stripe="account-configurations">
176
+ {items.map((item) => (
177
+ <li key={item.key}>{item.label}</li>
178
+ ))}
179
+ </ul>
180
+ ) : (
181
+ <p>No configurations yet.</p>
182
+ );
183
+ }
@@ -0,0 +1,45 @@
1
+ // @vitest-environment jsdom
2
+ import {
3
+ act,
4
+ cleanup,
5
+ renderHook,
6
+ render,
7
+ screen,
8
+ } from "@testing-library/react";
9
+ import userEvent from "@testing-library/user-event";
10
+ import { afterEach, expect, it, vi } from "vitest";
11
+ import { useBalanceFunding, InvoiceEstimate } from "./Billing.js";
12
+ afterEach(cleanup);
13
+ it("requires explicit consent before enabling balance payments", async () => {
14
+ const change = vi.fn().mockResolvedValue(null);
15
+ const { result } = renderHook(() =>
16
+ useBalanceFunding({ scopeKey: "seller", change }),
17
+ );
18
+ await act(async () => {
19
+ await result.current.confirm(true);
20
+ });
21
+ expect(change).not.toHaveBeenCalled();
22
+ expect(result.current.error).toContain("consent");
23
+ act(() => result.current.setConsent(true));
24
+ await act(async () => {
25
+ await result.current.confirm(true);
26
+ });
27
+ expect(change).toHaveBeenCalledWith({ enabled: true, consent: true });
28
+ expect(result.current.consent).toBe(false);
29
+ });
30
+ it("loads an itemized estimate only when requested and displays the server total", async () => {
31
+ const load = vi.fn().mockResolvedValue({
32
+ currency: "usd",
33
+ total: 3700,
34
+ nextBillingAt: 1800000000000,
35
+ lines: [
36
+ { id: "plan", description: "Store plan", amount: 2900 },
37
+ { id: "cost", description: "Refund costs", amount: 800 },
38
+ ],
39
+ });
40
+ render(<InvoiceEstimate scopeKey="seller" load={load} />);
41
+ expect(load).not.toHaveBeenCalled();
42
+ await userEvent.click(screen.getByRole("button", { name: "View estimate" }));
43
+ await screen.findByText("$37.00");
44
+ expect(screen.getByText("Refund costs")).toBeTruthy();
45
+ });
@@ -0,0 +1,213 @@
1
+ "use client";
2
+ import { useId, useState, type ReactNode } from "react";
3
+ import { useWorkflowAction } from "./useWorkflowAction.js";
4
+ import { formatPrice } from "../lib/price-helpers.js";
5
+ export type EstimatedInvoice = {
6
+ currency: string;
7
+ total: number;
8
+ nextBillingAt: number;
9
+ lines: {
10
+ id: string;
11
+ description: string;
12
+ amount: number;
13
+ sourceType?: string;
14
+ }[];
15
+ };
16
+ export function useInvoiceEstimate(
17
+ load: () => Promise<EstimatedInvoice>,
18
+ scopeKey: string,
19
+ ) {
20
+ const action = useWorkflowAction(load, scopeKey);
21
+ return {
22
+ invoice: action.result,
23
+ isPending: action.isPending,
24
+ error: action.error,
25
+ refresh: action.run,
26
+ };
27
+ }
28
+ export type InvoiceEstimateProps = {
29
+ scopeKey: string;
30
+ load: () => Promise<EstimatedInvoice>;
31
+ children?: (state: ReturnType<typeof useInvoiceEstimate>) => ReactNode;
32
+ };
33
+ export function InvoiceEstimate({
34
+ scopeKey,
35
+ load,
36
+ children,
37
+ }: InvoiceEstimateProps) {
38
+ const state = useInvoiceEstimate(load, scopeKey);
39
+ if (children) return <>{children(state)}</>;
40
+ return (
41
+ <section data-better-stripe="invoice-estimate">
42
+ <h2>Estimated next invoice</h2>
43
+ <button
44
+ type="button"
45
+ disabled={state.isPending}
46
+ onClick={() => {
47
+ void state.refresh();
48
+ }}
49
+ >
50
+ {state.isPending
51
+ ? "Loading…"
52
+ : state.invoice
53
+ ? "Refresh estimate"
54
+ : "View estimate"}
55
+ </button>
56
+ {state.error && <p role="alert">{state.error}</p>}
57
+ {state.invoice && (
58
+ <>
59
+ <p>
60
+ Next billing date:{" "}
61
+ {new Date(state.invoice.nextBillingAt).toLocaleDateString()}
62
+ </p>
63
+ <ul>
64
+ {state.invoice.lines.map((line) => (
65
+ <li key={line.id}>
66
+ {line.description}{" "}
67
+ <span>{formatPrice(line.amount, state.invoice!.currency)}</span>
68
+ </li>
69
+ ))}
70
+ </ul>
71
+ <p>
72
+ Estimated total:{" "}
73
+ <span>
74
+ {formatPrice(state.invoice.total, state.invoice.currency)}
75
+ </span>
76
+ </p>
77
+ </>
78
+ )}
79
+ </section>
80
+ );
81
+ }
82
+ export type BalanceFundingActions = {
83
+ scopeKey: string;
84
+ change: (args: { enabled: boolean; consent?: true }) => Promise<unknown>;
85
+ };
86
+ export function useBalanceFunding({ scopeKey, change }: BalanceFundingActions) {
87
+ const [state, setState] = useState({ scope: scopeKey, consent: false });
88
+ if (state.scope !== scopeKey) setState({ scope: scopeKey, consent: false });
89
+ const action = useWorkflowAction(async (enabled: boolean) => {
90
+ if (enabled && !state.consent)
91
+ throw new Error(
92
+ "Explicit consent is required to debit a Stripe balance.",
93
+ );
94
+ await change({ enabled, consent: enabled ? true : undefined });
95
+ return true;
96
+ }, scopeKey);
97
+ return {
98
+ consent: state.consent,
99
+ setConsent: (consent: boolean) =>
100
+ setState((previous) => ({ ...previous, consent })),
101
+ error: action.error,
102
+ isPending: action.isPending,
103
+ confirm: async (enabled: boolean) => {
104
+ if (await action.run(enabled))
105
+ setState((previous) => ({ ...previous, consent: false }));
106
+ },
107
+ };
108
+ }
109
+ export type BalancePaymentSourceProps = BalanceFundingActions & {
110
+ enabled: boolean | undefined;
111
+ consentLabel?: string;
112
+ children?: (
113
+ state: ReturnType<typeof useBalanceFunding> & {
114
+ enabled: boolean | undefined;
115
+ },
116
+ ) => ReactNode;
117
+ };
118
+ export function BalancePaymentSource(props: BalancePaymentSourceProps) {
119
+ const state = useBalanceFunding(props);
120
+ const id = useId();
121
+ if (props.children)
122
+ return <>{props.children({ ...state, enabled: props.enabled })}</>;
123
+ return (
124
+ <section data-better-stripe="balance-payment-source">
125
+ <h2>Payment source</h2>
126
+ <p role="status">
127
+ {props.enabled === undefined
128
+ ? "Loading…"
129
+ : props.enabled
130
+ ? "Pay from Stripe balance"
131
+ : "Pay with saved payment method"}
132
+ </p>
133
+ <p>
134
+ If your Stripe balance is insufficient, payment can fail. Switch to a
135
+ saved payment method to pay instead.
136
+ </p>
137
+ {state.error && <p role="alert">{state.error}</p>}
138
+ {props.enabled === false && (
139
+ <>
140
+ <label htmlFor={id}>
141
+ <input
142
+ id={id}
143
+ type="checkbox"
144
+ checked={state.consent}
145
+ onChange={(event) => state.setConsent(event.target.checked)}
146
+ />
147
+ {props.consentLabel ??
148
+ "I authorize recurring platform charges from my Stripe balance."}
149
+ </label>
150
+ <button
151
+ type="button"
152
+ disabled={!state.consent || state.isPending}
153
+ onClick={() => {
154
+ void state.confirm(true);
155
+ }}
156
+ >
157
+ {state.isPending ? "Saving…" : "Confirm balance payments"}
158
+ </button>
159
+ </>
160
+ )}
161
+ {props.enabled && (
162
+ <button
163
+ type="button"
164
+ disabled={state.isPending}
165
+ onClick={() => {
166
+ void state.confirm(false);
167
+ }}
168
+ >
169
+ Use saved payment method
170
+ </button>
171
+ )}
172
+ </section>
173
+ );
174
+ }
175
+ export type BillingPortalProps = {
176
+ scopeKey?: string;
177
+ createSession: () => Promise<string | { url: string }>;
178
+ onNavigate?: (url: string) => void;
179
+ children?: (state: {
180
+ open: () => Promise<true | undefined>;
181
+ isPending: boolean;
182
+ error: string | null;
183
+ }) => ReactNode;
184
+ };
185
+ export function BillingPortal(props: BillingPortalProps) {
186
+ const action = useWorkflowAction(async () => {
187
+ const result = await props.createSession();
188
+ const url = typeof result === "string" ? result : result.url;
189
+ if (!url) throw new Error("Stripe did not return a portal URL.");
190
+ (props.onNavigate ?? ((url) => window.location.assign(url)))(url);
191
+ return true as const;
192
+ }, props.scopeKey);
193
+ const state = {
194
+ open: action.run,
195
+ isPending: action.isPending,
196
+ error: action.error,
197
+ };
198
+ if (props.children) return <>{props.children(state)}</>;
199
+ return (
200
+ <div data-better-stripe="billing-portal">
201
+ {action.error && <p role="alert">{action.error}</p>}
202
+ <button
203
+ type="button"
204
+ disabled={action.isPending}
205
+ onClick={() => {
206
+ void action.run();
207
+ }}
208
+ >
209
+ {action.isPending ? "Opening portal…" : "Open Stripe Billing Portal"}
210
+ </button>
211
+ </div>
212
+ );
213
+ }
@@ -0,0 +1,31 @@
1
+ // @vitest-environment jsdom
2
+ import { act, cleanup, renderHook, waitFor } from "@testing-library/react";
3
+ import { afterEach, expect, it, vi } from "vitest";
4
+ import { usePlanBilling } from "./BillingPlans.js";
5
+ afterEach(cleanup);
6
+ it("confirms a return session once and creates plan checkout only on explicit selection", async () => {
7
+ const confirm = vi.fn().mockResolvedValue(null);
8
+ const createCheckout = vi.fn().mockResolvedValue({
9
+ stripeSessionId: "cs_plan",
10
+ clientSecret: "cs_plan_secret",
11
+ });
12
+ const { result, rerender } = renderHook(
13
+ ({ scope }) =>
14
+ usePlanBilling({
15
+ scopeKey: scope,
16
+ sessionId: "cs_return",
17
+ confirm,
18
+ createCheckout,
19
+ createPortal: async () => "https://billing.stripe.com/session",
20
+ }),
21
+ { initialProps: { scope: "seller_one" } },
22
+ );
23
+ await waitFor(() => expect(confirm).toHaveBeenCalledWith("cs_return"));
24
+ expect(createCheckout).not.toHaveBeenCalled();
25
+ await act(async () => {
26
+ await result.current.choose("growth");
27
+ });
28
+ expect(result.current.clientSecret).toBe("cs_plan_secret");
29
+ rerender({ scope: "seller_two" });
30
+ expect(result.current.clientSecret).toBeUndefined();
31
+ });
@@ -0,0 +1,130 @@
1
+ "use client";
2
+ import type { ReactNode } from "react";
3
+ import { EmbeddedCheckout } from "../components/EmbeddedCheckout.js";
4
+ import { formatPrice } from "../lib/price-helpers.js";
5
+ import { useWorkflowAction } from "./useWorkflowAction.js";
6
+ import { useWorkflowResource } from "./useWorkflowResource.js";
7
+ import type { CheckoutSessionResult } from "./Checkout.js";
8
+ export type PlanBillingOptions<PlanId extends string = string> = {
9
+ scopeKey: string;
10
+ sessionId?: string | null;
11
+ confirm?: (sessionId: string) => Promise<unknown>;
12
+ createCheckout: (planId: PlanId) => Promise<CheckoutSessionResult>;
13
+ createPortal: () => Promise<string | { url: string }>;
14
+ onNavigate?: (url: string) => void;
15
+ };
16
+ export function usePlanBilling<PlanId extends string = string>(
17
+ props: PlanBillingOptions<PlanId>,
18
+ ) {
19
+ const confirmation = useWorkflowResource(
20
+ () =>
21
+ props.sessionId && props.confirm
22
+ ? props.confirm(props.sessionId)
23
+ : Promise.resolve(null),
24
+ `${props.scopeKey}:${props.sessionId ?? ""}`,
25
+ );
26
+ const action = useWorkflowAction(
27
+ async (
28
+ operation: { type: "checkout"; planId: PlanId } | { type: "portal" },
29
+ ) => {
30
+ if (operation.type === "checkout") {
31
+ const session = await props.createCheckout(operation.planId);
32
+ if (!session.clientSecret)
33
+ throw new Error("Stripe did not return a checkout form.");
34
+ return {
35
+ type: "checkout" as const,
36
+ clientSecret: session.clientSecret,
37
+ };
38
+ }
39
+ const result = await props.createPortal();
40
+ const url = typeof result === "string" ? result : result.url;
41
+ if (!url) throw new Error("Stripe did not return a billing portal URL.");
42
+ return { type: "portal" as const, url };
43
+ },
44
+ props.scopeKey,
45
+ );
46
+ return {
47
+ clientSecret:
48
+ action.result?.type === "checkout"
49
+ ? action.result.clientSecret
50
+ : undefined,
51
+ isPending: action.isPending,
52
+ error: action.error ?? confirmation.error,
53
+ choose: (planId: PlanId) => action.run({ type: "checkout", planId }),
54
+ openPortal: async () => {
55
+ const result = await action.run({ type: "portal" });
56
+ if (result?.type === "portal")
57
+ (props.onNavigate ?? ((url) => window.location.assign(url)))(
58
+ result.url,
59
+ );
60
+ },
61
+ };
62
+ }
63
+ export type BillingPlan<PlanId extends string = string> = {
64
+ id: PlanId;
65
+ name: string;
66
+ monthlyAmount: number;
67
+ currency: string;
68
+ description?: string;
69
+ feeDescription?: string;
70
+ };
71
+ export type BillingPlansProps<PlanId extends string = string> =
72
+ PlanBillingOptions<PlanId> & {
73
+ plans: BillingPlan<PlanId>[];
74
+ publishableKey: string;
75
+ currentPlanId?: PlanId;
76
+ children?: (
77
+ state: ReturnType<typeof usePlanBilling<PlanId>> & {
78
+ plans: BillingPlan<PlanId>[];
79
+ },
80
+ ) => ReactNode;
81
+ };
82
+ export function BillingPlans<PlanId extends string = string>(
83
+ props: BillingPlansProps<PlanId>,
84
+ ) {
85
+ const state = usePlanBilling(props);
86
+ if (props.children)
87
+ return <>{props.children({ ...state, plans: props.plans })}</>;
88
+ return (
89
+ <section data-better-stripe="billing-plans" aria-busy={state.isPending}>
90
+ <h2>Billing</h2>
91
+ {state.error && <p role="alert">{state.error}</p>}
92
+ <button
93
+ type="button"
94
+ disabled={state.isPending}
95
+ onClick={() => {
96
+ void state.openPortal();
97
+ }}
98
+ >
99
+ {state.isPending ? "Loading…" : "Manage billing"}
100
+ </button>
101
+ {props.plans.length ? (
102
+ props.plans.map((plan) => (
103
+ <article key={plan.id}>
104
+ <h3>{plan.name}</h3>
105
+ <p>{formatPrice(plan.monthlyAmount, plan.currency)}/month</p>
106
+ {plan.description && <p>{plan.description}</p>}
107
+ {plan.feeDescription && <p>{plan.feeDescription}</p>}
108
+ <button
109
+ type="button"
110
+ disabled={state.isPending || plan.id === props.currentPlanId}
111
+ onClick={() => {
112
+ void state.choose(plan.id);
113
+ }}
114
+ >
115
+ {plan.id === props.currentPlanId ? "Current plan" : "Choose plan"}
116
+ </button>
117
+ </article>
118
+ ))
119
+ ) : (
120
+ <p>No billing plans configured.</p>
121
+ )}
122
+ {state.clientSecret && (
123
+ <EmbeddedCheckout
124
+ publishableKey={props.publishableKey}
125
+ clientSecret={state.clientSecret}
126
+ />
127
+ )}
128
+ </section>
129
+ );
130
+ }