@easypayment/medusa-paypal 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/.medusa/server/src/admin/index.js +2127 -0
  2. package/.medusa/server/src/admin/index.mjs +2128 -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 +25 -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/audit-logs/route.d.ts +3 -0
  8. package/.medusa/server/src/api/admin/paypal/audit-logs/route.d.ts.map +1 -0
  9. package/.medusa/server/src/api/admin/paypal/audit-logs/route.js +12 -0
  10. package/.medusa/server/src/api/admin/paypal/audit-logs/route.js.map +1 -0
  11. package/.medusa/server/src/api/admin/paypal/disconnect/route.d.ts +3 -0
  12. package/.medusa/server/src/api/admin/paypal/disconnect/route.d.ts.map +1 -0
  13. package/.medusa/server/src/api/admin/paypal/disconnect/route.js +9 -0
  14. package/.medusa/server/src/api/admin/paypal/disconnect/route.js.map +1 -0
  15. package/.medusa/server/src/api/admin/paypal/disputes/[id]/route.d.ts +3 -0
  16. package/.medusa/server/src/api/admin/paypal/disputes/[id]/route.d.ts.map +1 -0
  17. package/.medusa/server/src/api/admin/paypal/disputes/[id]/route.js +17 -0
  18. package/.medusa/server/src/api/admin/paypal/disputes/[id]/route.js.map +1 -0
  19. package/.medusa/server/src/api/admin/paypal/disputes/route.d.ts +3 -0
  20. package/.medusa/server/src/api/admin/paypal/disputes/route.d.ts.map +1 -0
  21. package/.medusa/server/src/api/admin/paypal/disputes/route.js +27 -0
  22. package/.medusa/server/src/api/admin/paypal/disputes/route.js.map +1 -0
  23. package/.medusa/server/src/api/admin/paypal/disputes/summary/route.d.ts +3 -0
  24. package/.medusa/server/src/api/admin/paypal/disputes/summary/route.d.ts.map +1 -0
  25. package/.medusa/server/src/api/admin/paypal/disputes/summary/route.js +17 -0
  26. package/.medusa/server/src/api/admin/paypal/disputes/summary/route.js.map +1 -0
  27. package/.medusa/server/src/api/admin/paypal/environment/route.d.ts +4 -0
  28. package/.medusa/server/src/api/admin/paypal/environment/route.d.ts.map +1 -0
  29. package/.medusa/server/src/api/admin/paypal/environment/route.js +23 -0
  30. package/.medusa/server/src/api/admin/paypal/environment/route.js.map +1 -0
  31. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts +8 -0
  32. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts.map +1 -0
  33. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js +41 -0
  34. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js.map +1 -0
  35. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.d.ts +4 -0
  36. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.d.ts.map +1 -0
  37. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js +35 -0
  38. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js.map +1 -0
  39. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.d.ts +3 -0
  40. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.d.ts.map +1 -0
  41. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js +20 -0
  42. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js.map +1 -0
  43. package/.medusa/server/src/api/admin/paypal/reconciliation-status/route.d.ts +3 -0
  44. package/.medusa/server/src/api/admin/paypal/reconciliation-status/route.d.ts.map +1 -0
  45. package/.medusa/server/src/api/admin/paypal/reconciliation-status/route.js +8 -0
  46. package/.medusa/server/src/api/admin/paypal/reconciliation-status/route.js.map +1 -0
  47. package/.medusa/server/src/api/admin/paypal/rotate-credentials/route.d.ts +3 -0
  48. package/.medusa/server/src/api/admin/paypal/rotate-credentials/route.d.ts.map +1 -0
  49. package/.medusa/server/src/api/admin/paypal/rotate-credentials/route.js +9 -0
  50. package/.medusa/server/src/api/admin/paypal/rotate-credentials/route.js.map +1 -0
  51. package/.medusa/server/src/api/admin/paypal/save-credentials/route.d.ts +3 -0
  52. package/.medusa/server/src/api/admin/paypal/save-credentials/route.d.ts.map +1 -0
  53. package/.medusa/server/src/api/admin/paypal/save-credentials/route.js +13 -0
  54. package/.medusa/server/src/api/admin/paypal/save-credentials/route.js.map +1 -0
  55. package/.medusa/server/src/api/admin/paypal/settings/route.d.ts +4 -0
  56. package/.medusa/server/src/api/admin/paypal/settings/route.d.ts.map +1 -0
  57. package/.medusa/server/src/api/admin/paypal/settings/route.js +14 -0
  58. package/.medusa/server/src/api/admin/paypal/settings/route.js.map +1 -0
  59. package/.medusa/server/src/api/admin/paypal/status/route.d.ts +3 -0
  60. package/.medusa/server/src/api/admin/paypal/status/route.d.ts.map +1 -0
  61. package/.medusa/server/src/api/admin/paypal/status/route.js +11 -0
  62. package/.medusa/server/src/api/admin/paypal/status/route.js.map +1 -0
  63. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts +3 -0
  64. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -0
  65. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js +43 -0
  66. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js.map +1 -0
  67. package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts +3 -0
  68. package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts.map +1 -0
  69. package/.medusa/server/src/api/store/paypal/capture-order/route.js +215 -0
  70. package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -0
  71. package/.medusa/server/src/api/store/paypal/config/route.d.ts +3 -0
  72. package/.medusa/server/src/api/store/paypal/config/route.d.ts.map +1 -0
  73. package/.medusa/server/src/api/store/paypal/config/route.js +45 -0
  74. package/.medusa/server/src/api/store/paypal/config/route.js.map +1 -0
  75. package/.medusa/server/src/api/store/paypal/create-order/route.d.ts +3 -0
  76. package/.medusa/server/src/api/store/paypal/create-order/route.d.ts.map +1 -0
  77. package/.medusa/server/src/api/store/paypal/create-order/route.js +305 -0
  78. package/.medusa/server/src/api/store/paypal/create-order/route.js.map +1 -0
  79. package/.medusa/server/src/api/store/paypal/disputes/route.d.ts +3 -0
  80. package/.medusa/server/src/api/store/paypal/disputes/route.d.ts.map +1 -0
  81. package/.medusa/server/src/api/store/paypal/disputes/route.js +46 -0
  82. package/.medusa/server/src/api/store/paypal/disputes/route.js.map +1 -0
  83. package/.medusa/server/src/api/store/paypal/settings/route.d.ts +3 -0
  84. package/.medusa/server/src/api/store/paypal/settings/route.d.ts.map +1 -0
  85. package/.medusa/server/src/api/store/paypal/settings/route.js +14 -0
  86. package/.medusa/server/src/api/store/paypal/settings/route.js.map +1 -0
  87. package/.medusa/server/src/api/store/paypal/webhook/route.d.ts +3 -0
  88. package/.medusa/server/src/api/store/paypal/webhook/route.d.ts.map +1 -0
  89. package/.medusa/server/src/api/store/paypal/webhook/route.js +203 -0
  90. package/.medusa/server/src/api/store/paypal/webhook/route.js.map +1 -0
  91. package/.medusa/server/src/jobs/paypal-reconcile.d.ts +7 -0
  92. package/.medusa/server/src/jobs/paypal-reconcile.d.ts.map +1 -0
  93. package/.medusa/server/src/jobs/paypal-reconcile.js +131 -0
  94. package/.medusa/server/src/jobs/paypal-reconcile.js.map +1 -0
  95. package/.medusa/server/src/jobs/paypal-webhook-retry.d.ts +7 -0
  96. package/.medusa/server/src/jobs/paypal-webhook-retry.d.ts.map +1 -0
  97. package/.medusa/server/src/jobs/paypal-webhook-retry.js +78 -0
  98. package/.medusa/server/src/jobs/paypal-webhook-retry.js.map +1 -0
  99. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.d.ts +14 -0
  100. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.d.ts.map +1 -0
  101. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.js +65 -0
  102. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.js.map +1 -0
  103. package/.medusa/server/src/modules/paypal/index.d.ts +92 -0
  104. package/.medusa/server/src/modules/paypal/index.d.ts.map +1 -0
  105. package/.medusa/server/src/modules/paypal/index.js +13 -0
  106. package/.medusa/server/src/modules/paypal/index.js.map +1 -0
  107. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.d.ts +6 -0
  108. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.d.ts.map +1 -0
  109. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.js +36 -0
  110. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.js.map +1 -0
  111. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.d.ts +6 -0
  112. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.d.ts.map +1 -0
  113. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.js +25 -0
  114. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.js.map +1 -0
  115. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.d.ts +6 -0
  116. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.d.ts.map +1 -0
  117. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.js +32 -0
  118. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.js.map +1 -0
  119. package/.medusa/server/src/modules/paypal/migrations/20260301090000_create_paypal_audit_log.d.ts +6 -0
  120. package/.medusa/server/src/modules/paypal/migrations/20260301090000_create_paypal_audit_log.d.ts.map +1 -0
  121. package/.medusa/server/src/modules/paypal/migrations/20260301090000_create_paypal_audit_log.js +29 -0
  122. package/.medusa/server/src/modules/paypal/migrations/20260301090000_create_paypal_audit_log.js.map +1 -0
  123. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.d.ts +6 -0
  124. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.d.ts.map +1 -0
  125. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.js +30 -0
  126. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.js.map +1 -0
  127. package/.medusa/server/src/modules/paypal/migrations/20260501090000_create_paypal_dispute.d.ts +6 -0
  128. package/.medusa/server/src/modules/paypal/migrations/20260501090000_create_paypal_dispute.d.ts.map +1 -0
  129. package/.medusa/server/src/modules/paypal/migrations/20260501090000_create_paypal_dispute.js +43 -0
  130. package/.medusa/server/src/modules/paypal/migrations/20260501090000_create_paypal_dispute.js.map +1 -0
  131. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.d.ts +6 -0
  132. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.d.ts.map +1 -0
  133. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.js +34 -0
  134. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.js.map +1 -0
  135. package/.medusa/server/src/modules/paypal/models/paypal_audit_log.d.ts +7 -0
  136. package/.medusa/server/src/modules/paypal/models/paypal_audit_log.d.ts.map +1 -0
  137. package/.medusa/server/src/modules/paypal/models/paypal_audit_log.js +10 -0
  138. package/.medusa/server/src/modules/paypal/models/paypal_audit_log.js.map +1 -0
  139. package/.medusa/server/src/modules/paypal/models/paypal_connection.d.ts +14 -0
  140. package/.medusa/server/src/modules/paypal/models/paypal_connection.d.ts.map +1 -0
  141. package/.medusa/server/src/modules/paypal/models/paypal_connection.js +17 -0
  142. package/.medusa/server/src/modules/paypal/models/paypal_connection.js.map +1 -0
  143. package/.medusa/server/src/modules/paypal/models/paypal_dispute.d.ts +16 -0
  144. package/.medusa/server/src/modules/paypal/models/paypal_dispute.d.ts.map +1 -0
  145. package/.medusa/server/src/modules/paypal/models/paypal_dispute.js +19 -0
  146. package/.medusa/server/src/modules/paypal/models/paypal_dispute.js.map +1 -0
  147. package/.medusa/server/src/modules/paypal/models/paypal_metric.d.ts +7 -0
  148. package/.medusa/server/src/modules/paypal/models/paypal_metric.d.ts.map +1 -0
  149. package/.medusa/server/src/modules/paypal/models/paypal_metric.js +10 -0
  150. package/.medusa/server/src/modules/paypal/models/paypal_metric.js.map +1 -0
  151. package/.medusa/server/src/modules/paypal/models/paypal_settings.d.ts +6 -0
  152. package/.medusa/server/src/modules/paypal/models/paypal_settings.d.ts.map +1 -0
  153. package/.medusa/server/src/modules/paypal/models/paypal_settings.js +9 -0
  154. package/.medusa/server/src/modules/paypal/models/paypal_settings.js.map +1 -0
  155. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.d.ts +17 -0
  156. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.d.ts.map +1 -0
  157. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.js +20 -0
  158. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.js.map +1 -0
  159. package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts +35 -0
  160. package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts.map +1 -0
  161. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js +569 -0
  162. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js.map +1 -0
  163. package/.medusa/server/src/modules/paypal/payment-provider/index.d.ts +10 -0
  164. package/.medusa/server/src/modules/paypal/payment-provider/index.d.ts.map +1 -0
  165. package/.medusa/server/src/modules/paypal/payment-provider/index.js +22 -0
  166. package/.medusa/server/src/modules/paypal/payment-provider/index.js.map +1 -0
  167. package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts +44 -0
  168. package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts.map +1 -0
  169. package/.medusa/server/src/modules/paypal/payment-provider/service.js +825 -0
  170. package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -0
  171. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.d.ts +3 -0
  172. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.d.ts.map +1 -0
  173. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.js +74 -0
  174. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.js.map +1 -0
  175. package/.medusa/server/src/modules/paypal/service.d.ts +362 -0
  176. package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -0
  177. package/.medusa/server/src/modules/paypal/service.js +1180 -0
  178. package/.medusa/server/src/modules/paypal/service.js.map +1 -0
  179. package/.medusa/server/src/modules/paypal/types/config.d.ts +14 -0
  180. package/.medusa/server/src/modules/paypal/types/config.d.ts.map +1 -0
  181. package/.medusa/server/src/modules/paypal/types/config.js +33 -0
  182. package/.medusa/server/src/modules/paypal/types/config.js.map +1 -0
  183. package/.medusa/server/src/modules/paypal/utils/amounts.d.ts +3 -0
  184. package/.medusa/server/src/modules/paypal/utils/amounts.d.ts.map +1 -0
  185. package/.medusa/server/src/modules/paypal/utils/amounts.js +40 -0
  186. package/.medusa/server/src/modules/paypal/utils/amounts.js.map +1 -0
  187. package/.medusa/server/src/modules/paypal/utils/crypto.d.ts +4 -0
  188. package/.medusa/server/src/modules/paypal/utils/crypto.d.ts.map +1 -0
  189. package/.medusa/server/src/modules/paypal/utils/crypto.js +47 -0
  190. package/.medusa/server/src/modules/paypal/utils/crypto.js.map +1 -0
  191. package/.medusa/server/src/modules/paypal/utils/currencies.d.ts +19 -0
  192. package/.medusa/server/src/modules/paypal/utils/currencies.d.ts.map +1 -0
  193. package/.medusa/server/src/modules/paypal/utils/currencies.js +69 -0
  194. package/.medusa/server/src/modules/paypal/utils/currencies.js.map +1 -0
  195. package/.medusa/server/src/modules/paypal/utils/provider-ids.d.ts +9 -0
  196. package/.medusa/server/src/modules/paypal/utils/provider-ids.d.ts.map +1 -0
  197. package/.medusa/server/src/modules/paypal/utils/provider-ids.js +50 -0
  198. package/.medusa/server/src/modules/paypal/utils/provider-ids.js.map +1 -0
  199. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts +38 -0
  200. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts.map +1 -0
  201. package/.medusa/server/src/modules/paypal/webhook-processor.js +265 -0
  202. package/.medusa/server/src/modules/paypal/webhook-processor.js.map +1 -0
  203. package/LICENSE +21 -0
  204. package/README.md +67 -0
  205. package/package.json +61 -0
  206. package/postcss.config.cjs +3 -0
  207. package/src/admin/index.ts +7 -0
  208. package/src/admin/routes/settings/paypal/_components/Tabs.tsx +55 -0
  209. package/src/admin/routes/settings/paypal/_components/Toast.tsx +51 -0
  210. package/src/admin/routes/settings/paypal/additional-settings/page.tsx +346 -0
  211. package/src/admin/routes/settings/paypal/advanced-card-payments/page.tsx +381 -0
  212. package/src/admin/routes/settings/paypal/apple-pay/page.tsx +5 -0
  213. package/src/admin/routes/settings/paypal/audit-logs/page.tsx +131 -0
  214. package/src/admin/routes/settings/paypal/connection/page.tsx +750 -0
  215. package/src/admin/routes/settings/paypal/disputes/page.tsx +259 -0
  216. package/src/admin/routes/settings/paypal/google-pay/page.tsx +5 -0
  217. package/src/admin/routes/settings/paypal/page.tsx +16 -0
  218. package/src/admin/routes/settings/paypal/pay-later-messaging/page.tsx +5 -0
  219. package/src/admin/routes/settings/paypal/paypal-settings/page.tsx +557 -0
  220. package/src/admin/routes/settings/paypal/reconciliation-status/page.tsx +165 -0
  221. package/src/api/admin/payment-collections/[id]/payment-sessions/route.ts +32 -0
  222. package/src/api/admin/paypal/audit-logs/route.ts +13 -0
  223. package/src/api/admin/paypal/disconnect/route.ts +8 -0
  224. package/src/api/admin/paypal/disputes/[id]/route.ts +19 -0
  225. package/src/api/admin/paypal/disputes/route.ts +30 -0
  226. package/src/api/admin/paypal/disputes/summary/route.ts +18 -0
  227. package/src/api/admin/paypal/environment/route.ts +25 -0
  228. package/src/api/admin/paypal/onboard-complete/route.ts +44 -0
  229. package/src/api/admin/paypal/onboarding-link/route.ts +45 -0
  230. package/src/api/admin/paypal/onboarding-status/route.ts +18 -0
  231. package/src/api/admin/paypal/reconciliation-status/route.ts +7 -0
  232. package/src/api/admin/paypal/rotate-credentials/route.ts +8 -0
  233. package/src/api/admin/paypal/save-credentials/route.ts +14 -0
  234. package/src/api/admin/paypal/settings/route.ts +14 -0
  235. package/src/api/admin/paypal/status/route.ts +12 -0
  236. package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +51 -0
  237. package/src/api/store/paypal/capture-order/route.ts +270 -0
  238. package/src/api/store/paypal/config/route.ts +59 -0
  239. package/src/api/store/paypal/create-order/route.ts +374 -0
  240. package/src/api/store/paypal/disputes/route.ts +67 -0
  241. package/src/api/store/paypal/settings/route.ts +12 -0
  242. package/src/api/store/paypal/webhook/route.ts +247 -0
  243. package/src/jobs/paypal-reconcile.ts +135 -0
  244. package/src/jobs/paypal-webhook-retry.ts +86 -0
  245. package/src/modules/paypal/clients/paypal-seller.client.ts +59 -0
  246. package/src/modules/paypal/index.ts +8 -0
  247. package/src/modules/paypal/migrations/20260115120000_create_paypal_connection.ts +33 -0
  248. package/src/modules/paypal/migrations/20260123090000_create_paypal_settings.ts +22 -0
  249. package/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.ts +29 -0
  250. package/src/modules/paypal/migrations/20260301090000_create_paypal_audit_log.ts +26 -0
  251. package/src/modules/paypal/migrations/20260401090000_create_paypal_metric.ts +27 -0
  252. package/src/modules/paypal/migrations/20260501090000_create_paypal_dispute.ts +40 -0
  253. package/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.ts +31 -0
  254. package/src/modules/paypal/models/paypal_audit_log.ts +9 -0
  255. package/src/modules/paypal/models/paypal_connection.ts +21 -0
  256. package/src/modules/paypal/models/paypal_dispute.ts +18 -0
  257. package/src/modules/paypal/models/paypal_metric.ts +9 -0
  258. package/src/modules/paypal/models/paypal_settings.ts +8 -0
  259. package/src/modules/paypal/models/paypal_webhook_event.ts +19 -0
  260. package/src/modules/paypal/payment-provider/README.md +22 -0
  261. package/src/modules/paypal/payment-provider/card-service.ts +710 -0
  262. package/src/modules/paypal/payment-provider/index.ts +19 -0
  263. package/src/modules/paypal/payment-provider/service.ts +1035 -0
  264. package/src/modules/paypal/payment-provider/webhook-utils.ts +88 -0
  265. package/src/modules/paypal/service.ts +1422 -0
  266. package/src/modules/paypal/types/config.ts +47 -0
  267. package/src/modules/paypal/utils/amounts.ts +41 -0
  268. package/src/modules/paypal/utils/crypto.ts +51 -0
  269. package/src/modules/paypal/utils/currencies.ts +84 -0
  270. package/src/modules/paypal/utils/provider-ids.ts +53 -0
  271. package/src/modules/paypal/webhook-processor.ts +313 -0
  272. package/tsconfig.json +31 -0
