@oxyhq/services 5.5.9 → 5.6.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 (393) hide show
  1. package/README.md +16 -2
  2. package/lib/commonjs/core/index.js +69 -82
  3. package/lib/commonjs/core/index.js.map +1 -1
  4. package/lib/commonjs/index.js +24 -183
  5. package/lib/commonjs/index.js.map +1 -1
  6. package/lib/commonjs/node/index.js +0 -2
  7. package/lib/commonjs/node/index.js.map +1 -1
  8. package/lib/commonjs/ui/components/FollowButton.js +100 -229
  9. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  10. package/lib/commonjs/ui/components/OxyPayButton.js +131 -0
  11. package/lib/commonjs/ui/components/OxyPayButton.js.map +1 -0
  12. package/lib/commonjs/ui/components/OxyProvider.js +41 -198
  13. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  14. package/lib/commonjs/ui/components/OxySignInButton.js +15 -2
  15. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  16. package/lib/commonjs/ui/components/icon/FAIRWalletIcon.js +66 -0
  17. package/lib/commonjs/ui/components/icon/FAIRWalletIcon.js.map +1 -0
  18. package/lib/commonjs/ui/components/icon/index.js +7 -0
  19. package/lib/commonjs/ui/components/icon/index.js.map +1 -1
  20. package/lib/commonjs/ui/components/index.js +7 -0
  21. package/lib/commonjs/ui/components/index.js.map +1 -1
  22. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +14 -7
  23. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  24. package/lib/commonjs/ui/components/internal/PinInput.js +108 -0
  25. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -0
  26. package/lib/commonjs/ui/components/internal/TextField.js +20 -0
  27. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
  28. package/lib/commonjs/ui/context/OxyContext.js +26 -36
  29. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  30. package/lib/commonjs/ui/hooks/index.js +2 -15
  31. package/lib/commonjs/ui/hooks/index.js.map +1 -1
  32. package/lib/commonjs/ui/hooks/useFollow.js +52 -136
  33. package/lib/commonjs/ui/hooks/useFollow.js.map +1 -1
  34. package/lib/commonjs/ui/hooks/useSessionSocket.js +52 -0
  35. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -0
  36. package/lib/commonjs/ui/index.js +8 -191
  37. package/lib/commonjs/ui/index.js.map +1 -1
  38. package/lib/commonjs/ui/navigation/OxyRouter.js +52 -60
  39. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  40. package/lib/commonjs/ui/screens/AccountCenterScreen.js +18 -30
  41. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  42. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +4 -22
  43. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  44. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +6 -14
  45. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  46. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +37 -66
  47. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  48. package/lib/commonjs/ui/screens/AppInfoScreen.js +21 -44
  49. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  50. package/lib/commonjs/ui/screens/FeedbackScreen.js +44 -23
  51. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  52. package/lib/commonjs/ui/screens/FileManagementScreen.js +59 -78
  53. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  54. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +1588 -0
  55. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -0
  56. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +22 -36
  57. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  58. package/lib/commonjs/ui/screens/RecoverAccountScreen.js +269 -0
  59. package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -0
  60. package/lib/commonjs/ui/screens/SessionManagementScreen.js +47 -69
  61. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  62. package/lib/commonjs/ui/screens/SignInScreen.js +99 -333
  63. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  64. package/lib/commonjs/ui/screens/SignUpScreen.js +136 -340
  65. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  66. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +192 -0
  67. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -0
  68. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +135 -0
  69. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -0
  70. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js +108 -0
  71. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js.map +1 -0
  72. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js +126 -0
  73. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js.map +1 -0
  74. package/lib/commonjs/ui/screens/internal/SignUpSummaryStep.js +84 -0
  75. package/lib/commonjs/ui/screens/internal/SignUpSummaryStep.js.map +1 -0
  76. package/lib/commonjs/ui/screens/internal/SignUpWelcomeStep.js +59 -0
  77. package/lib/commonjs/ui/screens/internal/SignUpWelcomeStep.js.map +1 -0
  78. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +15 -2
  79. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  80. package/lib/commonjs/ui/stores/authStore.js +31 -0
  81. package/lib/commonjs/ui/stores/authStore.js.map +1 -0
  82. package/lib/commonjs/ui/stores/followStore.js +124 -0
  83. package/lib/commonjs/ui/stores/followStore.js.map +1 -0
  84. package/lib/commonjs/ui/styles/index.js +0 -11
  85. package/lib/commonjs/ui/styles/index.js.map +1 -1
  86. package/lib/commonjs/ui/utils/confirmAction.js +28 -0
  87. package/lib/commonjs/ui/utils/confirmAction.js.map +1 -0
  88. package/lib/module/core/index.js +69 -81
  89. package/lib/module/core/index.js.map +1 -1
  90. package/lib/module/index.js +14 -17
  91. package/lib/module/index.js.map +1 -1
  92. package/lib/module/node/index.js +0 -3
  93. package/lib/module/node/index.js.map +1 -1
  94. package/lib/module/ui/components/FollowButton.js +100 -229
  95. package/lib/module/ui/components/FollowButton.js.map +1 -1
  96. package/lib/module/ui/components/OxyPayButton.js +125 -0
  97. package/lib/module/ui/components/OxyPayButton.js.map +1 -0
  98. package/lib/module/ui/components/OxyProvider.js +42 -199
  99. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  100. package/lib/module/ui/components/OxySignInButton.js +15 -2
  101. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  102. package/lib/module/ui/components/icon/FAIRWalletIcon.js +60 -0
  103. package/lib/module/ui/components/icon/FAIRWalletIcon.js.map +1 -0
  104. package/lib/module/ui/components/icon/index.js +1 -0
  105. package/lib/module/ui/components/icon/index.js.map +1 -1
  106. package/lib/module/ui/components/index.js +1 -0
  107. package/lib/module/ui/components/index.js.map +1 -1
  108. package/lib/module/ui/components/internal/GroupedPillButtons.js +15 -8
  109. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  110. package/lib/module/ui/components/internal/PinInput.js +103 -0
  111. package/lib/module/ui/components/internal/PinInput.js.map +1 -0
  112. package/lib/module/ui/components/internal/TextField.js +20 -0
  113. package/lib/module/ui/components/internal/TextField.js.map +1 -1
  114. package/lib/module/ui/context/OxyContext.js +26 -36
  115. package/lib/module/ui/context/OxyContext.js.map +1 -1
  116. package/lib/module/ui/hooks/index.js +1 -2
  117. package/lib/module/ui/hooks/index.js.map +1 -1
  118. package/lib/module/ui/hooks/useFollow.js +52 -137
  119. package/lib/module/ui/hooks/useFollow.js.map +1 -1
  120. package/lib/module/ui/hooks/useSessionSocket.js +47 -0
  121. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -0
  122. package/lib/module/ui/index.js +2 -13
  123. package/lib/module/ui/index.js.map +1 -1
  124. package/lib/module/ui/navigation/OxyRouter.js +53 -61
  125. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  126. package/lib/module/ui/screens/AccountCenterScreen.js +6 -18
  127. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  128. package/lib/module/ui/screens/AccountOverviewScreen.js +5 -23
  129. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  130. package/lib/module/ui/screens/AccountSettingsScreen.js +7 -15
  131. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  132. package/lib/module/ui/screens/AccountSwitcherScreen.js +38 -67
  133. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  134. package/lib/module/ui/screens/AppInfoScreen.js +22 -45
  135. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  136. package/lib/module/ui/screens/FeedbackScreen.js +44 -23
  137. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  138. package/lib/module/ui/screens/FileManagementScreen.js +59 -78
  139. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  140. package/lib/module/ui/screens/PaymentGatewayScreen.js +1583 -0
  141. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -0
  142. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +23 -37
  143. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  144. package/lib/module/ui/screens/RecoverAccountScreen.js +263 -0
  145. package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -0
  146. package/lib/module/ui/screens/SessionManagementScreen.js +47 -69
  147. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  148. package/lib/module/ui/screens/SignInScreen.js +100 -334
  149. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  150. package/lib/module/ui/screens/SignUpScreen.js +137 -341
  151. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  152. package/lib/module/ui/screens/internal/SignInPasswordStep.js +186 -0
  153. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -0
  154. package/lib/module/ui/screens/internal/SignInUsernameStep.js +129 -0
  155. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -0
  156. package/lib/module/ui/screens/internal/SignUpIdentityStep.js +102 -0
  157. package/lib/module/ui/screens/internal/SignUpIdentityStep.js.map +1 -0
  158. package/lib/module/ui/screens/internal/SignUpSecurityStep.js +120 -0
  159. package/lib/module/ui/screens/internal/SignUpSecurityStep.js.map +1 -0
  160. package/lib/module/ui/screens/internal/SignUpSummaryStep.js +79 -0
  161. package/lib/module/ui/screens/internal/SignUpSummaryStep.js.map +1 -0
  162. package/lib/module/ui/screens/internal/SignUpWelcomeStep.js +54 -0
  163. package/lib/module/ui/screens/internal/SignUpWelcomeStep.js.map +1 -0
  164. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +16 -3
  165. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  166. package/lib/module/ui/stores/authStore.js +27 -0
  167. package/lib/module/ui/stores/authStore.js.map +1 -0
  168. package/lib/module/ui/stores/followStore.js +120 -0
  169. package/lib/module/ui/stores/followStore.js.map +1 -0
  170. package/lib/module/ui/styles/index.js +0 -1
  171. package/lib/module/ui/styles/index.js.map +1 -1
  172. package/lib/module/ui/utils/confirmAction.js +25 -0
  173. package/lib/module/ui/utils/confirmAction.js.map +1 -0
  174. package/lib/typescript/core/index.d.ts +28 -10
  175. package/lib/typescript/core/index.d.ts.map +1 -1
  176. package/lib/typescript/index.d.ts +5 -4
  177. package/lib/typescript/index.d.ts.map +1 -1
  178. package/lib/typescript/models/secureSession.d.ts +0 -1
  179. package/lib/typescript/models/secureSession.d.ts.map +1 -1
  180. package/lib/typescript/node/index.d.ts +0 -1
  181. package/lib/typescript/node/index.d.ts.map +1 -1
  182. package/lib/typescript/ui/components/FollowButton.d.ts +1 -77
  183. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  184. package/lib/typescript/ui/components/OxyPayButton.d.ts +29 -0
  185. package/lib/typescript/ui/components/OxyPayButton.d.ts.map +1 -0
  186. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  187. package/lib/typescript/ui/components/OxySignInButton.d.ts.map +1 -1
  188. package/lib/typescript/ui/components/icon/FAIRWalletIcon.d.ts +8 -0
  189. package/lib/typescript/ui/components/icon/FAIRWalletIcon.d.ts.map +1 -0
  190. package/lib/typescript/ui/components/icon/index.d.ts +1 -0
  191. package/lib/typescript/ui/components/icon/index.d.ts.map +1 -1
  192. package/lib/typescript/ui/components/index.d.ts +1 -0
  193. package/lib/typescript/ui/components/index.d.ts.map +1 -1
  194. package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
  195. package/lib/typescript/ui/components/internal/PinInput.d.ts +12 -0
  196. package/lib/typescript/ui/components/internal/PinInput.d.ts.map +1 -0
  197. package/lib/typescript/ui/components/internal/TextField.d.ts +1 -0
  198. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
  199. package/lib/typescript/ui/context/OxyContext.d.ts +0 -2
  200. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  201. package/lib/typescript/ui/hooks/index.d.ts +1 -2
  202. package/lib/typescript/ui/hooks/index.d.ts.map +1 -1
  203. package/lib/typescript/ui/hooks/useFollow.d.ts +14 -15
  204. package/lib/typescript/ui/hooks/useFollow.d.ts.map +1 -1
  205. package/lib/typescript/ui/hooks/useSessionSocket.d.ts +11 -0
  206. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -0
  207. package/lib/typescript/ui/index.d.ts +2 -5
  208. package/lib/typescript/ui/index.d.ts.map +1 -1
  209. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
  210. package/lib/typescript/ui/navigation/types.d.ts +5 -23
  211. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  212. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  213. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  214. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  215. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  216. package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
  217. package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -1
  218. package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
  219. package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts +27 -0
  220. package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts.map +1 -0
  221. package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  222. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts +8 -0
  223. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -0
  224. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  225. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  226. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  227. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +27 -0
  228. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -0
  229. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +26 -0
  230. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -0
  231. package/lib/typescript/ui/screens/internal/SignUpIdentityStep.d.ts +20 -0
  232. package/lib/typescript/ui/screens/internal/SignUpIdentityStep.d.ts.map +1 -0
  233. package/lib/typescript/ui/screens/internal/SignUpSecurityStep.d.ts +24 -0
  234. package/lib/typescript/ui/screens/internal/SignUpSecurityStep.d.ts.map +1 -0
  235. package/lib/typescript/ui/screens/internal/SignUpSummaryStep.d.ts +15 -0
  236. package/lib/typescript/ui/screens/internal/SignUpSummaryStep.d.ts.map +1 -0
  237. package/lib/typescript/ui/screens/internal/SignUpWelcomeStep.d.ts +13 -0
  238. package/lib/typescript/ui/screens/internal/SignUpWelcomeStep.d.ts.map +1 -0
  239. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
  240. package/lib/typescript/ui/stores/authStore.d.ts +14 -0
  241. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -0
  242. package/lib/typescript/ui/stores/followStore.d.ts +15 -0
  243. package/lib/typescript/ui/stores/followStore.d.ts.map +1 -0
  244. package/lib/typescript/ui/styles/index.d.ts +0 -1
  245. package/lib/typescript/ui/styles/index.d.ts.map +1 -1
  246. package/lib/typescript/ui/utils/confirmAction.d.ts +7 -0
  247. package/lib/typescript/ui/utils/confirmAction.d.ts.map +1 -0
  248. package/package.json +12 -7
  249. package/src/core/index.ts +78 -88
  250. package/src/index.ts +8 -45
  251. package/src/models/secureSession.ts +1 -2
  252. package/src/node/index.ts +0 -3
  253. package/src/ui/components/FollowButton.tsx +100 -322
  254. package/src/ui/components/OxyPayButton.tsx +133 -0
  255. package/src/ui/components/OxyProvider.tsx +39 -201
  256. package/src/ui/components/OxySignInButton.tsx +13 -2
  257. package/src/ui/components/icon/FAIRWalletIcon.tsx +49 -0
  258. package/src/ui/components/icon/index.ts +1 -0
  259. package/src/ui/components/index.ts +1 -0
  260. package/src/ui/components/internal/GroupedPillButtons.tsx +12 -8
  261. package/src/ui/components/internal/PinInput.tsx +102 -0
  262. package/src/ui/components/internal/TextField.tsx +9 -0
  263. package/src/ui/context/OxyContext.tsx +26 -40
  264. package/src/ui/hooks/index.ts +1 -2
  265. package/src/ui/hooks/useFollow.ts +58 -129
  266. package/src/ui/hooks/useSessionSocket.ts +50 -0
  267. package/src/ui/index.ts +2 -37
  268. package/src/ui/navigation/OxyRouter.tsx +47 -63
  269. package/src/ui/navigation/types.ts +5 -26
  270. package/src/ui/screens/AccountCenterScreen.tsx +12 -21
  271. package/src/ui/screens/AccountOverviewScreen.tsx +6 -30
  272. package/src/ui/screens/AccountSettingsScreen.tsx +7 -22
  273. package/src/ui/screens/AccountSwitcherScreen.tsx +46 -88
  274. package/src/ui/screens/AppInfoScreen.tsx +27 -47
  275. package/src/ui/screens/FeedbackScreen.tsx +34 -19
  276. package/src/ui/screens/FileManagementScreen.tsx +293 -321
  277. package/src/ui/screens/PaymentGatewayScreen.tsx +1315 -0
  278. package/src/ui/screens/PremiumSubscriptionScreen.tsx +109 -124
  279. package/src/ui/screens/RecoverAccountScreen.tsx +260 -0
  280. package/src/ui/screens/SessionManagementScreen.tsx +65 -137
  281. package/src/ui/screens/SignInScreen.tsx +89 -283
  282. package/src/ui/screens/SignUpScreen.tsx +138 -291
  283. package/src/ui/screens/internal/SignInPasswordStep.tsx +179 -0
  284. package/src/ui/screens/internal/SignInUsernameStep.tsx +139 -0
  285. package/src/ui/screens/internal/SignUpIdentityStep.tsx +114 -0
  286. package/src/ui/screens/internal/SignUpSecurityStep.tsx +132 -0
  287. package/src/ui/screens/internal/SignUpSummaryStep.tsx +66 -0
  288. package/src/ui/screens/internal/SignUpWelcomeStep.tsx +52 -0
  289. package/src/ui/screens/karma/KarmaRewardsScreen.tsx +13 -3
  290. package/src/ui/stores/authStore.ts +24 -0
  291. package/src/ui/stores/followStore.ts +80 -0
  292. package/src/ui/styles/index.ts +0 -1
  293. package/src/ui/utils/confirmAction.ts +23 -0
  294. package/lib/commonjs/ui/components/bottomSheet/index.js +0 -37
  295. package/lib/commonjs/ui/components/bottomSheet/index.js.map +0 -1
  296. package/lib/commonjs/ui/hooks/useAuthFetch.js +0 -217
  297. package/lib/commonjs/ui/hooks/useAuthFetch.js.map +0 -1
  298. package/lib/commonjs/ui/hooks/useOxyFollow.js +0 -190
  299. package/lib/commonjs/ui/hooks/useOxyFollow.js.map +0 -1
  300. package/lib/commonjs/ui/screens/BillingManagementScreen.js +0 -636
  301. package/lib/commonjs/ui/screens/BillingManagementScreen.js.map +0 -1
  302. package/lib/commonjs/ui/store/index.js +0 -67
  303. package/lib/commonjs/ui/store/index.js.map +0 -1
  304. package/lib/commonjs/ui/store/setupOxyStore.js +0 -63
  305. package/lib/commonjs/ui/store/setupOxyStore.js.map +0 -1
  306. package/lib/commonjs/ui/store/slices/authSlice.js +0 -56
  307. package/lib/commonjs/ui/store/slices/authSlice.js.map +0 -1
  308. package/lib/commonjs/ui/store/slices/followSlice.js +0 -238
  309. package/lib/commonjs/ui/store/slices/followSlice.js.map +0 -1
  310. package/lib/commonjs/ui/store/slices/index.js +0 -129
  311. package/lib/commonjs/ui/store/slices/index.js.map +0 -1
  312. package/lib/commonjs/ui/store/slices/types.js +0 -19
  313. package/lib/commonjs/ui/store/slices/types.js.map +0 -1
  314. package/lib/commonjs/ui/styles/shadows.js +0 -123
  315. package/lib/commonjs/ui/styles/shadows.js.map +0 -1
  316. package/lib/commonjs/utils/polyfills.js +0 -42
  317. package/lib/commonjs/utils/polyfills.js.map +0 -1
  318. package/lib/module/ui/components/bottomSheet/index.js +0 -5
  319. package/lib/module/ui/components/bottomSheet/index.js.map +0 -1
  320. package/lib/module/ui/hooks/useAuthFetch.js +0 -212
  321. package/lib/module/ui/hooks/useAuthFetch.js.map +0 -1
  322. package/lib/module/ui/hooks/useOxyFollow.js +0 -186
  323. package/lib/module/ui/hooks/useOxyFollow.js.map +0 -1
  324. package/lib/module/ui/screens/BillingManagementScreen.js +0 -631
  325. package/lib/module/ui/screens/BillingManagementScreen.js.map +0 -1
  326. package/lib/module/ui/store/index.js +0 -33
  327. package/lib/module/ui/store/index.js.map +0 -1
  328. package/lib/module/ui/store/setupOxyStore.js +0 -59
  329. package/lib/module/ui/store/setupOxyStore.js.map +0 -1
  330. package/lib/module/ui/store/slices/authSlice.js +0 -48
  331. package/lib/module/ui/store/slices/authSlice.js.map +0 -1
  332. package/lib/module/ui/store/slices/followSlice.js +0 -232
  333. package/lib/module/ui/store/slices/followSlice.js.map +0 -1
  334. package/lib/module/ui/store/slices/index.js +0 -11
  335. package/lib/module/ui/store/slices/index.js.map +0 -1
  336. package/lib/module/ui/store/slices/types.js +0 -15
  337. package/lib/module/ui/store/slices/types.js.map +0 -1
  338. package/lib/module/ui/styles/shadows.js +0 -119
  339. package/lib/module/ui/styles/shadows.js.map +0 -1
  340. package/lib/module/utils/polyfills.js +0 -36
  341. package/lib/module/utils/polyfills.js.map +0 -1
  342. package/lib/typescript/types/react-redux.d.ts +0 -5
  343. package/lib/typescript/ui/components/bottomSheet/index.d.ts +0 -4
  344. package/lib/typescript/ui/components/bottomSheet/index.d.ts.map +0 -1
  345. package/lib/typescript/ui/hooks/useAuthFetch.d.ts +0 -34
  346. package/lib/typescript/ui/hooks/useAuthFetch.d.ts.map +0 -1
  347. package/lib/typescript/ui/hooks/useOxyFollow.d.ts +0 -81
  348. package/lib/typescript/ui/hooks/useOxyFollow.d.ts.map +0 -1
  349. package/lib/typescript/ui/screens/BillingManagementScreen.d.ts +0 -5
  350. package/lib/typescript/ui/screens/BillingManagementScreen.d.ts.map +0 -1
  351. package/lib/typescript/ui/store/index.d.ts +0 -27
  352. package/lib/typescript/ui/store/index.d.ts.map +0 -1
  353. package/lib/typescript/ui/store/setupOxyStore.d.ts +0 -29
  354. package/lib/typescript/ui/store/setupOxyStore.d.ts.map +0 -1
  355. package/lib/typescript/ui/store/slices/authSlice.d.ts +0 -32
  356. package/lib/typescript/ui/store/slices/authSlice.d.ts.map +0 -1
  357. package/lib/typescript/ui/store/slices/followSlice.d.ts +0 -120
  358. package/lib/typescript/ui/store/slices/followSlice.d.ts.map +0 -1
  359. package/lib/typescript/ui/store/slices/index.d.ts +0 -9
  360. package/lib/typescript/ui/store/slices/index.d.ts.map +0 -1
  361. package/lib/typescript/ui/store/slices/types.d.ts +0 -16
  362. package/lib/typescript/ui/store/slices/types.d.ts.map +0 -1
  363. package/lib/typescript/ui/styles/shadows.d.ts +0 -233
  364. package/lib/typescript/ui/styles/shadows.d.ts.map +0 -1
  365. package/lib/typescript/utils/polyfills.d.ts +0 -6
  366. package/lib/typescript/utils/polyfills.d.ts.map +0 -1
  367. package/src/__tests__/backend-middleware.test.ts +0 -209
  368. package/src/__tests__/polyfills.test.ts +0 -30
  369. package/src/__tests__/setup.ts +0 -43
  370. package/src/__tests__/ui/hooks/authfetch-integration.test.ts +0 -197
  371. package/src/__tests__/ui/hooks/backward-compatibility.test.ts +0 -159
  372. package/src/__tests__/ui/hooks/real-world-scenarios.test.ts +0 -224
  373. package/src/__tests__/ui/hooks/url-resolution.test.ts +0 -129
  374. package/src/__tests__/ui/hooks/useAuthFetch-separation.test.ts +0 -69
  375. package/src/__tests__/ui/hooks/useAuthFetch.test.ts +0 -70
  376. package/src/__tests__/ui/hooks/useOxyFollow.test.tsx +0 -92
  377. package/src/__tests__/ui/screens/AccountSettingsScreen.test.tsx +0 -112
  378. package/src/__tests__/ui/store/setupOxyStore.test.ts +0 -50
  379. package/src/__tests__/validate-structure.js +0 -91
  380. package/src/__tests__/validation.js +0 -42
  381. package/src/types/react-redux.d.ts +0 -5
  382. package/src/ui/components/bottomSheet/index.tsx +0 -14
  383. package/src/ui/hooks/useAuthFetch.ts +0 -238
  384. package/src/ui/hooks/useOxyFollow.ts +0 -188
  385. package/src/ui/screens/BillingManagementScreen.tsx +0 -589
  386. package/src/ui/store/index.ts +0 -36
  387. package/src/ui/store/setupOxyStore.ts +0 -58
  388. package/src/ui/store/slices/authSlice.ts +0 -43
  389. package/src/ui/store/slices/followSlice.ts +0 -207
  390. package/src/ui/store/slices/index.ts +0 -31
  391. package/src/ui/store/slices/types.ts +0 -33
  392. package/src/ui/styles/shadows.ts +0 -112
  393. package/src/utils/polyfills.ts +0 -34
