@easypayment/medusa-payment-paypal 0.7.4

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 (268) hide show
  1. package/.medusa/server/src/admin/index.js +1267 -0
  2. package/.medusa/server/src/admin/index.mjs +1268 -0
  3. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.d.ts +3 -0
  4. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -0
  5. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js +18 -0
  6. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js.map +1 -0
  7. package/.medusa/server/src/api/admin/paypal/disconnect/route.d.ts +3 -0
  8. package/.medusa/server/src/api/admin/paypal/disconnect/route.d.ts.map +1 -0
  9. package/.medusa/server/src/api/admin/paypal/disconnect/route.js +9 -0
  10. package/.medusa/server/src/api/admin/paypal/disconnect/route.js.map +1 -0
  11. package/.medusa/server/src/api/admin/paypal/environment/route.d.ts +4 -0
  12. package/.medusa/server/src/api/admin/paypal/environment/route.d.ts.map +1 -0
  13. package/.medusa/server/src/api/admin/paypal/environment/route.js +23 -0
  14. package/.medusa/server/src/api/admin/paypal/environment/route.js.map +1 -0
  15. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts +4 -0
  16. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts.map +1 -0
  17. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js +31 -0
  18. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js.map +1 -0
  19. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.d.ts +4 -0
  20. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.d.ts.map +1 -0
  21. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js +35 -0
  22. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js.map +1 -0
  23. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.d.ts +3 -0
  24. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.d.ts.map +1 -0
  25. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js +19 -0
  26. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js.map +1 -0
  27. package/.medusa/server/src/api/admin/paypal/save-credentials/route.d.ts +3 -0
  28. package/.medusa/server/src/api/admin/paypal/save-credentials/route.d.ts.map +1 -0
  29. package/.medusa/server/src/api/admin/paypal/save-credentials/route.js +17 -0
  30. package/.medusa/server/src/api/admin/paypal/save-credentials/route.js.map +1 -0
  31. package/.medusa/server/src/api/admin/paypal/settings/route.d.ts +4 -0
  32. package/.medusa/server/src/api/admin/paypal/settings/route.d.ts.map +1 -0
  33. package/.medusa/server/src/api/admin/paypal/settings/route.js +14 -0
  34. package/.medusa/server/src/api/admin/paypal/settings/route.js.map +1 -0
  35. package/.medusa/server/src/api/admin/paypal/status/route.d.ts +3 -0
  36. package/.medusa/server/src/api/admin/paypal/status/route.d.ts.map +1 -0
  37. package/.medusa/server/src/api/admin/paypal/status/route.js +11 -0
  38. package/.medusa/server/src/api/admin/paypal/status/route.js.map +1 -0
  39. package/.medusa/server/src/api/middlewares.d.ts +3 -0
  40. package/.medusa/server/src/api/middlewares.d.ts.map +1 -0
  41. package/.medusa/server/src/api/middlewares.js +16 -0
  42. package/.medusa/server/src/api/middlewares.js.map +1 -0
  43. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts +3 -0
  44. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -0
  45. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js +43 -0
  46. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js.map +1 -0
  47. package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts +3 -0
  48. package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts.map +1 -0
  49. package/.medusa/server/src/api/store/paypal/capture-order/route.js +204 -0
  50. package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -0
  51. package/.medusa/server/src/api/store/paypal/config/route.d.ts +3 -0
  52. package/.medusa/server/src/api/store/paypal/config/route.d.ts.map +1 -0
  53. package/.medusa/server/src/api/store/paypal/config/route.js +77 -0
  54. package/.medusa/server/src/api/store/paypal/config/route.js.map +1 -0
  55. package/.medusa/server/src/api/store/paypal/create-order/route.d.ts +3 -0
  56. package/.medusa/server/src/api/store/paypal/create-order/route.d.ts.map +1 -0
  57. package/.medusa/server/src/api/store/paypal/create-order/route.js +361 -0
  58. package/.medusa/server/src/api/store/paypal/create-order/route.js.map +1 -0
  59. package/.medusa/server/src/api/store/paypal/settings/route.d.ts +3 -0
  60. package/.medusa/server/src/api/store/paypal/settings/route.d.ts.map +1 -0
  61. package/.medusa/server/src/api/store/paypal/settings/route.js +20 -0
  62. package/.medusa/server/src/api/store/paypal/settings/route.js.map +1 -0
  63. package/.medusa/server/src/api/store/paypal/webhook/route.d.ts +3 -0
  64. package/.medusa/server/src/api/store/paypal/webhook/route.d.ts.map +1 -0
  65. package/.medusa/server/src/api/store/paypal/webhook/route.js +250 -0
  66. package/.medusa/server/src/api/store/paypal/webhook/route.js.map +1 -0
  67. package/.medusa/server/src/api/store/paypal-complete/route.d.ts +3 -0
  68. package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -0
  69. package/.medusa/server/src/api/store/paypal-complete/route.js +76 -0
  70. package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -0
  71. package/.medusa/server/src/index.d.ts +2 -0
  72. package/.medusa/server/src/index.d.ts.map +1 -0
  73. package/.medusa/server/src/index.js +9 -0
  74. package/.medusa/server/src/index.js.map +1 -0
  75. package/.medusa/server/src/jobs/paypal-webhook-retry.d.ts +7 -0
  76. package/.medusa/server/src/jobs/paypal-webhook-retry.d.ts.map +1 -0
  77. package/.medusa/server/src/jobs/paypal-webhook-retry.js +132 -0
  78. package/.medusa/server/src/jobs/paypal-webhook-retry.js.map +1 -0
  79. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.d.ts +15 -0
  80. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.d.ts.map +1 -0
  81. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.js +67 -0
  82. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.js.map +1 -0
  83. package/.medusa/server/src/modules/paypal/index.d.ts +64 -0
  84. package/.medusa/server/src/modules/paypal/index.d.ts.map +1 -0
  85. package/.medusa/server/src/modules/paypal/index.js +13 -0
  86. package/.medusa/server/src/modules/paypal/index.js.map +1 -0
  87. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.d.ts +6 -0
  88. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.d.ts.map +1 -0
  89. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.js +36 -0
  90. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.js.map +1 -0
  91. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.d.ts +6 -0
  92. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.d.ts.map +1 -0
  93. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.js +25 -0
  94. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.js.map +1 -0
  95. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.d.ts +6 -0
  96. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.d.ts.map +1 -0
  97. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.js +32 -0
  98. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.js.map +1 -0
  99. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.d.ts +6 -0
  100. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.d.ts.map +1 -0
  101. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.js +30 -0
  102. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.js.map +1 -0
  103. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.d.ts +6 -0
  104. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.d.ts.map +1 -0
  105. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.js +34 -0
  106. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.js.map +1 -0
  107. package/.medusa/server/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.d.ts +6 -0
  108. package/.medusa/server/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.d.ts.map +1 -0
  109. package/.medusa/server/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.js +28 -0
  110. package/.medusa/server/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.js.map +1 -0
  111. package/.medusa/server/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.d.ts +6 -0
  112. package/.medusa/server/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.d.ts.map +1 -0
  113. package/.medusa/server/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.js +29 -0
  114. package/.medusa/server/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.js.map +1 -0
  115. package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.d.ts +6 -0
  116. package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.d.ts.map +1 -0
  117. package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.js +14 -0
  118. package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.js.map +1 -0
  119. package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.d.ts +6 -0
  120. package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.d.ts.map +1 -0
  121. package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.js +14 -0
  122. package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.js.map +1 -0
  123. package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.d.ts +6 -0
  124. package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.d.ts.map +1 -0
  125. package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.js +14 -0
  126. package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.js.map +1 -0
  127. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.d.ts +6 -0
  128. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.d.ts.map +1 -0
  129. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.js +20 -0
  130. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.js.map +1 -0
  131. package/.medusa/server/src/modules/paypal/models/paypal_connection.d.ts +16 -0
  132. package/.medusa/server/src/modules/paypal/models/paypal_connection.d.ts.map +1 -0
  133. package/.medusa/server/src/modules/paypal/models/paypal_connection.js +19 -0
  134. package/.medusa/server/src/modules/paypal/models/paypal_connection.js.map +1 -0
  135. package/.medusa/server/src/modules/paypal/models/paypal_metric.d.ts +7 -0
  136. package/.medusa/server/src/modules/paypal/models/paypal_metric.d.ts.map +1 -0
  137. package/.medusa/server/src/modules/paypal/models/paypal_metric.js +10 -0
  138. package/.medusa/server/src/modules/paypal/models/paypal_metric.js.map +1 -0
  139. package/.medusa/server/src/modules/paypal/models/paypal_settings.d.ts +6 -0
  140. package/.medusa/server/src/modules/paypal/models/paypal_settings.d.ts.map +1 -0
  141. package/.medusa/server/src/modules/paypal/models/paypal_settings.js +9 -0
  142. package/.medusa/server/src/modules/paypal/models/paypal_settings.js.map +1 -0
  143. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.d.ts +17 -0
  144. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.d.ts.map +1 -0
  145. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.js +20 -0
  146. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.js.map +1 -0
  147. package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts +32 -0
  148. package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts.map +1 -0
  149. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js +625 -0
  150. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js.map +1 -0
  151. package/.medusa/server/src/modules/paypal/payment-provider/index.d.ts +6 -0
  152. package/.medusa/server/src/modules/paypal/payment-provider/index.d.ts.map +1 -0
  153. package/.medusa/server/src/modules/paypal/payment-provider/index.js +18 -0
  154. package/.medusa/server/src/modules/paypal/payment-provider/index.js.map +1 -0
  155. package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts +39 -0
  156. package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts.map +1 -0
  157. package/.medusa/server/src/modules/paypal/payment-provider/service.js +869 -0
  158. package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -0
  159. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.d.ts +3 -0
  160. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.d.ts.map +1 -0
  161. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.js +74 -0
  162. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.js.map +1 -0
  163. package/.medusa/server/src/modules/paypal/service.d.ts +266 -0
  164. package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -0
  165. package/.medusa/server/src/modules/paypal/service.js +1149 -0
  166. package/.medusa/server/src/modules/paypal/service.js.map +1 -0
  167. package/.medusa/server/src/modules/paypal/types/config.d.ts +12 -0
  168. package/.medusa/server/src/modules/paypal/types/config.d.ts.map +1 -0
  169. package/.medusa/server/src/modules/paypal/types/config.js +24 -0
  170. package/.medusa/server/src/modules/paypal/types/config.js.map +1 -0
  171. package/.medusa/server/src/modules/paypal/utils/amounts.d.ts +3 -0
  172. package/.medusa/server/src/modules/paypal/utils/amounts.d.ts.map +1 -0
  173. package/.medusa/server/src/modules/paypal/utils/amounts.js +40 -0
  174. package/.medusa/server/src/modules/paypal/utils/amounts.js.map +1 -0
  175. package/.medusa/server/src/modules/paypal/utils/currencies.d.ts +19 -0
  176. package/.medusa/server/src/modules/paypal/utils/currencies.d.ts.map +1 -0
  177. package/.medusa/server/src/modules/paypal/utils/currencies.js +69 -0
  178. package/.medusa/server/src/modules/paypal/utils/currencies.js.map +1 -0
  179. package/.medusa/server/src/modules/paypal/utils/paypal-auth.d.ts +10 -0
  180. package/.medusa/server/src/modules/paypal/utils/paypal-auth.d.ts.map +1 -0
  181. package/.medusa/server/src/modules/paypal/utils/paypal-auth.js +30 -0
  182. package/.medusa/server/src/modules/paypal/utils/paypal-auth.js.map +1 -0
  183. package/.medusa/server/src/modules/paypal/utils/provider-ids.d.ts +5 -0
  184. package/.medusa/server/src/modules/paypal/utils/provider-ids.d.ts.map +1 -0
  185. package/.medusa/server/src/modules/paypal/utils/provider-ids.js +16 -0
  186. package/.medusa/server/src/modules/paypal/utils/provider-ids.js.map +1 -0
  187. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts +29 -0
  188. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts.map +1 -0
  189. package/.medusa/server/src/modules/paypal/webhook-processor.js +267 -0
  190. package/.medusa/server/src/modules/paypal/webhook-processor.js.map +1 -0
  191. package/.medusa/server/src/providers/paypal/index.d.ts +5 -0
  192. package/.medusa/server/src/providers/paypal/index.d.ts.map +1 -0
  193. package/.medusa/server/src/providers/paypal/index.js +10 -0
  194. package/.medusa/server/src/providers/paypal/index.js.map +1 -0
  195. package/.medusa/server/src/providers/paypal_card/index.d.ts +5 -0
  196. package/.medusa/server/src/providers/paypal_card/index.d.ts.map +1 -0
  197. package/.medusa/server/src/providers/paypal_card/index.js +10 -0
  198. package/.medusa/server/src/providers/paypal_card/index.js.map +1 -0
  199. package/.medusa/server/src/subscribers/paypal-order-invoice.d.ts +6 -0
  200. package/.medusa/server/src/subscribers/paypal-order-invoice.d.ts.map +1 -0
  201. package/.medusa/server/src/subscribers/paypal-order-invoice.js +124 -0
  202. package/.medusa/server/src/subscribers/paypal-order-invoice.js.map +1 -0
  203. package/LICENSE +21 -0
  204. package/README.md +172 -0
  205. package/package.json +80 -0
  206. package/src/admin/index.ts +7 -0
  207. package/src/admin/routes/settings/paypal/_components/Tabs.tsx +48 -0
  208. package/src/admin/routes/settings/paypal/_components/Toast.tsx +51 -0
  209. package/src/admin/routes/settings/paypal/additional-settings/page.tsx +199 -0
  210. package/src/admin/routes/settings/paypal/advanced-card-payments/page.tsx +183 -0
  211. package/src/admin/routes/settings/paypal/apple-pay/page.tsx +5 -0
  212. package/src/admin/routes/settings/paypal/connection/page.tsx +699 -0
  213. package/src/admin/routes/settings/paypal/google-pay/page.tsx +5 -0
  214. package/src/admin/routes/settings/paypal/page.tsx +13 -0
  215. package/src/admin/routes/settings/paypal/pay-later-messaging/page.tsx +5 -0
  216. package/src/admin/routes/settings/paypal/paypal-settings/page.tsx +351 -0
  217. package/src/api/admin/payment-collections/[id]/payment-sessions/route.ts +24 -0
  218. package/src/api/admin/paypal/disconnect/route.ts +8 -0
  219. package/src/api/admin/paypal/environment/route.ts +25 -0
  220. package/src/api/admin/paypal/onboard-complete/route.ts +34 -0
  221. package/src/api/admin/paypal/onboarding-link/route.ts +45 -0
  222. package/src/api/admin/paypal/onboarding-status/route.ts +17 -0
  223. package/src/api/admin/paypal/save-credentials/route.ts +22 -0
  224. package/src/api/admin/paypal/settings/route.ts +14 -0
  225. package/src/api/admin/paypal/status/route.ts +12 -0
  226. package/src/api/middlewares.ts +14 -0
  227. package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +56 -0
  228. package/src/api/store/paypal/capture-order/route.ts +265 -0
  229. package/src/api/store/paypal/config/route.ts +100 -0
  230. package/src/api/store/paypal/create-order/route.ts +449 -0
  231. package/src/api/store/paypal/settings/route.ts +19 -0
  232. package/src/api/store/paypal/webhook/route.ts +325 -0
  233. package/src/api/store/paypal-complete/route.ts +95 -0
  234. package/src/index.ts +1 -0
  235. package/src/jobs/paypal-webhook-retry.ts +149 -0
  236. package/src/modules/paypal/clients/paypal-seller.client.ts +62 -0
  237. package/src/modules/paypal/index.ts +8 -0
  238. package/src/modules/paypal/migrations/20260115120000_create_paypal_connection.ts +33 -0
  239. package/src/modules/paypal/migrations/20260123090000_create_paypal_settings.ts +22 -0
  240. package/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.ts +29 -0
  241. package/src/modules/paypal/migrations/20260401090000_create_paypal_metric.ts +27 -0
  242. package/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.ts +31 -0
  243. package/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.ts +25 -0
  244. package/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.ts +26 -0
  245. package/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.ts +11 -0
  246. package/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.ts +11 -0
  247. package/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.ts +11 -0
  248. package/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.ts +17 -0
  249. package/src/modules/paypal/models/paypal_connection.ts +23 -0
  250. package/src/modules/paypal/models/paypal_metric.ts +9 -0
  251. package/src/modules/paypal/models/paypal_settings.ts +8 -0
  252. package/src/modules/paypal/models/paypal_webhook_event.ts +19 -0
  253. package/src/modules/paypal/payment-provider/README.md +22 -0
  254. package/src/modules/paypal/payment-provider/card-service.ts +767 -0
  255. package/src/modules/paypal/payment-provider/index.ts +15 -0
  256. package/src/modules/paypal/payment-provider/service.ts +1039 -0
  257. package/src/modules/paypal/payment-provider/webhook-utils.ts +88 -0
  258. package/src/modules/paypal/service.ts +1416 -0
  259. package/src/modules/paypal/types/config.ts +33 -0
  260. package/src/modules/paypal/utils/amounts.ts +41 -0
  261. package/src/modules/paypal/utils/currencies.ts +84 -0
  262. package/src/modules/paypal/utils/paypal-auth.ts +31 -0
  263. package/src/modules/paypal/utils/provider-ids.ts +15 -0
  264. package/src/modules/paypal/webhook-processor.ts +363 -0
  265. package/src/providers/paypal/index.ts +8 -0
  266. package/src/providers/paypal_card/index.ts +8 -0
  267. package/src/subscribers/paypal-order-invoice.ts +171 -0
  268. package/tsconfig.json +31 -0