@@ -0,0 +1,2127 @@
1
+ "use strict";
2
+ const jsxRuntime = require("react/jsx-runtime");
3
+ const adminSdk = require("@medusajs/admin-sdk");
4
+ const reactRouterDom = require("react-router-dom");
5
+ const react = require("react");
6
+ const config$1 = adminSdk.defineRouteConfig({
7
+ label: "PayPal",
8
+ icon: "Coins"
9
+ });
10
+ function PayPalSettingsIndexRoute() {
11
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "connection", replace: true });
12
+ }
13
+ const BASE = "/settings/paypal";
14
+ const TABS = [
15
+ { label: "PayPal Connection", to: `${BASE}/connection` },
16
+ { label: "PayPal Settings", to: `${BASE}/paypal-settings` },
17
+ { label: "Advanced Card Payments", to: `${BASE}/advanced-card-payments` },
18
+ { label: "Disputes", to: `${BASE}/disputes` },
19
+ { label: "Reconciliation Status", to: `${BASE}/reconciliation-status` },
20
+ /* { label: "Google Pay", to: `${BASE}/google-pay` },
21
+ { label: "Apple Pay", to: `${BASE}/apple-pay` },
22
+ { label: "Pay Later Messaging", to: `${BASE}/pay-later-messaging` }, */
23
+ { label: "Audit Logs", to: `${BASE}/audit-logs` },
24
+ { label: "Additional Settings", to: `${BASE}/additional-settings` }
25
+ ];
26
+ function isActive(pathname, to) {
27
+ return pathname === to || pathname.startsWith(to + "/");
28
+ }
29
+ function PayPalTabs() {
30
+ const { pathname } = reactRouterDom.useLocation();
31
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-6 text-sm", children: TABS.map((t) => {
32
+ const active = isActive(pathname, t.to);
33
+ return /* @__PURE__ */ jsxRuntime.jsx(
34
+ reactRouterDom.Link,
35
+ {
36
+ to: t.to,
37
+ className: active ? "border-b-2 border-ui-fg-base pb-2 font-medium text-ui-fg-base" : "pb-2 text-ui-fg-subtle hover:text-ui-fg-base",
38
+ children: t.label
39
+ },
40
+ t.to
41
+ );
42
+ }) }) });
43
+ }
44
+ const DEFAULT_FORM$1 = {
45
+ paymentAction: "capture",
46
+ brandName: "PayPal",
47
+ landingPage: "no_preference",
48
+ requireInstantPayment: false,
49
+ useShippingAsBilling: true,
50
+ sendItemDetails: true,
51
+ skipOrderReviewPage: true,
52
+ invoicePrefix: "WC-",
53
+ creditCardStatementName: "PayPal",
54
+ enableLogging: true,
55
+ logPath: "/uploads/wc-logs/"
56
+ };
57
+ function mergeWithDefaults$1(saved) {
58
+ if (!saved) return { ...DEFAULT_FORM$1 };
59
+ const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
60
+ return {
61
+ ...DEFAULT_FORM$1,
62
+ ...Object.fromEntries(entries)
63
+ };
64
+ }
65
+ function SectionCard$2({
66
+ title,
67
+ description,
68
+ right,
69
+ children
70
+ }) {
71
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
72
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
73
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
74
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
75
+ description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
76
+ ] }),
77
+ right
78
+ ] }),
79
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
80
+ ] });
81
+ }
82
+ function FieldRow$2({
83
+ label,
84
+ hint,
85
+ children
86
+ }) {
87
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
88
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
89
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
90
+ hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
91
+ ] }),
92
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
93
+ ] });
94
+ }
95
+ function AdditionalSettingsTab() {
96
+ const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM$1 }));
97
+ const [loading, setLoading] = react.useState(false);
98
+ const [saving, setSaving] = react.useState(false);
99
+ const didInit = react.useRef(false);
100
+ react.useEffect(() => {
101
+ if (didInit.current) return;
102
+ didInit.current = true;
103
+ (async () => {
104
+ try {
105
+ setLoading(true);
106
+ const r = await fetch("/admin/paypal/settings", {
107
+ credentials: "include",
108
+ headers: { "Accept": "application/json" }
109
+ });
110
+ if (!r.ok) return;
111
+ const json = await r.json();
112
+ const payload = (json == null ? void 0 : json.data) ?? json;
113
+ const saved = payload == null ? void 0 : payload.additional_settings;
114
+ if (saved && typeof saved === "object") {
115
+ setForm(mergeWithDefaults$1(saved));
116
+ }
117
+ } finally {
118
+ setLoading(false);
119
+ }
120
+ })();
121
+ }, []);
122
+ const [toast, setToast] = react.useState(null);
123
+ async function onSave() {
124
+ try {
125
+ setSaving(true);
126
+ setToast(null);
127
+ const r = await fetch("/admin/paypal/settings", {
128
+ method: "POST",
129
+ credentials: "include",
130
+ headers: {
131
+ "Content-Type": "application/json",
132
+ "Accept": "application/json"
133
+ },
134
+ body: JSON.stringify({
135
+ additional_settings: form
136
+ })
137
+ });
138
+ if (!r.ok) {
139
+ const errText = await r.text().catch(() => "");
140
+ throw new Error(errText || "Failed to save settings");
141
+ }
142
+ const json = await r.json().catch(() => ({}));
143
+ const payload = (json == null ? void 0 : json.data) ?? json;
144
+ const saved = payload == null ? void 0 : payload.additional_settings;
145
+ if (saved && typeof saved === "object") {
146
+ setForm(mergeWithDefaults$1(saved));
147
+ }
148
+ setToast({ type: "success", message: "Settings saved" });
149
+ window.setTimeout(() => setToast(null), 2500);
150
+ } catch (e) {
151
+ setToast({ type: "error", message: (e == null ? void 0 : e.message) || "Failed to save settings" });
152
+ window.setTimeout(() => setToast(null), 3500);
153
+ } finally {
154
+ setSaving(false);
155
+ }
156
+ }
157
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
158
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-between gap-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Gateway By Easy Payment" }) }) }),
159
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
160
+ toast ? /* @__PURE__ */ jsxRuntime.jsx(
161
+ "div",
162
+ {
163
+ className: "fixed right-6 top-6 z-50 rounded-md border border-ui-border-base bg-ui-bg-base px-4 py-3 text-sm shadow-lg",
164
+ role: "status",
165
+ "aria-live": "polite",
166
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message })
167
+ }
168
+ ) : null,
169
+ /* @__PURE__ */ jsxRuntime.jsx(
170
+ SectionCard$2,
171
+ {
172
+ title: "Additional Settings",
173
+ description: "These settings control checkout behavior, PayPal experience, and logging.",
174
+ right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
175
+ /* @__PURE__ */ jsxRuntime.jsx(
176
+ "button",
177
+ {
178
+ type: "button",
179
+ onClick: onSave,
180
+ disabled: saving || loading,
181
+ className: "rounded-md bg-ui-button-neutral px-4 py-2 text-sm font-medium text-ui-fg-on-color shadow-sm hover:opacity-90 disabled:opacity-60",
182
+ children: saving ? "Saving..." : "Save settings"
183
+ }
184
+ ),
185
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
186
+ ] }),
187
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
188
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Payment action", children: /* @__PURE__ */ jsxRuntime.jsxs(
189
+ "select",
190
+ {
191
+ value: form.paymentAction,
192
+ onChange: (e) => setForm((p) => ({ ...p, paymentAction: e.target.value })),
193
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
194
+ children: [
195
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "capture", children: "Capture" }),
196
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "authorize", children: "Authorize" })
197
+ ]
198
+ }
199
+ ) }),
200
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Brand Name", children: /* @__PURE__ */ jsxRuntime.jsx(
201
+ "input",
202
+ {
203
+ value: form.brandName,
204
+ onChange: (e) => setForm((p) => ({ ...p, brandName: e.target.value })),
205
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
206
+ placeholder: "PayPal"
207
+ }
208
+ ) }),
209
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Landing Page", children: /* @__PURE__ */ jsxRuntime.jsxs(
210
+ "select",
211
+ {
212
+ value: form.landingPage,
213
+ onChange: (e) => setForm((p) => ({ ...p, landingPage: e.target.value })),
214
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
215
+ children: [
216
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "no_preference", children: "No Preference" }),
217
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "login", children: "Login" }),
218
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "billing", children: "Billing" })
219
+ ]
220
+ }
221
+ ) }),
222
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Instant Payments", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
223
+ /* @__PURE__ */ jsxRuntime.jsx(
224
+ "input",
225
+ {
226
+ type: "checkbox",
227
+ checked: form.requireInstantPayment,
228
+ onChange: (e) => setForm((p) => ({ ...p, requireInstantPayment: e.target.checked })),
229
+ className: "h-4 w-4 rounded border-ui-border-base"
230
+ }
231
+ ),
232
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Require Instant Payment" })
233
+ ] }) }),
234
+ /* @__PURE__ */ jsxRuntime.jsx(
235
+ FieldRow$2,
236
+ {
237
+ label: "Billing Address",
238
+ hint: "If the billing address is empty and PayPal provides a shipping address, the order will use the shipping address as the billing address.",
239
+ children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
240
+ /* @__PURE__ */ jsxRuntime.jsx(
241
+ "input",
242
+ {
243
+ type: "checkbox",
244
+ checked: form.useShippingAsBilling,
245
+ onChange: (e) => setForm((p) => ({ ...p, useShippingAsBilling: e.target.checked })),
246
+ className: "h-4 w-4 rounded border-ui-border-base"
247
+ }
248
+ ),
249
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Use PayPal Shipping Address as Billing" })
250
+ ] })
251
+ }
252
+ ),
253
+ /* @__PURE__ */ jsxRuntime.jsx(
254
+ FieldRow$2,
255
+ {
256
+ label: "Send Item Details",
257
+ hint: "Include all line item details in the payment request to PayPal so that they can be seen from the PayPal transaction details page.",
258
+ children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
259
+ /* @__PURE__ */ jsxRuntime.jsx(
260
+ "input",
261
+ {
262
+ type: "checkbox",
263
+ checked: form.sendItemDetails,
264
+ onChange: (e) => setForm((p) => ({ ...p, sendItemDetails: e.target.checked })),
265
+ className: "h-4 w-4 rounded border-ui-border-base"
266
+ }
267
+ ),
268
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Send line item details to PayPal" })
269
+ ] })
270
+ }
271
+ ),
272
+ /* @__PURE__ */ jsxRuntime.jsx(
273
+ FieldRow$2,
274
+ {
275
+ label: "Order Review Page",
276
+ hint: "Payments from the Product or Cart page skip the review step and go straight to the Thank You page.",
277
+ children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
278
+ /* @__PURE__ */ jsxRuntime.jsx(
279
+ "input",
280
+ {
281
+ type: "checkbox",
282
+ checked: form.skipOrderReviewPage,
283
+ onChange: (e) => setForm((p) => ({ ...p, skipOrderReviewPage: e.target.checked })),
284
+ className: "h-4 w-4 rounded border-ui-border-base"
285
+ }
286
+ ),
287
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Skip Order Review Page" })
288
+ ] })
289
+ }
290
+ ),
291
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Invoice prefix", children: /* @__PURE__ */ jsxRuntime.jsx(
292
+ "input",
293
+ {
294
+ value: form.invoicePrefix,
295
+ onChange: (e) => setForm((p) => ({ ...p, invoicePrefix: e.target.value })),
296
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
297
+ placeholder: "WC-"
298
+ }
299
+ ) }),
300
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Credit Card Statement Name", children: /* @__PURE__ */ jsxRuntime.jsx(
301
+ "input",
302
+ {
303
+ value: form.creditCardStatementName,
304
+ onChange: (e) => setForm((p) => ({ ...p, creditCardStatementName: e.target.value })),
305
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
306
+ placeholder: "PayPal"
307
+ }
308
+ ) }),
309
+ /* @__PURE__ */ jsxRuntime.jsx(
310
+ FieldRow$2,
311
+ {
312
+ label: "Debug log",
313
+ hint: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
314
+ "Log PayPal events such as Webhook, Payment, Refund.",
315
+ " ",
316
+ form.logPath ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
317
+ "Log location: ",
318
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: form.logPath })
319
+ ] }) : null
320
+ ] }),
321
+ children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
322
+ /* @__PURE__ */ jsxRuntime.jsx(
323
+ "input",
324
+ {
325
+ type: "checkbox",
326
+ checked: form.enableLogging,
327
+ onChange: (e) => setForm((p) => ({ ...p, enableLogging: e.target.checked })),
328
+ className: "h-4 w-4 rounded border-ui-border-base"
329
+ }
330
+ ),
331
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable logging" })
332
+ ] })
333
+ }
334
+ )
335
+ ] })
336
+ }
337
+ )
338
+ ] }) });
339
+ }
340
+ function PayPalApplePayPage() {
341
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
342
+ }
343
+ const DEFAULT_FORM = {
344
+ enabled: true,
345
+ title: "Credit or Debit Card",
346
+ disabledCards: [],
347
+ threeDS: "when_required",
348
+ cardSaveEnabled: false
349
+ };
350
+ function mergeWithDefaults(saved) {
351
+ if (!saved) return { ...DEFAULT_FORM };
352
+ const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
353
+ return {
354
+ ...DEFAULT_FORM,
355
+ ...Object.fromEntries(entries)
356
+ };
357
+ }
358
+ const CARD_BRANDS = [
359
+ { value: "visa", label: "Visa" },
360
+ { value: "mastercard", label: "Mastercard" },
361
+ { value: "amex", label: "American Express" },
362
+ { value: "discover", label: "Discover" },
363
+ { value: "diners", label: "Diners Club" },
364
+ { value: "jcb", label: "JCB" },
365
+ { value: "unionpay", label: "UnionPay" }
366
+ ];
367
+ const THREE_DS_OPTIONS = [
368
+ {
369
+ value: "when_required",
370
+ label: "3D Secure when required",
371
+ hint: "Triggers 3DS only when the card / issuer requires it."
372
+ },
373
+ {
374
+ value: "sli",
375
+ label: "3D Secure (SCA) / liability shift (recommended)",
376
+ hint: "Attempts to optimize for liability shift while remaining compliant."
377
+ },
378
+ {
379
+ value: "always",
380
+ label: "Always request 3D Secure",
381
+ hint: "Forces 3DS challenge whenever possible (may reduce conversion)."
382
+ }
383
+ ];
384
+ function cx$1(...parts) {
385
+ return parts.filter(Boolean).join(" ");
386
+ }
387
+ function Pill$1({
388
+ children,
389
+ onRemove
390
+ }) {
391
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 rounded-md border border-ui-border-base bg-ui-bg-base px-2 py-1 text-sm text-ui-fg-base", children: [
392
+ children,
393
+ onRemove ? /* @__PURE__ */ jsxRuntime.jsx(
394
+ "button",
395
+ {
396
+ type: "button",
397
+ onClick: onRemove,
398
+ className: "ml-1 rounded px-1 text-ui-fg-subtle hover:text-ui-fg-base",
399
+ "aria-label": "Remove",
400
+ children: "×"
401
+ }
402
+ ) : null
403
+ ] });
404
+ }
405
+ function SectionCard$1({
406
+ title,
407
+ description,
408
+ right,
409
+ children
410
+ }) {
411
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
412
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
413
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
414
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
415
+ description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
416
+ ] }),
417
+ right
418
+ ] }),
419
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
420
+ ] });
421
+ }
422
+ function FieldRow$1({
423
+ label,
424
+ hint,
425
+ children
426
+ }) {
427
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
428
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
429
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
430
+ hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
431
+ ] }),
432
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
433
+ ] });
434
+ }
435
+ function AdvancedCardPaymentsTab() {
436
+ var _a, _b;
437
+ const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM }));
438
+ const [loading, setLoading] = react.useState(false);
439
+ const [saving, setSaving] = react.useState(false);
440
+ const [toast, setToast] = react.useState(null);
441
+ const didInit = react.useRef(false);
442
+ react.useEffect(() => {
443
+ if (didInit.current) return;
444
+ didInit.current = true;
445
+ (async () => {
446
+ try {
447
+ setLoading(true);
448
+ const r = await fetch("/admin/paypal/settings", {
449
+ credentials: "include",
450
+ headers: { "Accept": "application/json" }
451
+ });
452
+ if (!r.ok) return;
453
+ const json = await r.json();
454
+ const payload = (json == null ? void 0 : json.data) ?? json;
455
+ const saved = payload == null ? void 0 : payload.advanced_card_payments;
456
+ if (saved && typeof saved === "object") {
457
+ setForm(mergeWithDefaults(saved));
458
+ }
459
+ } finally {
460
+ setLoading(false);
461
+ }
462
+ })();
463
+ }, []);
464
+ async function onSave() {
465
+ try {
466
+ setSaving(true);
467
+ const r = await fetch("/admin/paypal/settings", {
468
+ method: "POST",
469
+ credentials: "include",
470
+ headers: {
471
+ "Content-Type": "application/json",
472
+ "Accept": "application/json"
473
+ },
474
+ body: JSON.stringify({ advanced_card_payments: form })
475
+ });
476
+ if (!r.ok) {
477
+ const t = await r.text();
478
+ setToast({ type: "error", message: "Failed to save settings. " + t });
479
+ window.setTimeout(() => setToast(null), 3500);
480
+ return;
481
+ }
482
+ const json = await r.json().catch(() => null);
483
+ const payload = (json == null ? void 0 : json.data) ?? json;
484
+ const saved = payload == null ? void 0 : payload.advanced_card_payments;
485
+ if (saved && typeof saved === "object") {
486
+ setForm(mergeWithDefaults(saved));
487
+ }
488
+ setToast({ type: "success", message: "Settings saved" });
489
+ window.setTimeout(() => setToast(null), 2500);
490
+ } finally {
491
+ setSaving(false);
492
+ }
493
+ }
494
+ const disabledSet = react.useMemo(() => new Set(form.disabledCards), [form.disabledCards]);
495
+ function toggleDisabledCard(value) {
496
+ setForm((prev) => {
497
+ const exists = prev.disabledCards.includes(value);
498
+ return {
499
+ ...prev,
500
+ disabledCards: exists ? prev.disabledCards.filter((v) => v !== value) : [...prev.disabledCards, value]
501
+ };
502
+ });
503
+ }
504
+ function removeDisabledCard(value) {
505
+ setForm((prev) => ({
506
+ ...prev,
507
+ disabledCards: prev.disabledCards.filter((v) => v !== value)
508
+ }));
509
+ }
510
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
511
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-between gap-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Gateway By Easy Payment" }) }) }),
512
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
513
+ toast ? /* @__PURE__ */ jsxRuntime.jsx(
514
+ "div",
515
+ {
516
+ className: "fixed right-6 top-6 z-50 rounded-md border border-ui-border-base bg-ui-bg-base px-4 py-3 text-sm shadow-lg",
517
+ role: "status",
518
+ "aria-live": "polite",
519
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message })
520
+ }
521
+ ) : null,
522
+ /* @__PURE__ */ jsxRuntime.jsx(
523
+ SectionCard$1,
524
+ {
525
+ title: "Advanced Card Payments",
526
+ description: "Control card checkout settings, 3D Secure behavior, and card saving.",
527
+ right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
528
+ /* @__PURE__ */ jsxRuntime.jsx(
529
+ "button",
530
+ {
531
+ type: "button",
532
+ onClick: onSave,
533
+ disabled: saving || loading,
534
+ className: "rounded-md bg-ui-button-neutral px-4 py-2 text-sm font-medium text-ui-fg-on-color shadow-sm hover:opacity-90 disabled:opacity-60",
535
+ children: saving ? "Saving..." : "Save settings"
536
+ }
537
+ ),
538
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
539
+ ] }),
540
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
541
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Enable/Disable", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
542
+ /* @__PURE__ */ jsxRuntime.jsx(
543
+ "input",
544
+ {
545
+ type: "checkbox",
546
+ checked: form.enabled,
547
+ onChange: (e) => setForm((p) => ({ ...p, enabled: e.target.checked })),
548
+ className: "h-4 w-4 rounded border-ui-border-base"
549
+ }
550
+ ),
551
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
552
+ ] }) }),
553
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Title", children: /* @__PURE__ */ jsxRuntime.jsx(
554
+ "input",
555
+ {
556
+ value: form.title,
557
+ onChange: (e) => setForm((p) => ({ ...p, title: e.target.value })),
558
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
559
+ placeholder: "Credit or Debit Card"
560
+ }
561
+ ) }),
562
+ /* @__PURE__ */ jsxRuntime.jsx(
563
+ FieldRow$1,
564
+ {
565
+ label: "Disable specific credit cards",
566
+ hint: "Select card brands to hide from the card form.",
567
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
568
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: form.disabledCards.length ? form.disabledCards.map((v) => {
569
+ var _a2;
570
+ const label = ((_a2 = CARD_BRANDS.find((b) => b.value === v)) == null ? void 0 : _a2.label) ?? v;
571
+ return /* @__PURE__ */ jsxRuntime.jsx(Pill$1, { onRemove: () => removeDisabledCard(v), children: label }, v);
572
+ }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No card brands disabled." }) }),
573
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-ui-border-base p-3", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-2 md:grid-cols-2", children: CARD_BRANDS.map((b) => {
574
+ const checked = disabledSet.has(b.value);
575
+ return /* @__PURE__ */ jsxRuntime.jsxs(
576
+ "label",
577
+ {
578
+ className: cx$1(
579
+ "flex items-center gap-2 rounded-md p-2",
580
+ "hover:bg-ui-bg-subtle"
581
+ ),
582
+ children: [
583
+ /* @__PURE__ */ jsxRuntime.jsx(
584
+ "input",
585
+ {
586
+ type: "checkbox",
587
+ checked,
588
+ onChange: () => toggleDisabledCard(b.value),
589
+ className: "h-4 w-4 rounded border-ui-border-base"
590
+ }
591
+ ),
592
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: b.label })
593
+ ]
594
+ },
595
+ b.value
596
+ );
597
+ }) }) })
598
+ ] })
599
+ }
600
+ ),
601
+ /* @__PURE__ */ jsxRuntime.jsx(
602
+ FieldRow$1,
603
+ {
604
+ label: "Contingency for 3D Secure",
605
+ hint: "Choose when 3D Secure should be triggered during card payments.",
606
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
607
+ /* @__PURE__ */ jsxRuntime.jsx(
608
+ "select",
609
+ {
610
+ value: form.threeDS,
611
+ onChange: (e) => setForm((p) => ({ ...p, threeDS: e.target.value })),
612
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
613
+ children: THREE_DS_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
614
+ }
615
+ ),
616
+ ((_a = THREE_DS_OPTIONS.find((o) => o.value === form.threeDS)) == null ? void 0 : _a.hint) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-ui-fg-subtle", children: (_b = THREE_DS_OPTIONS.find((o) => o.value === form.threeDS)) == null ? void 0 : _b.hint }) : null
617
+ ] })
618
+ }
619
+ ),
620
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Card Save Enabled", hint: "Allow customers to save a card at checkout for future use.", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
621
+ /* @__PURE__ */ jsxRuntime.jsx(
622
+ "input",
623
+ {
624
+ type: "checkbox",
625
+ checked: form.cardSaveEnabled,
626
+ onChange: (e) => setForm((p) => ({ ...p, cardSaveEnabled: e.target.checked })),
627
+ className: "h-4 w-4 rounded border-ui-border-base"
628
+ }
629
+ ),
630
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable card saving at checkout" })
631
+ ] }) })
632
+ ] })
633
+ }
634
+ )
635
+ ] }) });
636
+ }
637
+ function formatDate$2(value) {
638
+ if (!value) {
639
+ return "";
640
+ }
641
+ const parsed = new Date(value);
642
+ if (Number.isNaN(parsed.getTime())) {
643
+ return value;
644
+ }
645
+ return parsed.toLocaleString();
646
+ }
647
+ function PayPalAuditLogsPage() {
648
+ const [logs, setLogs] = react.useState([]);
649
+ const [loading, setLoading] = react.useState(false);
650
+ const [error, setError] = react.useState(null);
651
+ const fetchLogs = react.useCallback(async () => {
652
+ try {
653
+ setLoading(true);
654
+ setError(null);
655
+ const response = await fetch("/admin/paypal/audit-logs?limit=50", {
656
+ credentials: "include",
657
+ headers: {
658
+ Accept: "application/json"
659
+ }
660
+ });
661
+ if (!response.ok) {
662
+ const message = await response.text().catch(() => "");
663
+ throw new Error(message || "Failed to load audit logs.");
664
+ }
665
+ const data = await response.json().catch(() => ({}));
666
+ setLogs((data == null ? void 0 : data.logs) || []);
667
+ } catch (fetchError) {
668
+ setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load audit logs.");
669
+ setLogs([]);
670
+ } finally {
671
+ setLoading(false);
672
+ }
673
+ }, []);
674
+ react.useEffect(() => {
675
+ fetchLogs();
676
+ }, [fetchLogs]);
677
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
678
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
679
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Audit Logs" }),
680
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Track administrative changes and credential events for PayPal configuration." })
681
+ ] }),
682
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
683
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
684
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
685
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Latest events" }),
686
+ /* @__PURE__ */ jsxRuntime.jsx(
687
+ "button",
688
+ {
689
+ type: "button",
690
+ onClick: fetchLogs,
691
+ className: "rounded-md border border-ui-border-base px-3 py-2 text-sm text-ui-fg-base",
692
+ disabled: loading,
693
+ children: loading ? "Refreshing..." : "Refresh"
694
+ }
695
+ )
696
+ ] }) }),
697
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
698
+ error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-600", children: error }) : null,
699
+ !error && logs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-ui-fg-subtle", children: loading ? "Loading audit logs..." : "No audit log entries found yet." }) : null,
700
+ logs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full text-left text-sm", children: [
701
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "text-ui-fg-muted", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
702
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 pr-4 font-medium", children: "Timestamp" }),
703
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 pr-4 font-medium", children: "Event" }),
704
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 font-medium", children: "Details" })
705
+ ] }) }),
706
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: logs.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-t border-ui-border-base", children: [
707
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: formatDate$2(entry.created_at) || "—" }),
708
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: entry.event_type || "—" }),
709
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 text-ui-fg-subtle", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap rounded-md bg-ui-bg-subtle p-2 text-xs text-ui-fg-subtle", children: JSON.stringify(entry.metadata || {}, null, 2) }) })
710
+ ] }, entry.id)) })
711
+ ] }) }) : null
712
+ ] })
713
+ ] })
714
+ ] }) });
715
+ }
716
+ const EMPTY_FILTERS = {
717
+ dispute_id: "",
718
+ status: "",
719
+ order_id: "",
720
+ cart_id: ""
721
+ };
722
+ function formatDate$1(value) {
723
+ if (!value) {
724
+ return "";
725
+ }
726
+ const parsed = new Date(value);
727
+ if (Number.isNaN(parsed.getTime())) {
728
+ return value;
729
+ }
730
+ return parsed.toLocaleString();
731
+ }
732
+ function PayPalDisputesPage() {
733
+ const [filters, setFilters] = react.useState({ ...EMPTY_FILTERS });
734
+ const [disputes, setDisputes] = react.useState([]);
735
+ const [loading, setLoading] = react.useState(false);
736
+ const [error, setError] = react.useState(null);
737
+ const queryString = react.useMemo(() => {
738
+ const params = new URLSearchParams();
739
+ Object.entries(filters).forEach(([key, value]) => {
740
+ if (value.trim()) {
741
+ params.set(key, value.trim());
742
+ }
743
+ });
744
+ const qs = params.toString();
745
+ return qs ? `?${qs}` : "";
746
+ }, [filters]);
747
+ const fetchDisputes = react.useCallback(async (source) => {
748
+ try {
749
+ setLoading(true);
750
+ setError(null);
751
+ const params = new URLSearchParams();
752
+ Object.entries(source).forEach(([key, value]) => {
753
+ if (value.trim()) {
754
+ params.set(key, value.trim());
755
+ }
756
+ });
757
+ const qs = params.toString();
758
+ const resp = await fetch(`/admin/paypal/disputes${qs ? `?${qs}` : ""}`, {
759
+ credentials: "include",
760
+ headers: {
761
+ Accept: "application/json"
762
+ }
763
+ });
764
+ if (!resp.ok) {
765
+ const message = await resp.text().catch(() => "");
766
+ throw new Error(message || "Failed to load disputes");
767
+ }
768
+ const json = await resp.json().catch(() => ({}));
769
+ setDisputes((json == null ? void 0 : json.disputes) || []);
770
+ } catch (fetchError) {
771
+ setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load disputes");
772
+ setDisputes([]);
773
+ } finally {
774
+ setLoading(false);
775
+ }
776
+ }, []);
777
+ react.useEffect(() => {
778
+ fetchDisputes(EMPTY_FILTERS);
779
+ }, [fetchDisputes]);
780
+ const onSubmit = (event) => {
781
+ event.preventDefault();
782
+ fetchDisputes(filters);
783
+ };
784
+ const onReset = () => {
785
+ setFilters({ ...EMPTY_FILTERS });
786
+ fetchDisputes(EMPTY_FILTERS);
787
+ };
788
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
789
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
790
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Disputes" }),
791
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Review PayPal dispute activity tied to your Medusa orders. This view is read-only." })
792
+ ] }),
793
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
794
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
795
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Filters" }) }),
796
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit, className: "flex flex-col gap-4", children: [
797
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-4", children: [
798
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
799
+ "Dispute ID",
800
+ /* @__PURE__ */ jsxRuntime.jsx(
801
+ "input",
802
+ {
803
+ className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
804
+ value: filters.dispute_id,
805
+ onChange: (event) => setFilters((prev) => ({ ...prev, dispute_id: event.target.value })),
806
+ placeholder: "PP-D-123"
807
+ }
808
+ )
809
+ ] }),
810
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
811
+ "Status",
812
+ /* @__PURE__ */ jsxRuntime.jsx(
813
+ "input",
814
+ {
815
+ className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
816
+ value: filters.status,
817
+ onChange: (event) => setFilters((prev) => ({ ...prev, status: event.target.value })),
818
+ placeholder: "OPEN"
819
+ }
820
+ )
821
+ ] }),
822
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
823
+ "Order ID",
824
+ /* @__PURE__ */ jsxRuntime.jsx(
825
+ "input",
826
+ {
827
+ className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
828
+ value: filters.order_id,
829
+ onChange: (event) => setFilters((prev) => ({ ...prev, order_id: event.target.value })),
830
+ placeholder: "order_..."
831
+ }
832
+ )
833
+ ] }),
834
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
835
+ "Cart ID",
836
+ /* @__PURE__ */ jsxRuntime.jsx(
837
+ "input",
838
+ {
839
+ className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
840
+ value: filters.cart_id,
841
+ onChange: (event) => setFilters((prev) => ({ ...prev, cart_id: event.target.value })),
842
+ placeholder: "cart_..."
843
+ }
844
+ )
845
+ ] })
846
+ ] }),
847
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-3", children: [
848
+ /* @__PURE__ */ jsxRuntime.jsx(
849
+ "button",
850
+ {
851
+ type: "submit",
852
+ className: "rounded-md bg-ui-fg-base px-4 py-2 text-sm font-medium text-ui-bg-base",
853
+ disabled: loading,
854
+ children: loading ? "Loading..." : "Apply filters"
855
+ }
856
+ ),
857
+ /* @__PURE__ */ jsxRuntime.jsx(
858
+ "button",
859
+ {
860
+ type: "button",
861
+ className: "rounded-md border border-ui-border-base px-4 py-2 text-sm text-ui-fg-base",
862
+ onClick: onReset,
863
+ disabled: loading,
864
+ children: "Reset"
865
+ }
866
+ ),
867
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-ui-fg-subtle", children: [
868
+ "Showing ",
869
+ disputes.length,
870
+ " dispute",
871
+ disputes.length === 1 ? "" : "s",
872
+ queryString ? " (filtered)" : ""
873
+ ] })
874
+ ] })
875
+ ] }) })
876
+ ] }),
877
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
878
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Dispute Records" }) }),
879
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-ui-border-base text-sm", children: [
880
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-left text-ui-fg-subtle", children: [
881
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Dispute" }),
882
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Status" }),
883
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Reason" }),
884
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Stage" }),
885
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Amount" }),
886
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Order" }),
887
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Cart" }),
888
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Updated" })
889
+ ] }) }),
890
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-base text-ui-fg-base", children: disputes.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-6 text-center text-ui-fg-subtle", colSpan: 8, children: loading ? "Loading disputes..." : "No disputes found." }) }) : disputes.map((dispute) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
891
+ /* @__PURE__ */ jsxRuntime.jsxs("td", { className: "px-4 py-3", children: [
892
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: dispute.dispute_id }),
893
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-ui-fg-subtle", children: dispute.transaction_id || "No transaction" })
894
+ ] }),
895
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.status || "Unknown" }),
896
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.reason || "-" }),
897
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.stage || "-" }),
898
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.amount ? `${dispute.amount} ${dispute.currency_code || ""}` : "-" }),
899
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.order_id || "-" }),
900
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.cart_id || "-" }),
901
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 text-ui-fg-subtle", children: formatDate$1(dispute.updated_at || dispute.created_at) })
902
+ ] }, dispute.id)) })
903
+ ] }) }),
904
+ error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-ui-border-base px-4 py-3 text-sm text-ui-fg-error", children: error }) : null
905
+ ] })
906
+ ] }) });
907
+ }
908
+ function PayPalGooglePayPage() {
909
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
910
+ }
911
+ const config = adminSdk.defineRouteConfig({
912
+ label: "PayPal Connection",
913
+ hide: true
914
+ });
915
+ if (typeof window !== "undefined") {
916
+ const preloadHref = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
917
+ const existingPreload = document.head.querySelector(
918
+ `link[rel="preload"][href="${preloadHref}"]`
919
+ );
920
+ if (!existingPreload) {
921
+ const preloadLink = document.createElement("link");
922
+ preloadLink.rel = "preload";
923
+ preloadLink.href = preloadHref;
924
+ preloadLink.as = "script";
925
+ document.head.appendChild(preloadLink);
926
+ }
927
+ const existingScript = document.getElementById(
928
+ "paypal-partner-js"
929
+ );
930
+ if (!existingScript) {
931
+ const ppScript = document.createElement("script");
932
+ ppScript.id = "paypal-partner-js";
933
+ ppScript.src = preloadHref;
934
+ ppScript.async = true;
935
+ document.head.appendChild(ppScript);
936
+ }
937
+ }
938
+ const SERVICE_URL = "/admin/paypal/onboarding-link";
939
+ const CACHE_KEY = "pp_onboard_cache";
940
+ const RELOAD_KEY = "pp_onboard_reloaded_once";
941
+ const CACHE_EXPIRY = 10 * 60 * 1e3;
942
+ const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
943
+ const STATUS_ENDPOINT = "/admin/paypal/status";
944
+ const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
945
+ const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
946
+ let cachedUrl = null;
947
+ if (typeof window !== "undefined") {
948
+ try {
949
+ const cached = localStorage.getItem(CACHE_KEY);
950
+ if (cached) {
951
+ const data = JSON.parse(cached);
952
+ if ((/* @__PURE__ */ new Date()).getTime() - data.ts < CACHE_EXPIRY) {
953
+ cachedUrl = data.url;
954
+ }
955
+ }
956
+ } catch (e) {
957
+ console.error("Cache read error:", e);
958
+ }
959
+ }
960
+ function PayPalConnectionPage() {
961
+ const [env, setEnv] = react.useState("sandbox");
962
+ react.useEffect(() => {
963
+ fetch("/admin/paypal/environment", { method: "GET" }).then((r) => r.json()).then((d) => {
964
+ const v = (d == null ? void 0 : d.environment) === "live" ? "live" : "sandbox";
965
+ setEnv(v);
966
+ }).catch(() => {
967
+ });
968
+ }, []);
969
+ const [connState, setConnState] = react.useState("loading");
970
+ const [error, setError] = react.useState(null);
971
+ const [finalUrl, setFinalUrl] = react.useState("");
972
+ const [showManual, setShowManual] = react.useState(false);
973
+ const [clientId, setClientId] = react.useState("");
974
+ const [secret, setSecret] = react.useState("");
975
+ const [merchantId, setMerchantId] = react.useState("");
976
+ const [statusInfo, setStatusInfo] = react.useState(null);
977
+ const [onboardingInProgress, setOnboardingInProgress] = react.useState(false);
978
+ const initLoaderRef = react.useRef(null);
979
+ const paypalButtonRef = react.useRef(null);
980
+ const errorLogRef = react.useRef(null);
981
+ const runIdRef = react.useRef(0);
982
+ const currentRunId = react.useRef(0);
983
+ const ppBtnMeasureRef = react.useRef(null);
984
+ const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
985
+ const canSaveManual = react.useMemo(() => {
986
+ return clientId.trim().length > 0 && secret.trim().length > 0;
987
+ }, [clientId, secret]);
988
+ const maskValue = react.useCallback((value, visibleChars = 4) => {
989
+ if (!value) return "";
990
+ if (value.length <= visibleChars) {
991
+ return "•".repeat(value.length);
992
+ }
993
+ return `${"•".repeat(Math.max(0, value.length - visibleChars))}${value.slice(
994
+ -visibleChars
995
+ )}`;
996
+ }, []);
997
+ const fetchFreshLink = react.useCallback(
998
+ (runId) => {
999
+ if (initLoaderRef.current) {
1000
+ const loaderText = initLoaderRef.current.querySelector("#loader-text");
1001
+ if (loaderText)
1002
+ loaderText.textContent = "Generating onboarding session...";
1003
+ }
1004
+ fetch(SERVICE_URL, {
1005
+ method: "POST",
1006
+ headers: { "content-type": "application/json" },
1007
+ body: JSON.stringify({
1008
+ products: ["PPCP"]
1009
+ })
1010
+ }).then((r) => r.json()).then((data) => {
1011
+ if (runId !== currentRunId.current) return;
1012
+ const href = data == null ? void 0 : data.onboarding_url;
1013
+ if (!href) {
1014
+ showError("Onboarding URL not returned.");
1015
+ return;
1016
+ }
1017
+ const finalUrl2 = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
1018
+ localStorage.setItem(
1019
+ CACHE_KEY,
1020
+ JSON.stringify({
1021
+ url: finalUrl2,
1022
+ ts: Date.now()
1023
+ })
1024
+ );
1025
+ if (!localStorage.getItem(RELOAD_KEY)) {
1026
+ localStorage.setItem(RELOAD_KEY, "1");
1027
+ window.location.reload();
1028
+ return;
1029
+ }
1030
+ activatePayPal(finalUrl2, runId);
1031
+ }).catch(() => {
1032
+ if (runId !== currentRunId.current) return;
1033
+ showError("Unable to connect to service.");
1034
+ });
1035
+ },
1036
+ [env]
1037
+ );
1038
+ const showUI = react.useCallback(() => {
1039
+ var _a, _b, _c, _d;
1040
+ const btn = document.querySelector('[data-paypal-button="true"]');
1041
+ if (btn && ((_d = (_c = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) == null ? void 0 : _c.miniBrowser) == null ? void 0 : _d.init)) {
1042
+ window.PAYPAL.apps.Signup.miniBrowser.init();
1043
+ }
1044
+ setConnState("ready");
1045
+ }, []);
1046
+ const showError = react.useCallback((msg) => {
1047
+ setConnState("error");
1048
+ setError(msg);
1049
+ }, []);
1050
+ const activatePayPal = react.useCallback(
1051
+ (url, runId) => {
1052
+ if (paypalButtonRef.current) {
1053
+ paypalButtonRef.current.href = url;
1054
+ }
1055
+ setFinalUrl(url);
1056
+ const tryInit = () => {
1057
+ var _a, _b;
1058
+ if (runId !== currentRunId.current) return;
1059
+ if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
1060
+ showUI();
1061
+ return;
1062
+ }
1063
+ setTimeout(tryInit, 50);
1064
+ };
1065
+ tryInit();
1066
+ },
1067
+ [showUI]
1068
+ );
1069
+ react.useEffect(() => {
1070
+ currentRunId.current = ++runIdRef.current;
1071
+ const runId = currentRunId.current;
1072
+ let cancelled = false;
1073
+ const run = async () => {
1074
+ setConnState("loading");
1075
+ setError(null);
1076
+ setFinalUrl("");
1077
+ try {
1078
+ const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
1079
+ method: "GET"
1080
+ });
1081
+ const st = await r.json().catch(() => ({}));
1082
+ if (cancelled || runId !== currentRunId.current) return;
1083
+ setStatusInfo(st);
1084
+ const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
1085
+ if (isConnected) {
1086
+ setConnState("connected");
1087
+ setShowManual(false);
1088
+ return;
1089
+ }
1090
+ } catch (e) {
1091
+ console.error(e);
1092
+ }
1093
+ if (cachedUrl) {
1094
+ console.log("Using prioritized cache...");
1095
+ activatePayPal(cachedUrl, runId);
1096
+ } else {
1097
+ fetchFreshLink(runId);
1098
+ }
1099
+ };
1100
+ run();
1101
+ return () => {
1102
+ cancelled = true;
1103
+ currentRunId.current = 0;
1104
+ };
1105
+ }, [env, fetchFreshLink, activatePayPal]);
1106
+ react.useLayoutEffect(() => {
1107
+ window.onboardingCallback = async function(authCode, sharedId) {
1108
+ var _a, _b, _c, _d, _e, _f, _g;
1109
+ try {
1110
+ ;
1111
+ window.onbeforeunload = "";
1112
+ } catch {
1113
+ }
1114
+ setOnboardingInProgress(true);
1115
+ setConnState("loading");
1116
+ setError(null);
1117
+ const payload = {
1118
+ authCode,
1119
+ sharedId,
1120
+ env: env === "sandbox" ? "sandbox" : "live"
1121
+ };
1122
+ try {
1123
+ const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
1124
+ method: "POST",
1125
+ headers: { "content-type": "application/json" },
1126
+ body: JSON.stringify(payload)
1127
+ });
1128
+ if (!res.ok) {
1129
+ const txt = await res.text().catch(() => "");
1130
+ throw new Error(txt || `Onboarding exchange failed (${res.status})`);
1131
+ }
1132
+ try {
1133
+ const close1 = (_d = (_c = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) == null ? void 0 : _c.MiniBrowser) == null ? void 0 : _d.closeFlow;
1134
+ if (typeof close1 === "function") close1();
1135
+ } catch {
1136
+ }
1137
+ try {
1138
+ const close2 = ((_g = (_f = (_e = window.PAYPAL) == null ? void 0 : _e.apps) == null ? void 0 : _f.Signup) == null ? void 0 : _g.miniBrowser) && window.PAYPAL.apps.Signup.miniBrowser.closeFlow;
1139
+ if (typeof close2 === "function") close2();
1140
+ } catch {
1141
+ }
1142
+ try {
1143
+ localStorage.removeItem(CACHE_KEY);
1144
+ localStorage.removeItem(RELOAD_KEY);
1145
+ } catch {
1146
+ }
1147
+ window.location.href = window.location.href;
1148
+ } catch (e) {
1149
+ console.error(e);
1150
+ setConnState("error");
1151
+ setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
1152
+ setOnboardingInProgress(false);
1153
+ }
1154
+ };
1155
+ return () => {
1156
+ window.onboardingCallback = void 0;
1157
+ };
1158
+ }, [env]);
1159
+ react.useLayoutEffect(() => {
1160
+ const el = ppBtnMeasureRef.current;
1161
+ if (!el) return;
1162
+ const update = () => {
1163
+ const w = Math.round(el.getBoundingClientRect().width || 0);
1164
+ if (w > 0) setPpBtnWidth(w);
1165
+ };
1166
+ update();
1167
+ let ro = null;
1168
+ if (typeof ResizeObserver !== "undefined") {
1169
+ ro = new ResizeObserver(() => update());
1170
+ ro.observe(el);
1171
+ } else {
1172
+ window.addEventListener("resize", update);
1173
+ }
1174
+ return () => {
1175
+ if (ro) ro.disconnect();
1176
+ else window.removeEventListener("resize", update);
1177
+ };
1178
+ }, [connState, env, finalUrl]);
1179
+ const handleConnectClick = (e) => {
1180
+ if (connState !== "ready" || !finalUrl || onboardingInProgress) {
1181
+ e.preventDefault();
1182
+ }
1183
+ };
1184
+ const handleSaveManual = async () => {
1185
+ if (!canSaveManual || onboardingInProgress) return;
1186
+ setOnboardingInProgress(true);
1187
+ setConnState("loading");
1188
+ setError(null);
1189
+ try {
1190
+ const res = await fetch(SAVE_CREDENTIALS_ENDPOINT, {
1191
+ method: "POST",
1192
+ headers: { "content-type": "application/json" },
1193
+ body: JSON.stringify({
1194
+ clientId: clientId.trim(),
1195
+ clientSecret: secret.trim()
1196
+ })
1197
+ });
1198
+ if (!res.ok) {
1199
+ const txt = await res.text().catch(() => "");
1200
+ throw new Error(txt || `Save credentials failed (${res.status})`);
1201
+ }
1202
+ setConnState("connected");
1203
+ setStatusInfo({
1204
+ seller_client_id_masked: maskValue(clientId.trim()),
1205
+ seller_client_secret_masked: "••••••••"
1206
+ });
1207
+ setShowManual(false);
1208
+ try {
1209
+ localStorage.removeItem(CACHE_KEY);
1210
+ localStorage.removeItem(RELOAD_KEY);
1211
+ } catch {
1212
+ }
1213
+ } catch (e) {
1214
+ console.error(e);
1215
+ setConnState("error");
1216
+ setError((e == null ? void 0 : e.message) || "Failed to save credentials.");
1217
+ } finally {
1218
+ setOnboardingInProgress(false);
1219
+ }
1220
+ };
1221
+ const handleDisconnect = async () => {
1222
+ if (onboardingInProgress) return;
1223
+ if (!window.confirm("Disconnect PayPal for this environment?")) return;
1224
+ setOnboardingInProgress(true);
1225
+ setConnState("loading");
1226
+ setError(null);
1227
+ setFinalUrl("");
1228
+ setShowManual(false);
1229
+ try {
1230
+ const res = await fetch(DISCONNECT_ENDPOINT, {
1231
+ method: "POST",
1232
+ headers: { "content-type": "application/json" },
1233
+ body: JSON.stringify({ environment: env })
1234
+ });
1235
+ if (!res.ok) {
1236
+ const t = await res.text().catch(() => "");
1237
+ throw new Error(t || `Disconnect failed (${res.status})`);
1238
+ }
1239
+ try {
1240
+ localStorage.removeItem(CACHE_KEY);
1241
+ localStorage.removeItem(RELOAD_KEY);
1242
+ } catch {
1243
+ }
1244
+ currentRunId.current = ++runIdRef.current;
1245
+ const runId = currentRunId.current;
1246
+ fetchFreshLink(runId);
1247
+ } catch (e) {
1248
+ console.error(e);
1249
+ setConnState("error");
1250
+ setError((e == null ? void 0 : e.message) || "Failed to disconnect.");
1251
+ } finally {
1252
+ setOnboardingInProgress(false);
1253
+ }
1254
+ };
1255
+ const handleEnvChange = async (e) => {
1256
+ const next = e.target.value;
1257
+ setEnv(next);
1258
+ cachedUrl = null;
1259
+ try {
1260
+ await fetch("/admin/paypal/environment", {
1261
+ method: "POST",
1262
+ headers: { "content-type": "application/json" },
1263
+ body: JSON.stringify({ environment: next })
1264
+ });
1265
+ } catch {
1266
+ }
1267
+ try {
1268
+ localStorage.removeItem(CACHE_KEY);
1269
+ localStorage.removeItem(RELOAD_KEY);
1270
+ } catch {
1271
+ }
1272
+ };
1273
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
1274
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
1275
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold", children: "PayPal Gateway By Easy Payment" }),
1276
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
1277
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-ui-border-base p-4 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-y-6 md:grid-cols-[260px_1fr] md:items-start", children: [
1278
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: "Environment" }),
1279
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsxRuntime.jsxs(
1280
+ "select",
1281
+ {
1282
+ value: env,
1283
+ onChange: handleEnvChange,
1284
+ disabled: onboardingInProgress,
1285
+ className: "w-full rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm",
1286
+ children: [
1287
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "sandbox", children: "Sandbox (Test Mode)" }),
1288
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "live", children: "Live (Production)" })
1289
+ ]
1290
+ }
1291
+ ) }),
1292
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal Sandbox" : "Connect to PayPal Live" }),
1293
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1294
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
1295
+ "✅ Successfully connected to PayPal!",
1296
+ /* @__PURE__ */ jsxRuntime.jsx(
1297
+ "a",
1298
+ {
1299
+ "data-paypal-button": "true",
1300
+ "data-paypal-onboard-complete": "onboardingCallback",
1301
+ href: "#",
1302
+ style: { display: "none" },
1303
+ children: "PayPal"
1304
+ }
1305
+ )
1306
+ ] }),
1307
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded-md border border-ui-border-base bg-ui-bg-subtle p-3 text-xs text-ui-fg-subtle", children: [
1308
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
1309
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1", children: [
1310
+ "Email:",
1311
+ " ",
1312
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-ui-fg-base", children: (statusInfo == null ? void 0 : statusInfo.seller_email) || "Unavailable" })
1313
+ ] })
1314
+ ] }),
1315
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
1316
+ "button",
1317
+ {
1318
+ type: "button",
1319
+ onClick: handleDisconnect,
1320
+ disabled: onboardingInProgress,
1321
+ className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
1322
+ children: "Disconnect"
1323
+ }
1324
+ ) })
1325
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1326
+ /* @__PURE__ */ jsxRuntime.jsxs(
1327
+ "div",
1328
+ {
1329
+ ref: initLoaderRef,
1330
+ id: "init-loader",
1331
+ className: `status-msg mb-4 ${connState !== "loading" ? "hidden" : "block"}`,
1332
+ children: [
1333
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "loader inline-block align-middle mr-2" }),
1334
+ /* @__PURE__ */ jsxRuntime.jsx("span", { id: "loader-text", className: "text-sm", children: onboardingInProgress ? "Configuring connection to PayPal…" : "Checking connection..." })
1335
+ ]
1336
+ }
1337
+ ),
1338
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${connState === "ready" ? "block" : "hidden"}`, children: [
1339
+ /* @__PURE__ */ jsxRuntime.jsx(
1340
+ "a",
1341
+ {
1342
+ ref: (node) => {
1343
+ paypalButtonRef.current = node;
1344
+ ppBtnMeasureRef.current = node;
1345
+ },
1346
+ id: "paypal-button",
1347
+ "data-paypal-button": "true",
1348
+ href: finalUrl || "#",
1349
+ "data-paypal-onboard-complete": "onboardingCallback",
1350
+ onClick: handleConnectClick,
1351
+ className: "btn-paypal",
1352
+ style: {
1353
+ borderRadius: "50px",
1354
+ textDecoration: "none",
1355
+ display: "inline-block",
1356
+ fontWeight: "bold",
1357
+ border: "none",
1358
+ cursor: onboardingInProgress ? "not-allowed" : "pointer",
1359
+ opacity: onboardingInProgress ? 0.6 : 1,
1360
+ pointerEvents: onboardingInProgress ? "none" : "auto"
1361
+ },
1362
+ children: "Connect to PayPal"
1363
+ }
1364
+ ),
1365
+ /* @__PURE__ */ jsxRuntime.jsx(
1366
+ "div",
1367
+ {
1368
+ className: "mt-2",
1369
+ style: {
1370
+ width: ppBtnWidth ? `${ppBtnWidth}px` : "auto",
1371
+ marginTop: "20px",
1372
+ marginBottom: "10px"
1373
+ },
1374
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-ui-fg-muted leading-none", children: "OR" }) })
1375
+ }
1376
+ ),
1377
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntime.jsx(
1378
+ "button",
1379
+ {
1380
+ type: "button",
1381
+ onClick: () => setShowManual(!showManual),
1382
+ disabled: onboardingInProgress,
1383
+ className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
1384
+ children: "Click here to insert credentials manually"
1385
+ }
1386
+ ) })
1387
+ ] }),
1388
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${connState === "ready" ? "hidden" : "block"} mt-3`, children: /* @__PURE__ */ jsxRuntime.jsx(
1389
+ "button",
1390
+ {
1391
+ type: "button",
1392
+ onClick: () => setShowManual(!showManual),
1393
+ disabled: onboardingInProgress,
1394
+ className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
1395
+ children: "Click here to insert credentials manually"
1396
+ }
1397
+ ) }),
1398
+ /* @__PURE__ */ jsxRuntime.jsx(
1399
+ "div",
1400
+ {
1401
+ ref: errorLogRef,
1402
+ id: "error-log",
1403
+ className: `mt-4 text-left text-xs bg-red-50 text-red-600 p-3 border border-red-200 rounded ${connState === "error" && error ? "block" : "hidden"}`,
1404
+ children: error
1405
+ }
1406
+ )
1407
+ ] }) }),
1408
+ showManual && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:col-span-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-[260px] max-w-xl mt-4 grid grid-cols-1 gap-3 md:grid-cols-2", children: [
1409
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
1410
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client ID" }),
1411
+ /* @__PURE__ */ jsxRuntime.jsx(
1412
+ "input",
1413
+ {
1414
+ type: "text",
1415
+ value: clientId,
1416
+ onChange: (e) => setClientId(e.target.value),
1417
+ disabled: onboardingInProgress,
1418
+ className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
1419
+ placeholder: env === "sandbox" ? "Sandbox Client ID" : "Live Client ID"
1420
+ }
1421
+ )
1422
+ ] }),
1423
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
1424
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client Secret" }),
1425
+ /* @__PURE__ */ jsxRuntime.jsx(
1426
+ "input",
1427
+ {
1428
+ type: "password",
1429
+ value: secret,
1430
+ onChange: (e) => setSecret(e.target.value),
1431
+ disabled: onboardingInProgress,
1432
+ className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
1433
+ placeholder: env === "sandbox" ? "Sandbox Secret" : "Live Secret"
1434
+ }
1435
+ )
1436
+ ] }),
1437
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:col-span-2", children: [
1438
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Merchant ID (optional)" }),
1439
+ /* @__PURE__ */ jsxRuntime.jsx(
1440
+ "input",
1441
+ {
1442
+ type: "text",
1443
+ value: merchantId,
1444
+ onChange: (e) => setMerchantId(e.target.value),
1445
+ disabled: onboardingInProgress,
1446
+ className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
1447
+ placeholder: "Merchant ID"
1448
+ }
1449
+ )
1450
+ ] }),
1451
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
1452
+ /* @__PURE__ */ jsxRuntime.jsx(
1453
+ "button",
1454
+ {
1455
+ type: "button",
1456
+ className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
1457
+ onClick: () => setShowManual(false),
1458
+ disabled: onboardingInProgress,
1459
+ children: "Cancel"
1460
+ }
1461
+ ),
1462
+ /* @__PURE__ */ jsxRuntime.jsx(
1463
+ "button",
1464
+ {
1465
+ type: "button",
1466
+ className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium bg-ui-bg-base hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
1467
+ disabled: !canSaveManual || onboardingInProgress,
1468
+ onClick: handleSaveManual,
1469
+ children: "Save credentials"
1470
+ }
1471
+ )
1472
+ ] })
1473
+ ] }) })
1474
+ ] }) })
1475
+ ] }),
1476
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
1477
+ .loader {
1478
+ border: 3px solid #f3f3f3;
1479
+ border-top: 3px solid #0070ba;
1480
+ border-radius: 50%;
1481
+ width: 18px;
1482
+ height: 18px;
1483
+ animation: spin 1s linear infinite;
1484
+ display: inline-block;
1485
+ vertical-align: middle;
1486
+ margin-right: 8px;
1487
+ }
1488
+ @keyframes spin {
1489
+ 0% { transform: rotate(0deg); }
1490
+ 100% { transform: rotate(360deg); }
1491
+ }
1492
+ ` })
1493
+ ] });
1494
+ }
1495
+ function PayPalPayLaterMessagingPage() {
1496
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1497
+ }
1498
+ const DISPLAY_LOCATION_OPTIONS = [
1499
+ { value: "product", label: "Product Page" },
1500
+ { value: "cart", label: "Cart Page" },
1501
+ { value: "express", label: "Express Checkout" },
1502
+ { value: "checkout", label: "Checkout Page", disabled: true, hint: "Locked by PayPal eligibility / checkout config" },
1503
+ { value: "mini_cart", label: "Mini Cart (Side Cart)" }
1504
+ ];
1505
+ const DISABLE_BUTTON_OPTIONS = [
1506
+ { value: "paypal", label: "PayPal" },
1507
+ { value: "paylater", label: "Pay Later" },
1508
+ { value: "card", label: "Debit / Credit Card" },
1509
+ { value: "venmo", label: "Venmo" },
1510
+ { value: "applepay", label: "Apple Pay" },
1511
+ { value: "googlepay", label: "Google Pay" }
1512
+ ];
1513
+ const HIDDEN_DISABLE_BUTTONS = /* @__PURE__ */ new Set(["applepay", "googlepay", "paylater"]);
1514
+ const VISIBLE_DISABLE_BUTTON_OPTIONS = DISABLE_BUTTON_OPTIONS.filter(
1515
+ (option) => !HIDDEN_DISABLE_BUTTONS.has(option.value)
1516
+ );
1517
+ function filterHiddenDisableButtons(list = []) {
1518
+ return list.filter((value) => !HIDDEN_DISABLE_BUTTONS.has(value));
1519
+ }
1520
+ const COLOR_OPTIONS = [
1521
+ { value: "gold", label: "Gold (Recommended)" },
1522
+ { value: "blue", label: "Blue" },
1523
+ { value: "silver", label: "Silver" },
1524
+ { value: "black", label: "Black" },
1525
+ { value: "white", label: "White" }
1526
+ ];
1527
+ const SHAPE_OPTIONS = [
1528
+ { value: "rect", label: "Rect (Recommended)" },
1529
+ { value: "pill", label: "Pill" }
1530
+ ];
1531
+ const WIDTH_OPTIONS = [
1532
+ { value: "small", label: "Small" },
1533
+ { value: "medium", label: "Medium" },
1534
+ { value: "large", label: "Large" },
1535
+ { value: "responsive", label: "Responsive" }
1536
+ ];
1537
+ const HEIGHT_OPTIONS = [32, 36, 40, 44, 48, 52, 56];
1538
+ const LABEL_OPTIONS = [
1539
+ { value: "paypal", label: "PayPal (Recommended)" },
1540
+ { value: "checkout", label: "Checkout" },
1541
+ { value: "buynow", label: "Buy Now" },
1542
+ { value: "pay", label: "Pay" }
1543
+ ];
1544
+ function cx(...parts) {
1545
+ return parts.filter(Boolean).join(" ");
1546
+ }
1547
+ function Pill({
1548
+ children,
1549
+ onRemove,
1550
+ disabled
1551
+ }) {
1552
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1553
+ "span",
1554
+ {
1555
+ className: cx(
1556
+ "inline-flex items-center gap-1 rounded-md border px-2 py-1 text-sm",
1557
+ disabled ? "opacity-60" : "opacity-100"
1558
+ ),
1559
+ children: [
1560
+ children,
1561
+ onRemove ? /* @__PURE__ */ jsxRuntime.jsx(
1562
+ "button",
1563
+ {
1564
+ type: "button",
1565
+ onClick: onRemove,
1566
+ className: "ml-1 rounded px-1 text-ui-fg-subtle hover:text-ui-fg-base",
1567
+ "aria-label": "Remove",
1568
+ children: "×"
1569
+ }
1570
+ ) : null
1571
+ ]
1572
+ }
1573
+ );
1574
+ }
1575
+ function SectionCard({
1576
+ title,
1577
+ description,
1578
+ children,
1579
+ right
1580
+ }) {
1581
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
1582
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
1583
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1584
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
1585
+ description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
1586
+ ] }),
1587
+ right
1588
+ ] }),
1589
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
1590
+ ] });
1591
+ }
1592
+ function FieldRow({
1593
+ label,
1594
+ hint,
1595
+ children
1596
+ }) {
1597
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
1598
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
1599
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
1600
+ hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
1601
+ ] }),
1602
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
1603
+ ] });
1604
+ }
1605
+ function PayPalSettingsTab() {
1606
+ const [form, setForm] = react.useState({
1607
+ enabled: true,
1608
+ title: "PayPal",
1609
+ description: "Pay via PayPal; you can pay with your credit card if you don’t have a PayPal account",
1610
+ displayOn: ["product", "cart", "express", "mini_cart"],
1611
+ disableButtons: [],
1612
+ buttonColor: "gold",
1613
+ buttonShape: "rect",
1614
+ buttonWidth: "medium",
1615
+ buttonHeight: 48,
1616
+ buttonLabel: "paypal"
1617
+ });
1618
+ const [loading, setLoading] = react.useState(false);
1619
+ const [saving, setSaving] = react.useState(false);
1620
+ const [toast, setToast] = react.useState(null);
1621
+ const didInit = react.useRef(false);
1622
+ react.useEffect(() => {
1623
+ if (didInit.current) return;
1624
+ didInit.current = true;
1625
+ (async () => {
1626
+ try {
1627
+ setLoading(true);
1628
+ const r = await fetch("/admin/paypal/settings", {
1629
+ credentials: "include",
1630
+ headers: { Accept: "application/json" }
1631
+ });
1632
+ if (!r.ok) return;
1633
+ const json = await r.json();
1634
+ const payload = (json == null ? void 0 : json.data) ?? json;
1635
+ const saved = payload == null ? void 0 : payload.paypal_settings;
1636
+ if (saved && typeof saved === "object") {
1637
+ setForm((prev) => ({
1638
+ ...prev,
1639
+ ...saved,
1640
+ disableButtons: filterHiddenDisableButtons(saved.disableButtons)
1641
+ }));
1642
+ }
1643
+ } finally {
1644
+ setLoading(false);
1645
+ }
1646
+ })();
1647
+ }, []);
1648
+ async function onSave() {
1649
+ try {
1650
+ setSaving(true);
1651
+ const cleaned = {
1652
+ ...form,
1653
+ disableButtons: filterHiddenDisableButtons(form.disableButtons)
1654
+ };
1655
+ const r = await fetch("/admin/paypal/settings", {
1656
+ method: "POST",
1657
+ credentials: "include",
1658
+ headers: {
1659
+ "Content-Type": "application/json",
1660
+ Accept: "application/json"
1661
+ },
1662
+ body: JSON.stringify({ paypal_settings: cleaned })
1663
+ });
1664
+ if (!r.ok) {
1665
+ const t = await r.text();
1666
+ setToast({ type: "error", message: "Failed to save settings. " + t });
1667
+ window.setTimeout(() => setToast(null), 3500);
1668
+ return;
1669
+ }
1670
+ const json = await r.json().catch(() => null);
1671
+ const payload = (json == null ? void 0 : json.data) ?? json;
1672
+ const saved = payload == null ? void 0 : payload.paypal_settings;
1673
+ if (saved && typeof saved === "object") {
1674
+ setForm((prev) => ({
1675
+ ...prev,
1676
+ ...saved,
1677
+ disableButtons: filterHiddenDisableButtons(saved.disableButtons)
1678
+ }));
1679
+ }
1680
+ setToast({ type: "success", message: "Settings saved" });
1681
+ window.setTimeout(() => setToast(null), 2500);
1682
+ } finally {
1683
+ setSaving(false);
1684
+ }
1685
+ }
1686
+ react.useMemo(() => new Map(DISPLAY_LOCATION_OPTIONS.map((o) => [o.value, o])), []);
1687
+ function toggleMulti(key, value) {
1688
+ setForm((prev) => {
1689
+ const list = prev[key] || [];
1690
+ const exists = list.includes(value);
1691
+ const next = exists ? list.filter((v) => v !== value) : [...list, value];
1692
+ return { ...prev, [key]: next };
1693
+ });
1694
+ }
1695
+ function removeMulti(key, value) {
1696
+ setForm((prev) => {
1697
+ const list = prev[key] || [];
1698
+ return { ...prev, [key]: list.filter((v) => v !== value) };
1699
+ });
1700
+ }
1701
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
1702
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
1703
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Gateway By Easy Payment" }) }),
1704
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2" })
1705
+ ] }),
1706
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
1707
+ toast ? /* @__PURE__ */ jsxRuntime.jsx(
1708
+ "div",
1709
+ {
1710
+ className: "fixed right-6 top-6 z-50 rounded-md border border-ui-border-base bg-ui-bg-base px-4 py-3 text-sm shadow-lg",
1711
+ role: "status",
1712
+ "aria-live": "polite",
1713
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message })
1714
+ }
1715
+ ) : null,
1716
+ /* @__PURE__ */ jsxRuntime.jsx(
1717
+ SectionCard,
1718
+ {
1719
+ title: "PayPal Settings",
1720
+ description: "Enable PayPal, set title/description, and choose where Smart Buttons appear.",
1721
+ right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1722
+ /* @__PURE__ */ jsxRuntime.jsx(
1723
+ "button",
1724
+ {
1725
+ type: "button",
1726
+ onClick: onSave,
1727
+ disabled: saving || loading,
1728
+ className: "rounded-md bg-ui-button-neutral px-4 py-2 text-sm font-medium text-ui-fg-on-color shadow-sm hover:opacity-90 disabled:opacity-60",
1729
+ children: saving ? "Saving..." : "Save settings"
1730
+ }
1731
+ ),
1732
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
1733
+ ] }),
1734
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
1735
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Enable/Disable", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
1736
+ /* @__PURE__ */ jsxRuntime.jsx(
1737
+ "input",
1738
+ {
1739
+ type: "checkbox",
1740
+ checked: form.enabled,
1741
+ onChange: (e) => setForm((p) => ({ ...p, enabled: e.target.checked })),
1742
+ className: "h-4 w-4 rounded border-ui-border-base"
1743
+ }
1744
+ ),
1745
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable PayPal" })
1746
+ ] }) }),
1747
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Title", children: /* @__PURE__ */ jsxRuntime.jsx(
1748
+ "input",
1749
+ {
1750
+ value: form.title,
1751
+ onChange: (e) => setForm((p) => ({ ...p, title: e.target.value })),
1752
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
1753
+ placeholder: "PayPal"
1754
+ }
1755
+ ) }),
1756
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Description", children: /* @__PURE__ */ jsxRuntime.jsx(
1757
+ "textarea",
1758
+ {
1759
+ value: form.description,
1760
+ onChange: (e) => setForm((p) => ({ ...p, description: e.target.value })),
1761
+ className: "min-h-[84px] w-full resize-y rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
1762
+ placeholder: "Pay via PayPal..."
1763
+ }
1764
+ ) }),
1765
+ /* @__PURE__ */ jsxRuntime.jsx(
1766
+ FieldRow,
1767
+ {
1768
+ label: "Display PayPal Buttons On",
1769
+ hint: "Choose where PayPal Smart Buttons should render.",
1770
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
1771
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
1772
+ DISPLAY_LOCATION_OPTIONS.filter((o) => form.displayOn.includes(o.value)).map((o) => /* @__PURE__ */ jsxRuntime.jsxs(
1773
+ Pill,
1774
+ {
1775
+ disabled: o.disabled,
1776
+ onRemove: o.disabled ? void 0 : () => removeMulti("displayOn", o.value),
1777
+ children: [
1778
+ o.label,
1779
+ o.disabled ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 rounded bg-ui-bg-subtle px-1 py-[1px] text-[10px] text-ui-fg-subtle", children: "Locked" }) : null
1780
+ ]
1781
+ },
1782
+ o.value
1783
+ )),
1784
+ form.displayOn.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No locations selected." }) : null
1785
+ ] }),
1786
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-ui-border-base p-3", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-2 md:grid-cols-2", children: DISPLAY_LOCATION_OPTIONS.map((o) => {
1787
+ const checked = form.displayOn.includes(o.value);
1788
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1789
+ "label",
1790
+ {
1791
+ className: cx(
1792
+ "flex items-start gap-2 rounded-md p-2",
1793
+ o.disabled ? "opacity-60" : "hover:bg-ui-bg-subtle"
1794
+ ),
1795
+ children: [
1796
+ /* @__PURE__ */ jsxRuntime.jsx(
1797
+ "input",
1798
+ {
1799
+ type: "checkbox",
1800
+ disabled: o.disabled,
1801
+ checked,
1802
+ onChange: () => toggleMulti("displayOn", o.value),
1803
+ className: "mt-0.5 h-4 w-4 rounded border-ui-border-base"
1804
+ }
1805
+ ),
1806
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col", children: [
1807
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: o.label }),
1808
+ o.hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-ui-fg-subtle", children: o.hint }) : null
1809
+ ] })
1810
+ ]
1811
+ },
1812
+ o.value
1813
+ );
1814
+ }) }) })
1815
+ ] })
1816
+ }
1817
+ )
1818
+ ] })
1819
+ }
1820
+ ),
1821
+ /* @__PURE__ */ jsxRuntime.jsxs(
1822
+ SectionCard,
1823
+ {
1824
+ title: "Button Appearance",
1825
+ description: "Control PayPal Smart Button styling (color/shape/size/label) and optionally disable specific buttons.",
1826
+ children: [
1827
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
1828
+ /* @__PURE__ */ jsxRuntime.jsx(
1829
+ FieldRow,
1830
+ {
1831
+ label: "Disable Specific Payment Buttons",
1832
+ hint: "Hide individual funding sources (ex: Card, Venmo).",
1833
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
1834
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
1835
+ filterHiddenDisableButtons(form.disableButtons).map((v) => {
1836
+ const opt = VISIBLE_DISABLE_BUTTON_OPTIONS.find((o) => o.value === v);
1837
+ return /* @__PURE__ */ jsxRuntime.jsx(Pill, { onRemove: () => removeMulti("disableButtons", v), children: (opt == null ? void 0 : opt.label) ?? v }, v);
1838
+ }),
1839
+ filterHiddenDisableButtons(form.disableButtons).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No buttons disabled." }) : null
1840
+ ] }),
1841
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-ui-border-base p-3", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-2 md:grid-cols-2", children: VISIBLE_DISABLE_BUTTON_OPTIONS.map((o) => {
1842
+ const checked = form.disableButtons.includes(o.value);
1843
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 rounded-md p-2 hover:bg-ui-bg-subtle", children: [
1844
+ /* @__PURE__ */ jsxRuntime.jsx(
1845
+ "input",
1846
+ {
1847
+ type: "checkbox",
1848
+ checked,
1849
+ onChange: () => toggleMulti("disableButtons", o.value),
1850
+ className: "h-4 w-4 rounded border-ui-border-base"
1851
+ }
1852
+ ),
1853
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: o.label })
1854
+ ] }, o.value);
1855
+ }) }) })
1856
+ ] })
1857
+ }
1858
+ ),
1859
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Color", children: /* @__PURE__ */ jsxRuntime.jsx(
1860
+ "select",
1861
+ {
1862
+ value: form.buttonColor,
1863
+ onChange: (e) => setForm((p) => ({ ...p, buttonColor: e.target.value })),
1864
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
1865
+ children: COLOR_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1866
+ }
1867
+ ) }),
1868
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Shape", children: /* @__PURE__ */ jsxRuntime.jsx(
1869
+ "select",
1870
+ {
1871
+ value: form.buttonShape,
1872
+ onChange: (e) => setForm((p) => ({ ...p, buttonShape: e.target.value })),
1873
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
1874
+ children: SHAPE_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1875
+ }
1876
+ ) }),
1877
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Width", children: /* @__PURE__ */ jsxRuntime.jsx(
1878
+ "select",
1879
+ {
1880
+ value: form.buttonWidth,
1881
+ onChange: (e) => setForm((p) => ({ ...p, buttonWidth: e.target.value })),
1882
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
1883
+ children: WIDTH_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1884
+ }
1885
+ ) }),
1886
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Height", children: /* @__PURE__ */ jsxRuntime.jsx(
1887
+ "select",
1888
+ {
1889
+ value: String(form.buttonHeight),
1890
+ onChange: (e) => setForm((p) => ({ ...p, buttonHeight: Number(e.target.value) })),
1891
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
1892
+ children: HEIGHT_OPTIONS.map((h) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: h, children: [
1893
+ h,
1894
+ " px"
1895
+ ] }, h))
1896
+ }
1897
+ ) }),
1898
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Label", children: /* @__PURE__ */ jsxRuntime.jsx(
1899
+ "select",
1900
+ {
1901
+ value: form.buttonLabel,
1902
+ onChange: (e) => setForm((p) => ({ ...p, buttonLabel: e.target.value })),
1903
+ className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
1904
+ children: LABEL_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1905
+ }
1906
+ ) })
1907
+ ] }),
1908
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 rounded-md border border-ui-border-base bg-ui-bg-subtle p-4", children: [
1909
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: "Preview (UI only)" }),
1910
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 text-sm text-ui-fg-subtle", children: [
1911
+ "Color: ",
1912
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonColor }),
1913
+ " · Shape:",
1914
+ " ",
1915
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonShape }),
1916
+ " · Width:",
1917
+ " ",
1918
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonWidth }),
1919
+ " · Height:",
1920
+ " ",
1921
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-base", children: [
1922
+ form.buttonHeight,
1923
+ "px"
1924
+ ] }),
1925
+ " · Label:",
1926
+ " ",
1927
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonLabel })
1928
+ ] })
1929
+ ] })
1930
+ ]
1931
+ }
1932
+ )
1933
+ ] }) });
1934
+ }
1935
+ function formatDate(value) {
1936
+ if (!value) {
1937
+ return "—";
1938
+ }
1939
+ const parsed = new Date(value);
1940
+ if (Number.isNaN(parsed.getTime())) {
1941
+ return value;
1942
+ }
1943
+ return parsed.toLocaleString();
1944
+ }
1945
+ function PayPalReconciliationStatusPage() {
1946
+ const [status, setStatus] = react.useState({});
1947
+ const [loading, setLoading] = react.useState(false);
1948
+ const [error, setError] = react.useState(null);
1949
+ const fetchStatus = react.useCallback(async () => {
1950
+ try {
1951
+ setLoading(true);
1952
+ setError(null);
1953
+ const response = await fetch("/admin/paypal/reconciliation-status", {
1954
+ credentials: "include",
1955
+ headers: {
1956
+ Accept: "application/json"
1957
+ }
1958
+ });
1959
+ if (!response.ok) {
1960
+ const message = await response.text().catch(() => "");
1961
+ throw new Error(message || "Failed to load reconciliation status.");
1962
+ }
1963
+ const data = await response.json().catch(() => ({}));
1964
+ setStatus((data == null ? void 0 : data.status) || {});
1965
+ } catch (fetchError) {
1966
+ setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load reconciliation status.");
1967
+ setStatus({});
1968
+ } finally {
1969
+ setLoading(false);
1970
+ }
1971
+ }, []);
1972
+ react.useEffect(() => {
1973
+ fetchStatus();
1974
+ }, [fetchStatus]);
1975
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
1976
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1977
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Reconciliation Status" }),
1978
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Monitor reconciliation health and drift detection for PayPal payment sessions." })
1979
+ ] }),
1980
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
1981
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
1982
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
1983
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Latest reconciliation run" }),
1984
+ /* @__PURE__ */ jsxRuntime.jsx(
1985
+ "button",
1986
+ {
1987
+ type: "button",
1988
+ onClick: fetchStatus,
1989
+ className: "rounded-md border border-ui-border-base px-3 py-2 text-sm text-ui-fg-base",
1990
+ disabled: loading,
1991
+ children: loading ? "Refreshing..." : "Refresh"
1992
+ }
1993
+ )
1994
+ ] }) }),
1995
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
1996
+ error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-600", children: error }) : null,
1997
+ !error && Object.keys(status).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-ui-fg-subtle", children: loading ? "Loading reconciliation status..." : "No reconciliation data yet." }) : null,
1998
+ Object.keys(status).length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 text-sm text-ui-fg-base md:grid-cols-2", children: [
1999
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2000
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last run" }),
2001
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_run_at) })
2002
+ ] }),
2003
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2004
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last run status" }),
2005
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium capitalize", children: status.last_run_status || "—" })
2006
+ ] }),
2007
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2008
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last success" }),
2009
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_success_at) })
2010
+ ] }),
2011
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2012
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last failure" }),
2013
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_failure_at) })
2014
+ ] }),
2015
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2016
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Sessions checked" }),
2017
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.sessions_checked ?? 0 })
2018
+ ] }),
2019
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2020
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Sessions updated" }),
2021
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.sessions_updated ?? 0 })
2022
+ ] }),
2023
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2024
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Drift detections" }),
2025
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.drift_count ?? 0 })
2026
+ ] }),
2027
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2028
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last drift order" }),
2029
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.last_drift_order_id || "—" }),
2030
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: formatDate(status.last_drift_at) })
2031
+ ] }),
2032
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 md:col-span-2", children: [
2033
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last error" }),
2034
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.last_error || "No errors recorded." })
2035
+ ] }),
2036
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 md:col-span-2", children: [
2037
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Total runs" }),
2038
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.runs ?? 0 })
2039
+ ] })
2040
+ ] }) : null
2041
+ ] })
2042
+ ] })
2043
+ ] }) });
2044
+ }
2045
+ const widgetModule = { widgets: [] };
2046
+ const routeModule = {
2047
+ routes: [
2048
+ {
2049
+ Component: PayPalSettingsIndexRoute,
2050
+ path: "/settings/paypal"
2051
+ },
2052
+ {
2053
+ Component: AdditionalSettingsTab,
2054
+ path: "/settings/paypal/additional-settings"
2055
+ },
2056
+ {
2057
+ Component: PayPalApplePayPage,
2058
+ path: "/settings/paypal/apple-pay"
2059
+ },
2060
+ {
2061
+ Component: AdvancedCardPaymentsTab,
2062
+ path: "/settings/paypal/advanced-card-payments"
2063
+ },
2064
+ {
2065
+ Component: PayPalAuditLogsPage,
2066
+ path: "/settings/paypal/audit-logs"
2067
+ },
2068
+ {
2069
+ Component: PayPalDisputesPage,
2070
+ path: "/settings/paypal/disputes"
2071
+ },
2072
+ {
2073
+ Component: PayPalGooglePayPage,
2074
+ path: "/settings/paypal/google-pay"
2075
+ },
2076
+ {
2077
+ Component: PayPalConnectionPage,
2078
+ path: "/settings/paypal/connection"
2079
+ },
2080
+ {
2081
+ Component: PayPalPayLaterMessagingPage,
2082
+ path: "/settings/paypal/pay-later-messaging"
2083
+ },
2084
+ {
2085
+ Component: PayPalSettingsTab,
2086
+ path: "/settings/paypal/paypal-settings"
2087
+ },
2088
+ {
2089
+ Component: PayPalReconciliationStatusPage,
2090
+ path: "/settings/paypal/reconciliation-status"
2091
+ }
2092
+ ]
2093
+ };
2094
+ const menuItemModule = {
2095
+ menuItems: [
2096
+ {
2097
+ label: config$1.label,
2098
+ icon: config$1.icon,
2099
+ path: "/settings/paypal",
2100
+ nested: void 0,
2101
+ rank: void 0,
2102
+ translationNs: void 0
2103
+ },
2104
+ {
2105
+ label: config.label,
2106
+ icon: void 0,
2107
+ path: "/settings/paypal/connection",
2108
+ nested: void 0,
2109
+ rank: void 0,
2110
+ translationNs: void 0
2111
+ }
2112
+ ]
2113
+ };
2114
+ const formModule = { customFields: {} };
2115
+ const displayModule = {
2116
+ displays: {}
2117
+ };
2118
+ const i18nModule = { resources: {} };
2119
+ const plugin = {
2120
+ widgetModule,
2121
+ routeModule,
2122
+ menuItemModule,
2123
+ formModule,
2124
+ displayModule,
2125
+ i18nModule
2126
+ };
2127
+ module.exports = plugin;