@@ -0,0 +1,1315 @@
1
+ import React, { useState, useRef, useMemo, useCallback, useEffect } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ TouchableOpacity,
6
+ StyleSheet,
7
+ Platform,
8
+ KeyboardAvoidingView,
9
+ ScrollView,
10
+ Animated,
11
+ StatusBar,
12
+ ScrollView as RNScrollView,
13
+ Dimensions,
14
+ Linking,
15
+ Clipboard,
16
+ useWindowDimensions,
17
+ } from 'react-native';
18
+ import { BaseScreenProps } from '../navigation/types';
19
+ import { fontFamilies, useThemeColors, createCommonStyles } from '../styles';
20
+ import OxyLogo from '../components/OxyLogo';
21
+ import GroupedPillButtons from '../components/internal/GroupedPillButtons';
22
+ import TextField from '../components/internal/TextField';
23
+ import { Ionicons } from '@expo/vector-icons';
24
+ import { FAIRWalletIcon } from '../components/icon';
25
+ import { toast } from 'sonner';
26
+ import QRCode from 'react-native-qrcode-svg';
27
+ import * as RNIap from 'react-native-iap';
28
+
29
+ // Restrict payment methods to Card, Oxy Pay, and FairCoin (QR)
30
+ const PAYMENT_METHODS = [
31
+ { key: 'card', label: 'Credit/Debit Card', icon: 'card-outline', description: 'Pay securely with your credit or debit card.' },
32
+ { key: 'oxy', label: 'Oxy Pay', icon: 'wallet-outline', description: 'Use your Oxy Pay in-app balance.' },
33
+ { key: 'faircoin', label: 'FAIRWallet', icon: 'qr-code-outline', description: 'Pay with FairCoin by scanning a QR code.' },
34
+ ];
35
+
36
+ // Add Google Play Billing to payment methods if Android
37
+ const ANDROID_IAP_METHOD = {
38
+ key: 'googleplay',
39
+ label: 'Google Play Billing',
40
+ icon: 'logo-google-playstore',
41
+ description: 'Pay securely with your Google Play account.'
42
+ };
43
+ if (Platform.OS === 'android' && !PAYMENT_METHODS.find(m => m.key === 'googleplay')) {
44
+ PAYMENT_METHODS.push(ANDROID_IAP_METHOD);
45
+ }
46
+
47
+ // Add PaymentItem type
48
+ export type PaymentItem = {
49
+ type: 'product' | 'subscription' | 'service' | 'fee' | string;
50
+ name: string;
51
+ description?: string;
52
+ quantity?: number; // for products
53
+ period?: string; // for subscriptions, e.g. 'Monthly'
54
+ price: number;
55
+ currency?: string; // fallback to main currency if not set
56
+ };
57
+
58
+ // Extend props to accept onPaymentResult, amount, and currency
59
+ interface PaymentGatewayResult {
60
+ success: boolean;
61
+ details?: any;
62
+ error?: string;
63
+ }
64
+
65
+ interface PaymentGatewayScreenProps extends BaseScreenProps {
66
+ onPaymentResult?: (result: PaymentGatewayResult) => void;
67
+ amount: string | number;
68
+ currency?: string; // e.g. 'FAIR', 'INR', 'USD', 'EUR', 'GBP', etc.
69
+ onClose?: () => void;
70
+ paymentItems?: PaymentItem[]; // NEW: generic items
71
+ description?: string; // NEW: fallback if no items
72
+ }
73
+
74
+ // Currency symbol map
75
+ const CURRENCY_SYMBOLS: Record<string, string> = {
76
+ FAIR: '⊜',
77
+ INR: '₹',
78
+ USD: '$',
79
+ EUR: '€',
80
+ GBP: '£',
81
+ JPY: '¥',
82
+ CNY: '¥',
83
+ AUD: 'A$',
84
+ CAD: 'C$',
85
+ // Add more as needed
86
+ };
87
+
88
+ const CURRENCY_NAMES: Record<string, string> = {
89
+ FAIR: 'FairCoin',
90
+ INR: 'Indian Rupee',
91
+ USD: 'US Dollar',
92
+ EUR: 'Euro',
93
+ GBP: 'British Pound',
94
+ JPY: 'Japanese Yen',
95
+ CNY: 'Chinese Yuan',
96
+ AUD: 'Australian Dollar',
97
+ CAD: 'Canadian Dollar',
98
+ // Add more as needed
99
+ };
100
+
101
+ // Helper: icon for item type (Ionicons only)
102
+ const getItemTypeIcon = (type: string, color: string) => {
103
+ switch (type) {
104
+ case 'product':
105
+ return <Ionicons name="cart-outline" size={22} color={color} style={{ marginRight: 8 }} />;
106
+ case 'subscription':
107
+ return <Ionicons name="repeat-outline" size={22} color={color} style={{ marginRight: 8 }} />;
108
+ case 'service':
109
+ return <Ionicons name="construct-outline" size={22} color={color} style={{ marginRight: 8 }} />;
110
+ case 'fee':
111
+ return <Ionicons name="cash-outline" size={22} color={color} style={{ marginRight: 8 }} />;
112
+ default:
113
+ return <Ionicons name="pricetag-outline" size={22} color={color} style={{ marginRight: 8 }} />;
114
+ }
115
+ };
116
+
117
+ const IAP_PRODUCT_IDS = ['test_product_1', 'test_product_2']; // TODO: Replace with real product IDs
118
+
119
+ // Helper to get unique item types (move to top-level, before component)
120
+ const getUniqueItemTypes = (items: PaymentItem[]) => {
121
+ const types = items.map(item => item.type);
122
+ return Array.from(new Set(types));
123
+ };
124
+
125
+ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
126
+ const {
127
+ navigate,
128
+ goBack,
129
+ theme,
130
+ onPaymentResult,
131
+ amount,
132
+ currency = 'FAIR',
133
+ onClose,
134
+ paymentItems = [], // NEW
135
+ description = '', // NEW
136
+ } = props;
137
+
138
+ // DEV ENFORCEMENT: Only allow one type of payment item
139
+ if (process.env.NODE_ENV !== 'production' && paymentItems.length > 0) {
140
+ const uniqueTypes = getUniqueItemTypes(paymentItems);
141
+ if (uniqueTypes.length > 1) {
142
+ throw new Error(
143
+ `PaymentGatewayScreen: paymentItems contains mixed types (${uniqueTypes.join(', ')}). Only one type is allowed per payment.`
144
+ );
145
+ }
146
+ }
147
+
148
+ // Step states
149
+ const [currentStep, setCurrentStep] = useState(0);
150
+ const [paymentMethod, setPaymentMethod] = useState('card');
151
+ const [cardDetails, setCardDetails] = useState({ number: '', expiry: '', cvv: '' });
152
+ const [upiId, setUpiId] = useState('');
153
+ const [isPaying, setIsPaying] = useState(false);
154
+ const [success, setSuccess] = useState(false);
155
+
156
+ // IAP state
157
+ const [iapProducts, setIapProducts] = useState<RNIap.Product[]>([]);
158
+ const [iapError, setIapError] = useState<string | null>(null);
159
+ const [iapLoading, setIapLoading] = useState(false);
160
+ const [iapPurchase, setIapPurchase] = useState<RNIap.Purchase | null>(null);
161
+
162
+ // Animations
163
+ const fadeAnim = useRef(new Animated.Value(1)).current;
164
+ const slideAnim = useRef(new Animated.Value(0)).current;
165
+ const scaleAnim = useRef(new Animated.Value(1)).current;
166
+ const progressAnim = useRef(new Animated.Value(0.2)).current;
167
+
168
+ const colors = useThemeColors(theme);
169
+ const commonStyles = createCommonStyles(theme);
170
+ const styles = useMemo(() => createStyles(colors, theme), [colors, theme]);
171
+
172
+ // Get symbol and name for currency
173
+ const currencySymbol = CURRENCY_SYMBOLS[currency.toUpperCase()] || currency;
174
+ const currencyName = CURRENCY_NAMES[currency.toUpperCase()] || currency;
175
+
176
+ // Calculate total from items if provided, else use amount
177
+ const computedTotal = useMemo(() => {
178
+ if (paymentItems && paymentItems.length > 0) {
179
+ return paymentItems.reduce((sum, item) => {
180
+ const qty = item.quantity ?? 1;
181
+ return sum + (item.price * qty);
182
+ }, 0);
183
+ }
184
+ return Number(amount) || 0;
185
+ }, [paymentItems, amount]);
186
+
187
+ // Determine if the payment is for a recurring item (subscription)
188
+ const isRecurring = paymentItems.length > 0 && paymentItems[0].type === 'subscription';
189
+
190
+ // Filter payment methods: remove 'faircoin' if recurring
191
+ const availablePaymentMethods = useMemo(() => {
192
+ if (isRecurring) {
193
+ return PAYMENT_METHODS.filter(m => m.key !== 'faircoin');
194
+ }
195
+ return PAYMENT_METHODS;
196
+ }, [isRecurring]);
197
+
198
+ // Add after useState declarations
199
+ // Remove itemTypeError state, useEffect, and user-facing error in renderSummaryStep
200
+
201
+ // Helper to get unique item types
202
+ // Remove itemTypeError state, useEffect, and user-facing error in renderSummaryStep
203
+
204
+ // Validate item types on paymentItems change
205
+ // Remove itemTypeError state, useEffect, and user-facing error in renderSummaryStep
206
+
207
+ // Animation transitions
208
+ const animateTransition = useCallback((nextStep: number) => {
209
+ Animated.timing(scaleAnim, {
210
+ toValue: 0.95,
211
+ duration: 150,
212
+ useNativeDriver: true,
213
+ }).start();
214
+ Animated.timing(fadeAnim, {
215
+ toValue: 0,
216
+ duration: 200,
217
+ useNativeDriver: true,
218
+ }).start(() => {
219
+ setCurrentStep(nextStep);
220
+ slideAnim.setValue(-50);
221
+ scaleAnim.setValue(0.95);
222
+ Animated.parallel([
223
+ Animated.timing(fadeAnim, {
224
+ toValue: 1,
225
+ duration: 300,
226
+ useNativeDriver: true,
227
+ }),
228
+ Animated.spring(slideAnim, {
229
+ toValue: 0,
230
+ tension: 80,
231
+ friction: 8,
232
+ useNativeDriver: true,
233
+ }),
234
+ Animated.spring(scaleAnim, {
235
+ toValue: 1,
236
+ tension: 80,
237
+ friction: 8,
238
+ useNativeDriver: true,
239
+ })
240
+ ]).start();
241
+ });
242
+ }, [fadeAnim, slideAnim, scaleAnim]);
243
+
244
+ const nextStep = useCallback(() => {
245
+ if (currentStep < 4) {
246
+ Animated.timing(progressAnim, {
247
+ toValue: (currentStep + 2) / 5,
248
+ duration: 300,
249
+ useNativeDriver: false,
250
+ }).start();
251
+ animateTransition(currentStep + 1);
252
+ }
253
+ }, [currentStep, progressAnim, animateTransition]);
254
+
255
+ const prevStep = useCallback(() => {
256
+ if (currentStep > 0) {
257
+ Animated.timing(progressAnim, {
258
+ toValue: (currentStep) / 5,
259
+ duration: 300,
260
+ useNativeDriver: false,
261
+ }).start();
262
+ animateTransition(currentStep - 1);
263
+ }
264
+ }, [currentStep, progressAnim, animateTransition]);
265
+
266
+ // Dummy pay handler
267
+ const handlePay = useCallback(() => {
268
+ setIsPaying(true);
269
+ setTimeout(() => {
270
+ setIsPaying(false);
271
+ setSuccess(true);
272
+ nextStep();
273
+ }, 1500);
274
+ }, [nextStep]);
275
+
276
+ // Success handler for Done button
277
+ const handleDone = useCallback(() => {
278
+ if (onPaymentResult) {
279
+ onPaymentResult({ success: true });
280
+ }
281
+ navigate('AccountOverviewScreen');
282
+ }, [onPaymentResult, navigate]);
283
+
284
+ // Handle close/cancel: return failure result if payment is not completed
285
+ const handleClose = useCallback(() => {
286
+ if (onPaymentResult) {
287
+ onPaymentResult({ success: false, error: 'cancelled' });
288
+ }
289
+ if (onClose) {
290
+ onClose();
291
+ } else if (goBack) {
292
+ goBack();
293
+ }
294
+ }, [onPaymentResult, onClose, goBack]);
295
+
296
+ // Optionally, intercept goBack/onClose if user tries to close the screen
297
+ // (You may want to use useEffect to listen for unmount or navigation away)
298
+
299
+ // If amount is missing or invalid, show error
300
+ if (!amount || isNaN(Number(amount)) || Number(amount) <= 0) {
301
+ return (
302
+ <View style={styles.errorContainer}>
303
+ <Text style={styles.errorText}>Invalid or missing payment amount.</Text>
304
+ <GroupedPillButtons
305
+ buttons={[
306
+ {
307
+ text: 'Close',
308
+ onPress: handleClose,
309
+ icon: 'close',
310
+ variant: 'primary',
311
+ },
312
+ ]}
313
+ colors={useThemeColors(theme)}
314
+ />
315
+ </View>
316
+ );
317
+ }
318
+
319
+ // Example FairCoin address (replace with real one)
320
+ const faircoinAddress = 'f1abc1234FAIRCOINADDRESS';
321
+ const { width: windowWidth } = useWindowDimensions();
322
+ const isMobile = windowWidth < 600;
323
+ const qrSize = !isMobile
324
+ ? Math.min(windowWidth * 0.3, 220)
325
+ : Math.min(windowWidth * 0.8, 300);
326
+
327
+ const handleCopyAddress = () => {
328
+ Clipboard.setString(faircoinAddress);
329
+ toast('Address copied to clipboard!');
330
+ };
331
+ const handleOpenFairWallet = () => {
332
+ const url = `fairwallet://pay?address=${faircoinAddress}`;
333
+ Linking.openURL(url);
334
+ };
335
+
336
+ // IAP setup (Android only)
337
+ useEffect(() => {
338
+ if (paymentMethod !== 'googleplay' || Platform.OS !== 'android') return;
339
+ let purchaseUpdateSub: any, purchaseErrorSub: any;
340
+ setIapLoading(true);
341
+ RNIap.initConnection()
342
+ .then(() => RNIap.getProducts({ skus: IAP_PRODUCT_IDS }))
343
+ .then(setIapProducts)
344
+ .catch(e => setIapError(e.message))
345
+ .finally(() => setIapLoading(false));
346
+ purchaseUpdateSub = RNIap.purchaseUpdatedListener((purchase) => {
347
+ setIapPurchase(purchase);
348
+ setSuccess(true);
349
+ nextStep();
350
+ });
351
+ purchaseErrorSub = RNIap.purchaseErrorListener((err) => {
352
+ setIapError(err.message);
353
+ });
354
+ return () => {
355
+ purchaseUpdateSub && purchaseUpdateSub.remove();
356
+ purchaseErrorSub && purchaseErrorSub.remove();
357
+ RNIap.endConnection();
358
+ };
359
+ }, [paymentMethod]);
360
+
361
+ const handleIapBuy = async (sku: string) => {
362
+ setIapError(null);
363
+ setIapLoading(true);
364
+ try {
365
+ await RNIap.requestPurchase({ sku });
366
+ } catch (e: any) {
367
+ setIapError(e.message);
368
+ } finally {
369
+ setIapLoading(false);
370
+ }
371
+ };
372
+
373
+ // Helper for dynamic styles
374
+ const getStepIndicatorStyle = (active: boolean) => [
375
+ styles.stepIndicator,
376
+ active ? styles.stepIndicatorActive : styles.stepIndicatorInactive,
377
+ ];
378
+
379
+ const getPaymentMethodButtonStyle = (active: boolean) => [
380
+ styles.paymentMethodButton,
381
+ active ? styles.paymentMethodButtonActive : styles.paymentMethodButtonInactive,
382
+ ];
383
+
384
+ const getPaymentMethodIconColor = (active: boolean) => (
385
+ active ? colors.primary : colors.text
386
+ );
387
+
388
+ // Step indicator
389
+ const renderStepIndicator = () => {
390
+ const totalSteps = 5;
391
+ const activeStep = currentStep + 1;
392
+ return (
393
+ <View style={styles.stepIndicatorContainer}>
394
+ {Array.from({ length: totalSteps }).map((_, idx) => (
395
+ <View
396
+ key={idx}
397
+ style={getStepIndicatorStyle(activeStep === idx + 1)}
398
+ />
399
+ ))}
400
+ </View>
401
+ );
402
+ };
403
+
404
+ // PaymentGatewayHeader component
405
+ const stepTitles = [
406
+ 'Complete Your Payment',
407
+ 'Select Payment Method',
408
+ 'Enter Payment Details',
409
+ 'Review & Pay',
410
+ 'Success',
411
+ ];
412
+ const PaymentGatewayHeader: React.FC<{ currentStep: number; totalSteps: number; title: string; }> = ({ currentStep, totalSteps, title }) => (
413
+ <View style={styles.headerWrapper}>
414
+ <OxyLogo style={styles.logo} />
415
+ <Text style={styles.headerTitle}>{title}</Text>
416
+ <View style={styles.headerStepIndicatorContainer}>
417
+ {Array.from({ length: totalSteps }).map((_, idx) => (
418
+ <View
419
+ key={idx}
420
+ style={getStepIndicatorStyle(currentStep + 1 === idx + 1)}
421
+ />
422
+ ))}
423
+ </View>
424
+ </View>
425
+ );
426
+
427
+ // Card container for main content
428
+ const Card: React.FC<{ children: React.ReactNode; style?: any }> = ({ children, style }) => (
429
+ <View style={[styles.card, style]}>
430
+ {children}
431
+ </View>
432
+ );
433
+
434
+ // Product/Item summary card for step 1
435
+ const renderItemSummary = () => {
436
+ if (paymentItems && paymentItems.length > 0) {
437
+ return (
438
+ <Card style={{ marginBottom: 10 }}>
439
+ {paymentItems.map((item, idx) => (
440
+ <View key={idx} style={{ marginBottom: 8 }}>
441
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
442
+ <Text style={{ fontWeight: '600', color: colors.text }}>
443
+ {item.type === 'product' && item.quantity ? `${item.quantity} × ` : ''}
444
+ {item.name}
445
+ {item.type === 'subscription' && item.period ? ` (${item.period})` : ''}
446
+ </Text>
447
+ <Text style={{ color: colors.text }}>
448
+ {(item.currency ? (CURRENCY_SYMBOLS[item.currency.toUpperCase()] || item.currency) : currencySymbol)} {item.price * (item.quantity ?? 1)}
449
+ </Text>
450
+ </View>
451
+ {item.description ? (
452
+ <Text style={{ color: colors.secondaryText, fontSize: 13 }}>{item.description}</Text>
453
+ ) : null}
454
+ </View>
455
+ ))}
456
+ <View style={{ borderTopWidth: 1, borderColor: colors.border, marginTop: 8, paddingTop: 8, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
457
+ <Text style={{ fontWeight: '700', color: colors.text }}>Total</Text>
458
+ <Text style={{ fontWeight: '700', color: colors.primary, fontSize: 18 }}>{currencySymbol} {computedTotal}</Text>
459
+ </View>
460
+ </Card>
461
+ );
462
+ } else if (description) {
463
+ return (
464
+ <Card style={{ marginBottom: 10 }}>
465
+ <Text style={{ color: colors.text }}>{description}</Text>
466
+ <View style={{ borderTopWidth: 1, borderColor: colors.border, marginTop: 8, paddingTop: 8, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
467
+ <Text style={{ fontWeight: '700', color: colors.text }}>Total</Text>
468
+ <Text style={{ fontWeight: '700', color: colors.primary, fontSize: 18 }}>{currencySymbol} {computedTotal}</Text>
469
+ </View>
470
+ </Card>
471
+ );
472
+ }
473
+ return null;
474
+ };
475
+
476
+ // Step 1: Summary step (new first step, no header/dots here)
477
+ const renderSummaryStep = () => (
478
+ <Animated.View style={[styles.stepContainer, {
479
+ opacity: fadeAnim,
480
+ transform: [
481
+ { translateY: slideAnim },
482
+ { scale: scaleAnim },
483
+ ]
484
+ }]}
485
+ >
486
+ <Card>
487
+ <Text style={{ color: colors.secondaryText, fontSize: 15, marginBottom: 16 }}>You're about to pay for the following:</Text>
488
+ {paymentItems && paymentItems.length > 0 ? paymentItems.map((item, idx) => (
489
+ <View key={idx} style={{ marginBottom: 12, flexDirection: 'row', alignItems: 'flex-start' }}>
490
+ {getItemTypeIcon(item.type, colors.primary)}
491
+ <View style={{ flex: 1 }}>
492
+ <Text style={{ fontWeight: '600', color: colors.text, fontSize: 16 }}>
493
+ {item.type === 'product' && item.quantity ? `${item.quantity} × ` : ''}
494
+ {item.name}
495
+ {item.type === 'subscription' && item.period ? ` (${item.period})` : ''}
496
+ </Text>
497
+ {item.description ? (
498
+ <Text style={{ color: colors.secondaryText, fontSize: 13, marginTop: 2 }}>{item.description}</Text>
499
+ ) : null}
500
+ </View>
501
+ <Text style={{ color: colors.text, fontWeight: '600', fontSize: 16, marginLeft: 8 }}>
502
+ {(item.currency ? (CURRENCY_SYMBOLS[item.currency.toUpperCase()] || item.currency) : currencySymbol)} {item.price * (item.quantity ?? 1)}
503
+ </Text>
504
+ </View>
505
+ )) : (
506
+ <Text style={{ color: colors.text }}>{description}</Text>
507
+ )}
508
+ <GroupedPillButtons
509
+ buttons={[
510
+ {
511
+ text: 'Close',
512
+ onPress: handleClose,
513
+ icon: 'close',
514
+ variant: 'transparent',
515
+ },
516
+ {
517
+ text: 'Continue',
518
+ onPress: nextStep,
519
+ icon: 'arrow-forward',
520
+ variant: 'primary',
521
+ },
522
+ ]}
523
+ colors={colors}
524
+ />
525
+ </Card>
526
+ </Animated.View>
527
+ );
528
+
529
+ // Step 2: Choose Payment Method (now the second step, no header/dots here)
530
+ const renderMethodStep = () => (
531
+ <Animated.View style={[styles.stepContainer, {
532
+ opacity: fadeAnim,
533
+ transform: [
534
+ { translateY: slideAnim },
535
+ { scale: scaleAnim },
536
+ ]
537
+ }]}
538
+ >
539
+ <Card>
540
+ <View style={styles.circleListContainer}>
541
+ {availablePaymentMethods.map(method => {
542
+ const isSelected = paymentMethod === method.key;
543
+ return (
544
+ <TouchableOpacity
545
+ key={method.key}
546
+ onPress={() => setPaymentMethod(method.key)}
547
+ activeOpacity={0.85}
548
+ style={[styles.circleMethod, isSelected && styles.circleMethodSelected]}
549
+ >
550
+ <View style={styles.circleIconWrapper}>
551
+ {method.key === 'faircoin' ? (
552
+ <FAIRWalletIcon size={28} />
553
+ ) : (
554
+ <Ionicons
555
+ name={method.icon as any}
556
+ size={28}
557
+ color={isSelected ? colors.primary : colors.text}
558
+ />
559
+ )}
560
+ {isSelected && (
561
+ <View style={styles.circleCheckOverlay}>
562
+ <Ionicons name="checkmark-circle" size={28} color={colors.primary} />
563
+ </View>
564
+ )}
565
+ </View>
566
+ <Text style={[styles.circleLabel, isSelected && styles.circleLabelSelected]}>{method.label}</Text>
567
+ </TouchableOpacity>
568
+ );
569
+ })}
570
+ </View>
571
+ </Card>
572
+ <GroupedPillButtons
573
+ buttons={[
574
+ {
575
+ text: 'Back',
576
+ onPress: prevStep,
577
+ icon: 'arrow-back',
578
+ variant: 'transparent',
579
+ },
580
+ {
581
+ text: 'Continue',
582
+ onPress: nextStep,
583
+ icon: 'arrow-forward',
584
+ variant: 'primary',
585
+ },
586
+ ]}
587
+ colors={colors}
588
+ />
589
+ </Animated.View>
590
+ );
591
+
592
+ // Step 2: Enter Payment Details
593
+ const renderDetailsStep = () => (
594
+ <Animated.View style={[styles.stepContainer, {
595
+ opacity: fadeAnim,
596
+ transform: [
597
+ { translateY: slideAnim },
598
+ { scale: scaleAnim },
599
+ ]
600
+ }]}
601
+ >
602
+ <Card
603
+ style={paymentMethod === 'faircoin' ? { backgroundColor: '#f6fff0', paddingVertical: 24, paddingHorizontal: 0 } : undefined}
604
+ >
605
+ {paymentMethod === 'card' && (
606
+ <>
607
+ <View style={styles.cardRowInfo}>
608
+ <Ionicons name="card-outline" size={24} color={colors.primary} style={styles.cardRowIcon} />
609
+ <Text style={styles.cardRowText}>We accept Visa, Mastercard, and more</Text>
610
+ </View>
611
+ <TextField
612
+ value={cardDetails.number}
613
+ onChangeText={text => setCardDetails({ ...cardDetails, number: text })}
614
+ placeholder="Card Number"
615
+ keyboardType="numeric"
616
+ containerStyle={styles.cardFieldContainer}
617
+ leftComponent={<Ionicons name="card-outline" size={18} color={colors.primary} />}
618
+ />
619
+ <View style={styles.cardFieldRow}>
620
+ <TextField
621
+ value={cardDetails.expiry}
622
+ onChangeText={text => setCardDetails({ ...cardDetails, expiry: text })}
623
+ placeholder="MM/YY"
624
+ containerStyle={styles.cardFieldHalfLeft}
625
+ leftComponent={<Ionicons name="calendar-outline" size={16} color={colors.primary} />}
626
+ />
627
+ <TextField
628
+ value={cardDetails.cvv}
629
+ onChangeText={text => setCardDetails({ ...cardDetails, cvv: text })}
630
+ placeholder="CVV"
631
+ keyboardType="numeric"
632
+ containerStyle={styles.cardFieldHalfRight}
633
+ leftComponent={<Ionicons name="lock-closed-outline" size={16} color={colors.primary} />}
634
+ />
635
+ </View>
636
+ </>
637
+ )}
638
+ {paymentMethod === 'oxy' && (
639
+ <View style={styles.oxyPayContainer}>
640
+ <Ionicons name="wallet-outline" size={48} color={colors.primary} style={styles.oxyPayIcon} />
641
+ <Text style={styles.oxyPayTitle}>Pay with Oxy Pay</Text>
642
+ <Text style={styles.oxyPaySubtitle}>(Oxy Pay is your in-app wallet. Make sure you have enough balance.)</Text>
643
+ <View style={styles.oxyPayBalanceBox}>
644
+ <Text style={styles.oxyPayBalanceText}>Balance: ⊜ 123.45</Text>
645
+ </View>
646
+ </View>
647
+ )}
648
+ {paymentMethod === 'faircoin' && (
649
+ <View style={{ alignItems: 'center', width: '100%' }}>
650
+ <FAIRWalletIcon size={64} style={[styles.faircoinIcon, { shadowColor: '#1b1f0a', shadowOpacity: 0.18, shadowRadius: 12, elevation: 6, marginBottom: 12 }]} />
651
+ <Text style={{ fontFamily: fontFamilies.phuduBold, fontWeight: 'bold', fontSize: 28, color: '#1b1f0a', marginBottom: 2, textAlign: 'center', letterSpacing: 0.5 }}>FAIRWallet</Text>
652
+ <Text style={{ color: '#1b1f0a', fontWeight: '700', fontSize: 17, marginBottom: 18, textAlign: 'center', letterSpacing: 0.2 }}>Pay with FairCoin</Text>
653
+ {!isMobile ? (
654
+ <>
655
+ <Text style={{ color: '#1b1f0a', fontWeight: '600', fontSize: 15, marginBottom: 8 }}>Scan to Pay</Text>
656
+ <View style={[styles.faircoinQRBox, { width: qrSize, height: qrSize, borderColor: '#9ffb50', borderWidth: 3, position: 'relative', backgroundColor: '#fff', boxShadow: '0 2px 12px #9ffb5040', justifyContent: 'center', alignItems: 'center' }]}>
657
+ <QRCode value={faircoinAddress} size={qrSize - 32} />
658
+ <View style={{ position: 'absolute', bottom: 8, right: 8 }}>
659
+ <FAIRWalletIcon size={28} />
660
+ </View>
661
+ </View>
662
+ </>
663
+ ) : (
664
+ <>
665
+ <Text style={styles.faircoinTitle}>Use the options below to pay with FAIRWallet</Text>
666
+ <Text style={styles.faircoinAddress}>{faircoinAddress}</Text>
667
+ <TouchableOpacity style={[styles.faircoinButton, { backgroundColor: '#9ffb50', borderRadius: 18, marginTop: 12, width: '90%', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }]} onPress={handleOpenFairWallet}>
668
+ <FAIRWalletIcon size={20} style={{ marginRight: 8 }} />
669
+ <Text style={[styles.faircoinButtonText, { color: '#1b1f0a', fontWeight: 'bold', fontSize: 16 }]}>Open in FAIRWallet</Text>
670
+ </TouchableOpacity>
671
+ <TouchableOpacity style={[styles.faircoinButton, { backgroundColor: '#9ffb50', borderRadius: 18, marginTop: 10, width: '90%', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }]} onPress={handleCopyAddress}>
672
+ <FAIRWalletIcon size={20} style={{ marginRight: 8 }} />
673
+ <Text style={[styles.faircoinButtonText, { color: '#1b1f0a', fontWeight: 'bold', fontSize: 16 }]}>Copy Address</Text>
674
+ </TouchableOpacity>
675
+ </>
676
+ )}
677
+ <View style={{ height: 18 }} />
678
+ <Text style={styles.faircoinWaiting}>Waiting for payment...</Text>
679
+ <Text style={styles.faircoinPlaceholder}>(This is a placeholder. Integrate with a QR code generator for production.)</Text>
680
+ </View>
681
+ )}
682
+ </Card>
683
+ <GroupedPillButtons
684
+ buttons={[
685
+ {
686
+ text: 'Back',
687
+ onPress: prevStep,
688
+ icon: 'arrow-back',
689
+ variant: 'transparent',
690
+ },
691
+ {
692
+ text: 'Continue',
693
+ onPress: nextStep,
694
+ icon: 'arrow-forward',
695
+ variant: 'primary',
696
+ disabled:
697
+ (paymentMethod === 'card' && (!cardDetails.number || !cardDetails.expiry || !cardDetails.cvv)),
698
+ },
699
+ ]}
700
+ colors={colors}
701
+ />
702
+ </Animated.View>
703
+ );
704
+
705
+ // Step 4: Review & Pay
706
+ const renderReviewStep = () => (
707
+ <Animated.View style={[styles.stepContainer, {
708
+ opacity: fadeAnim,
709
+ transform: [
710
+ { translateY: slideAnim },
711
+ { scale: scaleAnim },
712
+ ]
713
+ }]}
714
+ >
715
+ <Card>
716
+ <View style={styles.reviewSecureRow}>
717
+ <Ionicons name="shield-checkmark" size={20} color={colors.success || '#4BB543'} style={styles.reviewSecureIcon} />
718
+ <Text style={styles.reviewSecureText}>Secure payment</Text>
719
+ </View>
720
+ <View style={styles.reviewRow}>
721
+ <Text style={styles.reviewLabel}>Amount</Text>
722
+ <Text style={styles.reviewValue}>{currencySymbol} {amount}</Text>
723
+ </View>
724
+ <View style={styles.reviewRow}>
725
+ <Text style={styles.reviewLabel}>Method</Text>
726
+ <View style={styles.reviewMethodRow}>
727
+ <Ionicons name={PAYMENT_METHODS.find(m => m.key === paymentMethod)?.icon as any} size={18} color={colors.primary} style={styles.reviewMethodIcon} />
728
+ <Text style={styles.reviewMethodText}>{PAYMENT_METHODS.find(m => m.key === paymentMethod)?.label}</Text>
729
+ </View>
730
+ </View>
731
+ {paymentMethod === 'card' && (
732
+ <View style={styles.reviewRow}>
733
+ <Text style={styles.reviewLabel}>Card</Text>
734
+ <Text style={styles.reviewValue}>{cardDetails.number.replace(/.(?=.{4})/g, '*')}</Text>
735
+ </View>
736
+ )}
737
+ {paymentMethod === 'oxy' && (
738
+ <View style={styles.reviewRow}>
739
+ <Text style={styles.reviewLabel}>Oxy Pay Account</Text>
740
+ <Text style={styles.reviewValue}>Balance: ⊜ 123.45</Text>
741
+ </View>
742
+ )}
743
+ {paymentMethod === 'faircoin' && (
744
+ <View style={styles.reviewRow}>
745
+ <Text style={styles.reviewLabel}>FairCoin Wallet</Text>
746
+ <Text style={styles.reviewValue}>Paid via QR</Text>
747
+ </View>
748
+ )}
749
+ </Card>
750
+ <GroupedPillButtons
751
+ buttons={[
752
+ {
753
+ text: 'Back',
754
+ onPress: prevStep,
755
+ icon: 'arrow-back',
756
+ variant: 'transparent',
757
+ },
758
+ {
759
+ text: isPaying ? 'Processing...' : 'Pay Now',
760
+ onPress: handlePay,
761
+ icon: 'checkmark',
762
+ variant: 'primary',
763
+ loading: isPaying,
764
+ },
765
+ ]}
766
+ colors={colors}
767
+ />
768
+ </Animated.View>
769
+ );
770
+
771
+ // Step 5: Success
772
+ const renderSuccessStep = () => (
773
+ <Animated.View style={[styles.stepContainer, {
774
+ opacity: fadeAnim,
775
+ transform: [
776
+ { translateY: slideAnim },
777
+ { scale: scaleAnim },
778
+ ]
779
+ }]}
780
+ >
781
+ <View style={styles.successContainer}>
782
+ <View style={styles.successIconBox}>
783
+ <Ionicons name="checkmark-circle" size={64} color={colors.success || '#4BB543'} />
784
+ </View>
785
+ <Text style={styles.successTitle}>Payment Successful!</Text>
786
+ <Text style={styles.successSubtitle}>Thank you for your payment.</Text>
787
+ </View>
788
+ <GroupedPillButtons
789
+ buttons={[
790
+ {
791
+ text: 'Done',
792
+ onPress: handleDone,
793
+ icon: 'checkmark',
794
+ variant: 'primary',
795
+ },
796
+ ]}
797
+ colors={colors}
798
+ />
799
+ </Animated.View>
800
+ );
801
+
802
+ // Step: Google Play Billing (Android only)
803
+ const renderGooglePlayStep = () => (
804
+ <Animated.View style={[styles.stepContainer, {
805
+ opacity: fadeAnim,
806
+ transform: [
807
+ { translateY: slideAnim },
808
+ { scale: scaleAnim },
809
+ ]
810
+ }]}
811
+ >
812
+ <Card>
813
+ <Text style={{ color: colors.text, fontWeight: '600', fontSize: 16, marginBottom: 12 }}>Select a product to purchase:</Text>
814
+ {iapLoading && <Text style={{ color: colors.secondaryText }}>Loading products...</Text>}
815
+ {iapError && <Text style={{ color: 'red' }}>{iapError}</Text>}
816
+ {iapProducts.map(product => (
817
+ <TouchableOpacity
818
+ key={product.productId}
819
+ style={[styles.paymentMethodButton, { marginBottom: 8 }]}
820
+ onPress={() => handleIapBuy(product.productId)}
821
+ disabled={iapLoading}
822
+ >
823
+ <Text style={{ color: colors.text, fontSize: 16 }}>{product.title} - {product.localizedPrice}</Text>
824
+ </TouchableOpacity>
825
+ ))}
826
+ {iapPurchase && (
827
+ <Text style={{ color: colors.success, marginTop: 10 }}>Purchase successful!</Text>
828
+ )}
829
+ </Card>
830
+ <GroupedPillButtons
831
+ buttons={[
832
+ {
833
+ text: 'Back',
834
+ onPress: prevStep,
835
+ icon: 'arrow-back',
836
+ variant: 'transparent',
837
+ },
838
+ ]}
839
+ colors={colors}
840
+ />
841
+ </Animated.View>
842
+ );
843
+
844
+ const renderCurrentStep = () => {
845
+ switch (currentStep) {
846
+ case 0: return renderSummaryStep();
847
+ case 1: return renderMethodStep();
848
+ case 2:
849
+ if (paymentMethod === 'googleplay') return renderGooglePlayStep();
850
+ return renderDetailsStep();
851
+ case 3: return renderReviewStep();
852
+ case 4: return renderSuccessStep();
853
+ default: return renderSummaryStep();
854
+ }
855
+ };
856
+
857
+ return (
858
+ <KeyboardAvoidingView
859
+ style={[styles.container, { backgroundColor: colors.background }]}
860
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
861
+ >
862
+ <StatusBar
863
+ barStyle={theme === 'dark' ? 'light-content' : 'dark-content'}
864
+ backgroundColor={colors.background}
865
+ />
866
+ <PaymentGatewayHeader
867
+ currentStep={currentStep}
868
+ totalSteps={5}
869
+ title={stepTitles[currentStep]}
870
+ />
871
+ <ScrollView
872
+ contentContainerStyle={styles.scrollContent}
873
+ showsVerticalScrollIndicator={false}
874
+ keyboardShouldPersistTaps="handled"
875
+ >
876
+ {renderCurrentStep()}
877
+ </ScrollView>
878
+ </KeyboardAvoidingView>
879
+ );
880
+ };
881
+
882
+ const createStyles = (colors: any, theme: string) => StyleSheet.create({
883
+ container: {
884
+ flex: 1,
885
+ },
886
+ scrollContent: {
887
+ flexGrow: 1,
888
+ paddingHorizontal: 24,
889
+ paddingBottom: 20,
890
+ },
891
+ stepContainer: {
892
+ flex: 1,
893
+ justifyContent: 'flex-start',
894
+ alignItems: 'flex-start',
895
+ width: '100%',
896
+ },
897
+ stepIndicatorContainer: {
898
+ flexDirection: 'row',
899
+ justifyContent: 'center',
900
+ alignItems: 'center',
901
+ marginVertical: 16,
902
+ },
903
+ stepIndicator: {
904
+ height: 10,
905
+ borderRadius: 5,
906
+ marginHorizontal: 4,
907
+ },
908
+ stepIndicatorActive: {
909
+ width: 28,
910
+ backgroundColor: colors.primary,
911
+ },
912
+ stepIndicatorInactive: {
913
+ width: 10,
914
+ backgroundColor: colors.border,
915
+ },
916
+ logo: {
917
+ width: 40,
918
+ height: 20,
919
+ alignSelf: 'center',
920
+ resizeMode: 'contain',
921
+ },
922
+ headerTitle: {
923
+ fontFamily: fontFamilies.phuduBold,
924
+ fontSize: 22,
925
+ fontWeight: Platform.OS === 'web' ? 'bold' : undefined,
926
+ color: colors.text,
927
+ letterSpacing: -0.5,
928
+ },
929
+ headerWrapper: {
930
+ flexDirection: 'column',
931
+ alignItems: 'center',
932
+ justifyContent: 'center',
933
+ width: '100%',
934
+ gap: 8,
935
+ paddingVertical: 8,
936
+ },
937
+ card: {
938
+ backgroundColor: '#fff',
939
+ borderRadius: 20,
940
+ padding: 28,
941
+ shadowColor: '#000',
942
+ shadowOffset: { width: 0, height: 2 },
943
+ shadowOpacity: 0.08,
944
+ shadowRadius: 8,
945
+ elevation: 3,
946
+ marginVertical: 8,
947
+ width: '100%',
948
+ alignSelf: 'center',
949
+ },
950
+ paymentMethodButton: {
951
+ flexDirection: 'row',
952
+ alignItems: 'center',
953
+ borderRadius: 16,
954
+ padding: 14,
955
+ marginBottom: 10,
956
+ width: '90%',
957
+ alignSelf: 'center',
958
+ borderWidth: 1,
959
+ },
960
+ paymentMethodButtonActive: {
961
+ backgroundColor: colors.primary + '22',
962
+ borderColor: colors.primary,
963
+ borderWidth: 2,
964
+ },
965
+ paymentMethodButtonInactive: {
966
+ backgroundColor: 'transparent',
967
+ borderColor: colors.border,
968
+ borderWidth: 1,
969
+ },
970
+ paymentMethodLabel: {
971
+ fontFamily: fontFamilies.phudu,
972
+ fontSize: 18,
973
+ color: colors.text,
974
+ fontWeight: '600',
975
+ },
976
+ paymentMethodDescription: {
977
+ fontFamily: fontFamilies.phudu,
978
+ fontSize: 15,
979
+ color: colors.secondaryText,
980
+ marginTop: 8,
981
+ minHeight: 36,
982
+ textAlign: 'center',
983
+ },
984
+ errorContainer: {
985
+ flex: 1,
986
+ justifyContent: 'center',
987
+ alignItems: 'center',
988
+ padding: 32,
989
+ },
990
+ errorText: {
991
+ fontSize: 18,
992
+ color: 'red',
993
+ marginBottom: 24,
994
+ },
995
+ methodListContainer: {
996
+ width: '100%',
997
+ alignItems: 'center',
998
+ },
999
+ methodIcon: {
1000
+ marginRight: 12,
1001
+ },
1002
+ methodCheckIcon: {
1003
+ marginLeft: 'auto',
1004
+ },
1005
+ cardRowInfo: {
1006
+ flexDirection: 'row',
1007
+ alignItems: 'center',
1008
+ marginBottom: 16,
1009
+ },
1010
+ cardRowIcon: {
1011
+ marginRight: 8,
1012
+ },
1013
+ cardRowText: {
1014
+ fontSize: 15,
1015
+ color: colors.secondaryText,
1016
+ },
1017
+ cardFieldContainer: {
1018
+ marginBottom: 16,
1019
+ },
1020
+ cardFieldRow: {
1021
+ flexDirection: 'row',
1022
+ gap: 12,
1023
+ },
1024
+ cardFieldHalfLeft: {
1025
+ flex: 1,
1026
+ marginRight: 6,
1027
+ },
1028
+ cardFieldHalfRight: {
1029
+ flex: 1,
1030
+ marginLeft: 6,
1031
+ },
1032
+ oxyPayContainer: {
1033
+ alignItems: 'center',
1034
+ },
1035
+ oxyPayIcon: {
1036
+ marginBottom: 8,
1037
+ },
1038
+ oxyPayTitle: {
1039
+ fontSize: 16,
1040
+ marginBottom: 8,
1041
+ color: colors.text,
1042
+ fontWeight: '600',
1043
+ textAlign: 'center',
1044
+ },
1045
+ oxyPaySubtitle: {
1046
+ fontSize: 14,
1047
+ color: colors.secondaryText,
1048
+ marginBottom: 8,
1049
+ textAlign: 'center',
1050
+ },
1051
+ oxyPayBalanceBox: {
1052
+ backgroundColor: colors.primary + '22',
1053
+ borderRadius: 12,
1054
+ padding: 8,
1055
+ marginTop: 8,
1056
+ },
1057
+ oxyPayBalanceText: {
1058
+ color: colors.primary,
1059
+ fontWeight: '600',
1060
+ },
1061
+ faircoinContainer: {
1062
+ alignItems: 'center',
1063
+ marginBottom: 24,
1064
+ width: '100%',
1065
+ },
1066
+ faircoinIcon: {
1067
+ marginBottom: 8,
1068
+ },
1069
+ faircoinTitle: {
1070
+ fontSize: 16,
1071
+ marginBottom: 8,
1072
+ color: colors.text,
1073
+ fontWeight: '600',
1074
+ textAlign: 'center',
1075
+ },
1076
+ faircoinQRBox: {
1077
+ width: 160,
1078
+ height: 160,
1079
+ backgroundColor: '#eee',
1080
+ borderRadius: 16,
1081
+ justifyContent: 'center',
1082
+ alignItems: 'center',
1083
+ marginBottom: 12,
1084
+ borderWidth: 2,
1085
+ borderColor: colors.primary,
1086
+ },
1087
+ faircoinQRText: {
1088
+ color: '#aaa',
1089
+ },
1090
+ faircoinWaiting: {
1091
+ fontSize: 14,
1092
+ color: colors.secondaryText,
1093
+ textAlign: 'center',
1094
+ marginBottom: 8,
1095
+ },
1096
+ faircoinPlaceholder: {
1097
+ fontSize: 13,
1098
+ color: colors.secondaryText,
1099
+ textAlign: 'center',
1100
+ },
1101
+ reviewSecureRow: {
1102
+ flexDirection: 'row',
1103
+ alignItems: 'center',
1104
+ marginBottom: 12,
1105
+ },
1106
+ reviewSecureIcon: {
1107
+ marginRight: 8,
1108
+ },
1109
+ reviewSecureText: {
1110
+ color: colors.success || '#4BB543',
1111
+ fontWeight: '600',
1112
+ fontSize: 15,
1113
+ },
1114
+ reviewRow: {
1115
+ flexDirection: 'row',
1116
+ justifyContent: 'space-between',
1117
+ alignItems: 'center',
1118
+ marginBottom: 8,
1119
+ },
1120
+ reviewLabel: {
1121
+ fontSize: 15,
1122
+ color: colors.secondaryText,
1123
+ },
1124
+ reviewValue: {
1125
+ fontSize: 18,
1126
+ fontWeight: '700',
1127
+ color: colors.text,
1128
+ },
1129
+ reviewMethodRow: {
1130
+ flexDirection: 'row',
1131
+ alignItems: 'center',
1132
+ },
1133
+ reviewMethodIcon: {
1134
+ marginRight: 6,
1135
+ },
1136
+ reviewMethodText: {
1137
+ fontSize: 16,
1138
+ color: colors.text,
1139
+ },
1140
+ successContainer: {
1141
+ alignItems: 'center',
1142
+ justifyContent: 'center',
1143
+ marginBottom: 24,
1144
+ width: '100%',
1145
+ },
1146
+ successIconBox: {
1147
+ backgroundColor: colors.success + '22',
1148
+ borderRadius: 48,
1149
+ padding: 18,
1150
+ marginBottom: 12,
1151
+ alignItems: 'center',
1152
+ justifyContent: 'center',
1153
+ },
1154
+ successTitle: {
1155
+ fontSize: 26,
1156
+ fontWeight: '700',
1157
+ color: colors.success || '#4BB543',
1158
+ marginBottom: 8,
1159
+ textAlign: 'center',
1160
+ width: '100%',
1161
+ },
1162
+ successSubtitle: {
1163
+ fontSize: 16,
1164
+ color: colors.text,
1165
+ textAlign: 'center',
1166
+ marginBottom: 8,
1167
+ width: '100%',
1168
+ },
1169
+ methodCard: {
1170
+ flexDirection: 'row',
1171
+ alignItems: 'center',
1172
+ backgroundColor: '#fff',
1173
+ borderRadius: 18,
1174
+ paddingVertical: 18,
1175
+ paddingHorizontal: 18,
1176
+ marginBottom: 14,
1177
+ borderWidth: 1.5,
1178
+ borderColor: colors.border,
1179
+ shadowColor: '#000',
1180
+ shadowOffset: { width: 0, height: 2 },
1181
+ shadowOpacity: 0.06,
1182
+ shadowRadius: 6,
1183
+ elevation: 2,
1184
+ minHeight: 72,
1185
+ },
1186
+ methodCardSelected: {
1187
+ backgroundColor: colors.primary + '11',
1188
+ borderColor: colors.primary,
1189
+ shadowOpacity: 0.13,
1190
+ shadowRadius: 10,
1191
+ elevation: 4,
1192
+ },
1193
+ methodCardContent: {
1194
+ flexDirection: 'row',
1195
+ alignItems: 'center',
1196
+ flex: 1,
1197
+ },
1198
+ methodCardIcon: {
1199
+ marginRight: 18,
1200
+ marginLeft: 2,
1201
+ },
1202
+ methodCardTextContainer: {
1203
+ flex: 1,
1204
+ flexDirection: 'column',
1205
+ justifyContent: 'center',
1206
+ },
1207
+ methodCardDescription: {
1208
+ fontSize: 14,
1209
+ color: colors.secondaryText,
1210
+ marginTop: 2,
1211
+ opacity: 0.85,
1212
+ },
1213
+ methodCardCheckIcon: {
1214
+ marginLeft: 12,
1215
+ },
1216
+ paymentMethodLabelSelected: {
1217
+ color: colors.primary,
1218
+ },
1219
+ circleListContainer: {
1220
+ flexDirection: 'row',
1221
+ flexWrap: 'nowrap',
1222
+ justifyContent: 'center',
1223
+ alignItems: 'flex-start',
1224
+ paddingHorizontal: 4,
1225
+ width: '100%',
1226
+ marginBottom: 0,
1227
+ },
1228
+ circleMethod: {
1229
+ alignItems: 'center',
1230
+ marginHorizontal: 0,
1231
+ flex: 1,
1232
+ minWidth: 62,
1233
+ paddingVertical: 2,
1234
+ paddingHorizontal: 2,
1235
+ },
1236
+ circleMethodSelected: {
1237
+ // No extra margin, but highlight below
1238
+ },
1239
+ circleIconWrapper: {
1240
+ width: 48, // restored padding
1241
+ height: 48, // restored padding
1242
+ borderRadius: 24, // half of width/height
1243
+ backgroundColor: '#fff',
1244
+ borderWidth: 2,
1245
+ borderColor: colors.border,
1246
+ alignItems: 'center',
1247
+ justifyContent: 'center',
1248
+ marginBottom: 8, // spacing below icon
1249
+ shadowColor: '#000',
1250
+ shadowOffset: { width: 0, height: 2 },
1251
+ shadowOpacity: 0.07,
1252
+ shadowRadius: 6,
1253
+ elevation: 2,
1254
+ },
1255
+ circleLabel: {
1256
+ fontFamily: fontFamilies.phudu,
1257
+ fontSize: 16,
1258
+ color: colors.text,
1259
+ fontWeight: '600',
1260
+ textAlign: 'center',
1261
+ marginBottom: 4,
1262
+ marginTop: 2,
1263
+ },
1264
+ circleLabelSelected: {
1265
+ color: colors.primary,
1266
+ },
1267
+ circleDescription: {
1268
+ fontSize: 13,
1269
+ color: colors.secondaryText,
1270
+ textAlign: 'center',
1271
+ opacity: 0.85,
1272
+ minHeight: 36,
1273
+ marginBottom: 2,
1274
+ },
1275
+ circleCheckOverlay: {
1276
+ position: 'absolute',
1277
+ bottom: -8,
1278
+ right: -8,
1279
+ backgroundColor: '#fff',
1280
+ borderRadius: 16,
1281
+ padding: 0,
1282
+ zIndex: 2,
1283
+ },
1284
+ headerStepIndicatorContainer: {
1285
+ marginVertical: 2,
1286
+ flexDirection: 'row',
1287
+ justifyContent: 'center',
1288
+ alignItems: 'center',
1289
+ },
1290
+ faircoinButton: {
1291
+ flexDirection: 'row',
1292
+ alignItems: 'center',
1293
+ alignSelf: 'center',
1294
+ backgroundColor: colors.primary + '11',
1295
+ borderRadius: 16,
1296
+ paddingHorizontal: 16,
1297
+ paddingVertical: 8,
1298
+ marginTop: 6,
1299
+ marginBottom: 2,
1300
+ },
1301
+ faircoinButtonText: {
1302
+ color: colors.primary,
1303
+ fontWeight: '600',
1304
+ fontSize: 15,
1305
+ },
1306
+ faircoinAddress: {
1307
+ color: colors.secondaryText,
1308
+ fontSize: 13,
1309
+ textAlign: 'center',
1310
+ marginTop: 6,
1311
+ marginBottom: 2,
1312
+ },
1313
+ });
1314
+
1315
+ export default PaymentGatewayScreen;