@@ -0,0 +1,699 @@
1
+ import React, {
2
+ useCallback,
3
+ useEffect,
4
+ useLayoutEffect,
5
+ useMemo,
6
+ useRef,
7
+ useState,
8
+ } from "react"
9
+ import { defineRouteConfig } from "@medusajs/admin-sdk"
10
+ import PayPalTabs from "../_components/Tabs"
11
+
12
+ export const config = defineRouteConfig({
13
+ label: "PayPal Connection",
14
+ hide: true,
15
+ })
16
+
17
+
18
+ if (typeof window !== "undefined") {
19
+ const preloadHref =
20
+ "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js"
21
+
22
+ const existingPreload = document.head.querySelector(
23
+ `link[rel="preload"][href="${preloadHref}"]`
24
+ )
25
+ if (!existingPreload) {
26
+ const preloadLink = document.createElement("link")
27
+ preloadLink.rel = "preload"
28
+ preloadLink.href = preloadHref
29
+ preloadLink.as = "script"
30
+ document.head.appendChild(preloadLink)
31
+ }
32
+
33
+ const existingScript = document.getElementById(
34
+ "paypal-partner-js"
35
+ ) as HTMLScriptElement | null
36
+ if (!existingScript) {
37
+ const ppScript = document.createElement("script")
38
+ ppScript.id = "paypal-partner-js"
39
+ ppScript.src = preloadHref
40
+ ppScript.async = true
41
+ document.head.appendChild(ppScript)
42
+ }
43
+ }
44
+
45
+ declare global {
46
+ interface Window {
47
+ PAYPAL?: {
48
+ apps?: {
49
+ Signup?: {
50
+ miniBrowser?: { init: () => void }
51
+ MiniBrowser?: { closeFlow?: () => void }
52
+ }
53
+ }
54
+ }
55
+ onboardingCallback?: (authCode: string, sharedId: string) => void
56
+ }
57
+ }
58
+
59
+
60
+ const SERVICE_URL = "/admin/paypal/onboarding-link"
61
+ const CACHE_KEY = "pp_onboard_cache"
62
+ const RELOAD_KEY = "pp_onboard_reloaded_once"
63
+ const CACHE_EXPIRY = 10 * 60 * 1000
64
+
65
+ const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete"
66
+ const STATUS_ENDPOINT = "/admin/paypal/status"
67
+ const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials"
68
+ const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect"
69
+
70
+ let cachedUrl: string | null = null
71
+ if (typeof window !== "undefined") {
72
+ try {
73
+ const cached = localStorage.getItem(CACHE_KEY)
74
+ if (cached) {
75
+ const data = JSON.parse(cached)
76
+ if (new Date().getTime() - data.ts < CACHE_EXPIRY) {
77
+ cachedUrl = data.url
78
+ }
79
+ }
80
+ } catch (e) {
81
+ console.error("Cache read error:", e)
82
+ }
83
+ }
84
+
85
+
86
+ export default function PayPalConnectionPage() {
87
+ const [env, setEnv] = useState<"sandbox" | "live">("live")
88
+
89
+ useEffect(() => {
90
+ fetch("/admin/paypal/environment", { method: "GET" })
91
+ .then((r) => r.json())
92
+ .then((d) => {
93
+ const v = d?.environment === "sandbox" ? "sandbox" : "live"
94
+ setEnv(v)
95
+ })
96
+ .catch(() => {})
97
+ }, [])
98
+ const [connState, setConnState] = useState<
99
+ "loading" | "ready" | "connected" | "error"
100
+ >("loading")
101
+ const [error, setError] = useState<string | null>(null)
102
+ const [finalUrl, setFinalUrl] = useState<string>("")
103
+ const [showManual, setShowManual] = useState(false)
104
+ const [clientId, setClientId] = useState("")
105
+ const [secret, setSecret] = useState("")
106
+ const [statusInfo, setStatusInfo] = useState<{
107
+ seller_client_id_masked?: string | null
108
+ seller_client_secret_masked?: string | null
109
+ seller_email?: string | null
110
+ } | null>(null)
111
+
112
+ const [onboardingInProgress, setOnboardingInProgress] = useState(false)
113
+
114
+ const initLoaderRef = useRef<HTMLDivElement>(null)
115
+ const paypalButtonRef = useRef<HTMLAnchorElement>(null)
116
+ const errorLogRef = useRef<HTMLDivElement>(null)
117
+ const runIdRef = useRef(0)
118
+ const currentRunId = useRef(0)
119
+
120
+ const ppBtnMeasureRef = useRef<HTMLAnchorElement | null>(null)
121
+ const [ppBtnWidth, setPpBtnWidth] = useState<number | null>(null)
122
+
123
+ const canSaveManual = useMemo(() => {
124
+ return clientId.trim().length > 0 && secret.trim().length > 0
125
+ }, [clientId, secret])
126
+
127
+ const fetchFreshLink = useCallback(
128
+ (runId: number) => {
129
+ if (initLoaderRef.current) {
130
+ const loaderText = initLoaderRef.current.querySelector("#loader-text")
131
+ if (loaderText)
132
+ loaderText.textContent = "Generating onboarding session..."
133
+ }
134
+
135
+ fetch(SERVICE_URL, {
136
+ method: "POST",
137
+ headers: { "content-type": "application/json" },
138
+ body: JSON.stringify({
139
+ products: ["PPCP"],
140
+ }),
141
+ })
142
+ .then((r) => r.json())
143
+ .then((data) => {
144
+ if (runId !== currentRunId.current) return
145
+
146
+ const href = data?.onboarding_url
147
+ if (!href) {
148
+ showError("Onboarding URL not returned.")
149
+ return
150
+ }
151
+
152
+ const finalUrl =
153
+ href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser"
154
+
155
+ localStorage.setItem(
156
+ CACHE_KEY,
157
+ JSON.stringify({
158
+ url: finalUrl,
159
+ ts: Date.now(),
160
+ })
161
+ )
162
+
163
+ if (!localStorage.getItem(RELOAD_KEY)) {
164
+ localStorage.setItem(RELOAD_KEY, "1")
165
+ window.location.reload()
166
+ return
167
+ }
168
+
169
+ activatePayPal(finalUrl, runId)
170
+ })
171
+ .catch(() => {
172
+ if (runId !== currentRunId.current) return
173
+ showError("Unable to connect to service.")
174
+ })
175
+ },
176
+ [env]
177
+ )
178
+
179
+ const showUI = useCallback(() => {
180
+ const btn = document.querySelector('[data-paypal-button="true"]')
181
+ if (btn && window.PAYPAL?.apps?.Signup?.miniBrowser?.init) {
182
+ window.PAYPAL.apps.Signup.miniBrowser.init()
183
+ }
184
+ setConnState("ready")
185
+ }, [])
186
+
187
+ const showError = useCallback((msg: string) => {
188
+ setConnState("error")
189
+ setError(msg)
190
+ }, [])
191
+
192
+ const activatePayPal = useCallback(
193
+ (url: string, runId: number) => {
194
+ if (paypalButtonRef.current) {
195
+ paypalButtonRef.current.href = url
196
+ }
197
+ setFinalUrl(url)
198
+
199
+ const tryInit = () => {
200
+ if (runId !== currentRunId.current) return
201
+ if (window.PAYPAL?.apps?.Signup) {
202
+ showUI()
203
+ return
204
+ }
205
+ setTimeout(tryInit, 50)
206
+ }
207
+
208
+ tryInit()
209
+ },
210
+ [showUI]
211
+ )
212
+
213
+ useEffect(() => {
214
+ currentRunId.current = ++runIdRef.current
215
+ const runId = currentRunId.current
216
+
217
+ let cancelled = false
218
+
219
+ const run = async () => {
220
+ setConnState("loading")
221
+ setError(null)
222
+ setFinalUrl("")
223
+
224
+ try {
225
+ const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
226
+ method: "GET",
227
+ })
228
+ const st = await r.json().catch(() => ({}))
229
+
230
+ if (cancelled || runId !== currentRunId.current) return
231
+
232
+ setStatusInfo(st)
233
+
234
+ const isConnected =
235
+ st?.status === "connected" && st?.seller_client_id_present === true
236
+
237
+ if (isConnected) {
238
+ setConnState("connected")
239
+ setShowManual(false)
240
+ return
241
+ }
242
+ } catch (e) {
243
+ console.error(e)
244
+ }
245
+
246
+ if (cachedUrl) {
247
+ activatePayPal(cachedUrl, runId)
248
+ } else {
249
+ fetchFreshLink(runId)
250
+ }
251
+ }
252
+
253
+ run()
254
+
255
+ return () => {
256
+ cancelled = true
257
+ currentRunId.current = 0
258
+ }
259
+ }, [env, fetchFreshLink, activatePayPal])
260
+
261
+ useLayoutEffect(() => {
262
+ window.onboardingCallback = async function (authCode: string, sharedId: string) {
263
+ try {
264
+ ;(window as any).onbeforeunload = ""
265
+ } catch {}
266
+
267
+ setOnboardingInProgress(true)
268
+ setConnState("loading")
269
+ setError(null)
270
+
271
+ const payload = {
272
+ authCode,
273
+ sharedId,
274
+ env: env === "sandbox" ? "sandbox" : "live",
275
+ }
276
+
277
+ try {
278
+ const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
279
+ method: "POST",
280
+ headers: { "content-type": "application/json" },
281
+ body: JSON.stringify(payload),
282
+ })
283
+
284
+ if (!res.ok) {
285
+ const txt = await res.text().catch(() => "")
286
+ throw new Error(txt || `Onboarding exchange failed (${res.status})`)
287
+ }
288
+
289
+ try {
290
+ const close1 = window.PAYPAL?.apps?.Signup?.MiniBrowser?.closeFlow
291
+ if (typeof close1 === "function") close1()
292
+ } catch {}
293
+ try {
294
+ const close2 =
295
+ window.PAYPAL?.apps?.Signup?.miniBrowser &&
296
+ (window.PAYPAL.apps.Signup.miniBrowser as any).closeFlow
297
+ if (typeof close2 === "function") close2()
298
+ } catch {}
299
+
300
+ try {
301
+ localStorage.removeItem(CACHE_KEY)
302
+ localStorage.removeItem(RELOAD_KEY)
303
+ } catch {}
304
+
305
+ window.location.href = window.location.href
306
+ } catch (e: any) {
307
+ console.error(e)
308
+ setConnState("error")
309
+ setError(e?.message || "Exchange failed while saving credentials.")
310
+ setOnboardingInProgress(false)
311
+ }
312
+ }
313
+
314
+ return () => {
315
+ window.onboardingCallback = undefined
316
+ }
317
+ }, [env])
318
+
319
+ useLayoutEffect(() => {
320
+ const el = ppBtnMeasureRef.current
321
+ if (!el) return
322
+
323
+ const update = () => {
324
+ const w = Math.round(el.getBoundingClientRect().width || 0)
325
+ if (w > 0) setPpBtnWidth(w)
326
+ }
327
+
328
+ update()
329
+
330
+ let ro: ResizeObserver | null = null
331
+ if (typeof ResizeObserver !== "undefined") {
332
+ ro = new ResizeObserver(() => update())
333
+ ro.observe(el)
334
+ } else {
335
+ window.addEventListener("resize", update)
336
+ }
337
+
338
+ return () => {
339
+ if (ro) ro.disconnect()
340
+ else window.removeEventListener("resize", update)
341
+ }
342
+ }, [connState, env, finalUrl])
343
+
344
+ const handleConnectClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
345
+ if (connState !== "ready" || !finalUrl || onboardingInProgress) {
346
+ e.preventDefault()
347
+ }
348
+ }
349
+
350
+ const handleSaveManual = async () => {
351
+ if (!canSaveManual || onboardingInProgress) return
352
+ setOnboardingInProgress(true)
353
+ setConnState("loading")
354
+ setError(null)
355
+
356
+ try {
357
+ const res = await fetch(SAVE_CREDENTIALS_ENDPOINT, {
358
+ method: "POST",
359
+ headers: { "content-type": "application/json" },
360
+ body: JSON.stringify({
361
+ clientId: clientId.trim(),
362
+ clientSecret: secret.trim(),
363
+ environment: env,
364
+ }),
365
+ })
366
+
367
+ if (!res.ok) {
368
+ const txt = await res.text().catch(() => "")
369
+ throw new Error(txt || `Save credentials failed (${res.status})`)
370
+ }
371
+
372
+ const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
373
+ method: "GET",
374
+ })
375
+ const refreshedStatus = await statusRes.json().catch(() => ({}))
376
+
377
+ setConnState("connected")
378
+ setStatusInfo(refreshedStatus || null)
379
+ setShowManual(false)
380
+
381
+ try {
382
+ localStorage.removeItem(CACHE_KEY)
383
+ localStorage.removeItem(RELOAD_KEY)
384
+ } catch {}
385
+ } catch (e: any) {
386
+ console.error(e)
387
+ setConnState("error")
388
+ setError(e?.message || "Failed to save credentials.")
389
+ } finally {
390
+ setOnboardingInProgress(false)
391
+ }
392
+ }
393
+
394
+ const handleDisconnect = async () => {
395
+ if (onboardingInProgress) return
396
+ if (!window.confirm("Disconnect PayPal for this environment?")) return
397
+
398
+ setOnboardingInProgress(true)
399
+ setConnState("loading")
400
+ setError(null)
401
+ setFinalUrl("")
402
+ setShowManual(false)
403
+
404
+ try {
405
+ const res = await fetch(DISCONNECT_ENDPOINT, {
406
+ method: "POST",
407
+ headers: { "content-type": "application/json" },
408
+ body: JSON.stringify({ environment: env }),
409
+ })
410
+
411
+ if (!res.ok) {
412
+ const t = await res.text().catch(() => "")
413
+ throw new Error(t || `Disconnect failed (${res.status})`)
414
+ }
415
+
416
+ try {
417
+ localStorage.removeItem(CACHE_KEY)
418
+ localStorage.removeItem(RELOAD_KEY)
419
+ } catch {}
420
+
421
+ currentRunId.current = ++runIdRef.current
422
+ const runId = currentRunId.current
423
+ fetchFreshLink(runId)
424
+ } catch (e: any) {
425
+ console.error(e)
426
+ setConnState("error")
427
+ setError(e?.message || "Failed to disconnect.")
428
+ } finally {
429
+ setOnboardingInProgress(false)
430
+ }
431
+ }
432
+
433
+ const handleEnvChange = async (e: React.ChangeEvent<HTMLSelectElement>) => {
434
+ const next = e.target.value as "sandbox" | "live"
435
+ setEnv(next)
436
+ cachedUrl = null
437
+
438
+ try {
439
+ await fetch("/admin/paypal/environment", {
440
+ method: "POST",
441
+ headers: { "content-type": "application/json" },
442
+ body: JSON.stringify({ environment: next }),
443
+ })
444
+ } catch {}
445
+
446
+ try {
447
+ localStorage.removeItem(CACHE_KEY)
448
+ localStorage.removeItem(RELOAD_KEY)
449
+ } catch {}
450
+ }
451
+
452
+ return (
453
+ <div className="p-6">
454
+ <div className="flex flex-col gap-6">
455
+ <h1 className="text-xl font-semibold">PayPal Gateway By Easy Payment</h1>
456
+
457
+ <PayPalTabs />
458
+
459
+ <div className="rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm">
460
+ <div className="grid grid-cols-1 gap-y-6 p-4 md:grid-cols-[260px_1fr] md:items-start">
461
+ <div className="text-sm font-medium pt-2">Environment</div>
462
+ <div className="max-w-xl">
463
+ <select
464
+ value={env}
465
+ onChange={handleEnvChange}
466
+ disabled={onboardingInProgress}
467
+ className="w-full rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm"
468
+ >
469
+ <option value="sandbox">Sandbox (Test Mode)</option>
470
+ <option value="live">Live (Production)</option>
471
+ </select>
472
+ </div>
473
+
474
+ <div className="text-sm font-medium pt-2">
475
+ {env === "sandbox" ? "Connect to PayPal (Sandbox)" : "Connect to PayPal"}
476
+ </div>
477
+
478
+ <div className="max-w-xl">
479
+ {connState === "connected" ? (
480
+ <div>
481
+ <div className="text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200">
482
+ ✅ Successfully connected to PayPal!
483
+ <a
484
+ data-paypal-button="true"
485
+ data-paypal-onboard-complete="onboardingCallback"
486
+ href="#"
487
+ style={{ display: "none" }}
488
+ >
489
+ PayPal
490
+ </a>
491
+ </div>
492
+ <div className="mt-3 rounded-md border border-ui-border-base bg-ui-bg-subtle p-3 text-xs text-ui-fg-subtle">
493
+ <div className="font-medium text-ui-fg-base">
494
+ Connected PayPal account
495
+ </div>
496
+ <div className="mt-1">
497
+ Email:{" "}
498
+ <span className="font-mono text-ui-fg-base">
499
+ {statusInfo?.seller_email || "Unavailable"}
500
+ </span>
501
+ </div>
502
+ </div>
503
+ <div className="mt-3 flex items-center gap-2">
504
+ <button
505
+ type="button"
506
+ onClick={handleDisconnect}
507
+ disabled={onboardingInProgress}
508
+ className="transition-fg relative inline-flex w-fit items-center justify-center overflow-hidden rounded-md outline-none shadow-buttons-neutral text-ui-fg-base bg-ui-button-neutral after:transition-fg after:absolute after:inset-0 after:content-[''] after:button-neutral-gradient hover:bg-ui-button-neutral-hover hover:after:button-neutral-hover-gradient active:bg-ui-button-neutral-pressed active:after:button-neutral-pressed-gradient focus-visible:shadow-buttons-neutral-focus disabled:bg-ui-bg-disabled disabled:border-ui-border-base disabled:text-ui-fg-disabled disabled:shadow-buttons-neutral disabled:after:hidden txt-compact-small-plus px-3 py-1.5"
509
+ >
510
+ Disconnect
511
+ </button>
512
+ </div>
513
+ </div>
514
+ ) : (
515
+ <>
516
+ <div
517
+ ref={initLoaderRef}
518
+ id="init-loader"
519
+ className={`status-msg mb-4 ${
520
+ connState !== "loading" ? "hidden" : "block"
521
+ }`}
522
+ >
523
+ <div className="loader inline-block align-middle mr-2"></div>
524
+ <span id="loader-text" className="text-sm">
525
+ {onboardingInProgress
526
+ ? "Configuring connection to PayPal…"
527
+ : "Checking connection..."}
528
+ </span>
529
+ </div>
530
+
531
+ <div className={`${connState === "ready" ? "block" : "hidden"}`}>
532
+ <a
533
+ ref={(node) => {
534
+ paypalButtonRef.current = node
535
+ ppBtnMeasureRef.current = node
536
+ }}
537
+ id="paypal-button"
538
+ data-paypal-button="true"
539
+ href={finalUrl || "#"}
540
+ data-paypal-onboard-complete="onboardingCallback"
541
+ onClick={handleConnectClick}
542
+ className="transition-fg relative inline-flex w-fit items-center justify-center overflow-hidden rounded-md outline-none no-underline shadow-buttons-neutral text-ui-fg-base bg-ui-button-neutral after:transition-fg after:absolute after:inset-0 after:content-[''] after:button-neutral-gradient hover:bg-ui-button-neutral-hover hover:after:button-neutral-hover-gradient active:bg-ui-button-neutral-pressed active:after:button-neutral-pressed-gradient focus-visible:shadow-buttons-neutral-focus disabled:bg-ui-bg-disabled disabled:border-ui-border-base disabled:text-ui-fg-disabled disabled:shadow-buttons-neutral disabled:after:hidden txt-compact-small-plus px-3 py-1.5"
543
+ style={{
544
+ cursor: onboardingInProgress ? "not-allowed" : "pointer",
545
+ opacity: onboardingInProgress ? 0.6 : 1,
546
+ pointerEvents: onboardingInProgress ? "none" : "auto",
547
+ }}
548
+ >
549
+ Connect to PayPal
550
+ </a>
551
+
552
+ <div
553
+ className="mt-2"
554
+ style={{
555
+ width: ppBtnWidth ? `${ppBtnWidth}px` : "auto",
556
+ marginTop: "20px",
557
+ marginBottom: "10px",
558
+ }}
559
+ >
560
+ <div className="flex justify-center">
561
+ <span className="text-[11px] text-ui-fg-muted leading-none">
562
+ OR
563
+ </span>
564
+ </div>
565
+ </div>
566
+
567
+ <div className="mt-1">
568
+ <button
569
+ type="button"
570
+ onClick={() => setShowManual(!showManual)}
571
+ disabled={onboardingInProgress}
572
+ className="text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed"
573
+ >
574
+ Click here to insert credentials manually
575
+ </button>
576
+ </div>
577
+ </div>
578
+
579
+ <div className={`${connState === "ready" ? "hidden" : "block"} mt-3`}>
580
+ <button
581
+ type="button"
582
+ onClick={() => setShowManual(!showManual)}
583
+ disabled={onboardingInProgress}
584
+ className="text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed"
585
+ >
586
+ Click here to insert credentials manually
587
+ </button>
588
+ </div>
589
+
590
+ <div
591
+ ref={errorLogRef}
592
+ id="error-log"
593
+ className={`mt-4 text-left text-xs bg-red-50 text-red-600 p-3 border border-red-200 rounded ${
594
+ connState === "error" && error ? "block" : "hidden"
595
+ }`}
596
+ >
597
+ {error}
598
+ </div>
599
+ </>
600
+ )}
601
+ </div>
602
+
603
+ {showManual && (
604
+ <div className="md:col-span-2">
605
+ <div className="ml-[260px] max-w-xl mt-4 grid grid-cols-1 gap-3 md:grid-cols-2">
606
+ <div className="flex flex-col gap-1">
607
+ <label className="text-sm font-medium">Client ID</label>
608
+ <input
609
+ type="text"
610
+ value={clientId}
611
+ onChange={(e) => setClientId(e.target.value)}
612
+ disabled={onboardingInProgress}
613
+ className="rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50"
614
+ placeholder={
615
+ env === "sandbox" ? "Sandbox Client ID" : "Live Client ID"
616
+ }
617
+ />
618
+ </div>
619
+
620
+ <div className="flex flex-col gap-1">
621
+ <label className="text-sm font-medium">Secret</label>
622
+ <input
623
+ type="password"
624
+ value={secret}
625
+ onChange={(e) => setSecret(e.target.value)}
626
+ disabled={onboardingInProgress}
627
+ className="rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50"
628
+ placeholder={env === "sandbox" ? "Sandbox Secret" : "Live Secret"}
629
+ />
630
+ </div>
631
+
632
+ <div className="md:col-span-2 rounded-md border border-ui-border-base bg-ui-bg-subtle p-4 text-sm text-ui-fg-subtle">
633
+ <p className="font-medium text-ui-fg-base">
634
+ Get your Client ID and Secret in 3 steps:
635
+ </p>
636
+ <ol className="mt-2 list-decimal space-y-2 pl-5">
637
+ <li>
638
+ Open{" "}
639
+ <a
640
+ href="https://developer.paypal.com/dashboard/"
641
+ target="_blank"
642
+ rel="noreferrer"
643
+ className="text-ui-fg-interactive underline"
644
+ >
645
+ Log in to Dashboard
646
+ </a>{" "}
647
+ and sign in or create an account.
648
+ </li>
649
+ <li>Select <span className="font-medium text-ui-fg-base">Apps & Credentials</span>, then choose <span className="font-medium text-ui-fg-base">Create App</span> if you need a new project.</li>
650
+ <li>Copy your app's <span className="font-medium text-ui-fg-base">Client ID</span> and <span className="font-medium text-ui-fg-base">Secret</span>, paste them above, then click <span className="font-medium text-ui-fg-base">Save credentials</span>.</li>
651
+ </ol>
652
+ </div>
653
+
654
+ <div className="md:col-span-2 flex items-center gap-2 mt-2">
655
+ <button
656
+ type="button"
657
+ className="transition-fg relative inline-flex w-fit items-center justify-center overflow-hidden rounded-md outline-none shadow-buttons-neutral text-ui-fg-base bg-ui-button-neutral after:transition-fg after:absolute after:inset-0 after:content-[''] after:button-neutral-gradient hover:bg-ui-button-neutral-hover hover:after:button-neutral-hover-gradient active:bg-ui-button-neutral-pressed active:after:button-neutral-pressed-gradient focus-visible:shadow-buttons-neutral-focus disabled:bg-ui-bg-disabled disabled:border-ui-border-base disabled:text-ui-fg-disabled disabled:shadow-buttons-neutral disabled:after:hidden txt-compact-small-plus px-3 py-1.5"
658
+ onClick={() => setShowManual(false)}
659
+ disabled={onboardingInProgress}
660
+ >
661
+ Cancel
662
+ </button>
663
+
664
+ <button
665
+ type="button"
666
+ className="transition-fg relative inline-flex w-fit items-center justify-center overflow-hidden rounded-md outline-none shadow-buttons-neutral text-ui-fg-base bg-ui-button-neutral after:transition-fg after:absolute after:inset-0 after:content-[''] after:button-neutral-gradient hover:bg-ui-button-neutral-hover hover:after:button-neutral-hover-gradient active:bg-ui-button-neutral-pressed active:after:button-neutral-pressed-gradient focus-visible:shadow-buttons-neutral-focus disabled:bg-ui-bg-disabled disabled:border-ui-border-base disabled:text-ui-fg-disabled disabled:shadow-buttons-neutral disabled:after:hidden txt-compact-small-plus px-3 py-1.5"
667
+ disabled={!canSaveManual || onboardingInProgress}
668
+ onClick={handleSaveManual}
669
+ >
670
+ Save credentials
671
+ </button>
672
+ </div>
673
+ </div>
674
+ </div>
675
+ )}
676
+ </div>
677
+ </div>
678
+ </div>
679
+
680
+ <style>{`
681
+ .loader {
682
+ border: 3px solid #f3f3f3;
683
+ border-top: 3px solid #0070ba;
684
+ border-radius: 50%;
685
+ width: 18px;
686
+ height: 18px;
687
+ animation: spin 1s linear infinite;
688
+ display: inline-block;
689
+ vertical-align: middle;
690
+ margin-right: 8px;
691
+ }
692
+ @keyframes spin {
693
+ 0% { transform: rotate(0deg); }
694
+ 100% { transform: rotate(360deg); }
695
+ }
696
+ `}</style>
697
+ </div>
698
+ )
699
+ }
@@ -0,0 +1,5 @@
1
+ import { Navigate } from "react-router-dom"
2
+
3
+ export default function PayPalGooglePayPage() {
4
+ return <Navigate to="/settings/paypal/connection" replace />
5
+ }