@oxyhq/services 5.7.5 → 5.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/README.md +76 -76
  2. package/lib/commonjs/core/index.js +177 -102
  3. package/lib/commonjs/core/index.js.map +1 -1
  4. package/lib/commonjs/index.js +88 -29
  5. package/lib/commonjs/index.js.map +1 -1
  6. package/lib/commonjs/node/createAuth.js +585 -7
  7. package/lib/commonjs/node/createAuth.js.map +1 -1
  8. package/lib/commonjs/node/index.js +38 -1
  9. package/lib/commonjs/node/index.js.map +1 -1
  10. package/lib/commonjs/ui/components/Avatar.js +15 -6
  11. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  12. package/lib/commonjs/ui/components/GroupedItem.js +58 -13
  13. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
  14. package/lib/commonjs/ui/components/GroupedSection.js +7 -1
  15. package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
  16. package/lib/commonjs/ui/components/Header.js +322 -0
  17. package/lib/commonjs/ui/components/Header.js.map +1 -0
  18. package/lib/commonjs/ui/components/OxyProvider.js +23 -7
  19. package/lib/commonjs/ui/components/OxyProvider.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 +1 -1
  23. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  24. package/lib/commonjs/ui/components/internal/TextField.js +606 -546
  25. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
  26. package/lib/commonjs/ui/components/internal/TextField.md +436 -0
  27. package/lib/commonjs/ui/context/OxyContext.js +122 -78
  28. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  29. package/lib/commonjs/ui/hooks/useSessionSocket.js +5 -2
  30. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  31. package/lib/commonjs/ui/navigation/OxyRouter.js +1 -1
  32. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  33. package/lib/commonjs/ui/screens/AccountCenterScreen.js +6 -6
  34. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  35. package/lib/commonjs/ui/screens/AccountManagementDemo.js +3 -3
  36. package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -1
  37. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +241 -598
  38. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +1151 -406
  40. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  41. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +135 -237
  42. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/AppInfoScreen.js +246 -463
  44. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/FeedbackScreen.js +3 -3
  46. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +808 -650
  48. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/RecoverAccountScreen.js +51 -72
  50. package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
  51. package/lib/commonjs/ui/screens/SessionManagementScreen.js +11 -29
  52. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/SignInScreen.js +30 -303
  54. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  55. package/lib/commonjs/ui/screens/SignUpScreen.js +4 -4
  56. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  57. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +19 -31
  58. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  59. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +7 -10
  60. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  61. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js +11 -5
  62. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
  63. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js +11 -4
  64. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
  65. package/lib/commonjs/ui/stores/authStore.js +12 -0
  66. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  67. package/lib/commonjs/ui/styles/authStyles.js +337 -0
  68. package/lib/commonjs/ui/styles/authStyles.js.map +1 -0
  69. package/lib/commonjs/ui/styles/index.js +11 -0
  70. package/lib/commonjs/ui/styles/index.js.map +1 -1
  71. package/lib/module/core/index.js +177 -41
  72. package/lib/module/core/index.js.map +1 -1
  73. package/lib/module/index.js +26 -4
  74. package/lib/module/index.js.map +1 -1
  75. package/lib/module/node/createAuth.js +584 -7
  76. package/lib/module/node/createAuth.js.map +1 -1
  77. package/lib/module/node/index.js +7 -1
  78. package/lib/module/node/index.js.map +1 -1
  79. package/lib/module/ui/components/Avatar.js +15 -6
  80. package/lib/module/ui/components/Avatar.js.map +1 -1
  81. package/lib/module/ui/components/GroupedItem.js +59 -14
  82. package/lib/module/ui/components/GroupedItem.js.map +1 -1
  83. package/lib/module/ui/components/GroupedSection.js +7 -1
  84. package/lib/module/ui/components/GroupedSection.js.map +1 -1
  85. package/lib/module/ui/components/Header.js +317 -0
  86. package/lib/module/ui/components/Header.js.map +1 -0
  87. package/lib/module/ui/components/OxyProvider.js +25 -9
  88. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  89. package/lib/module/ui/components/index.js +1 -0
  90. package/lib/module/ui/components/index.js.map +1 -1
  91. package/lib/module/ui/components/internal/GroupedPillButtons.js +1 -1
  92. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  93. package/lib/module/ui/components/internal/TextField.js +607 -547
  94. package/lib/module/ui/components/internal/TextField.js.map +1 -1
  95. package/lib/module/ui/components/internal/TextField.md +436 -0
  96. package/lib/module/ui/context/OxyContext.js +121 -77
  97. package/lib/module/ui/context/OxyContext.js.map +1 -1
  98. package/lib/module/ui/hooks/useSessionSocket.js +5 -2
  99. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  100. package/lib/module/ui/navigation/OxyRouter.js +1 -1
  101. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  102. package/lib/module/ui/screens/AccountCenterScreen.js +6 -6
  103. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  104. package/lib/module/ui/screens/AccountManagementDemo.js +3 -3
  105. package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -1
  106. package/lib/module/ui/screens/AccountOverviewScreen.js +242 -597
  107. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  108. package/lib/module/ui/screens/AccountSettingsScreen.js +1152 -407
  109. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  110. package/lib/module/ui/screens/AccountSwitcherScreen.js +135 -237
  111. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  112. package/lib/module/ui/screens/AppInfoScreen.js +248 -465
  113. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  114. package/lib/module/ui/screens/FeedbackScreen.js +3 -3
  115. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  116. package/lib/module/ui/screens/PaymentGatewayScreen.js +809 -651
  117. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  118. package/lib/module/ui/screens/RecoverAccountScreen.js +53 -74
  119. package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
  120. package/lib/module/ui/screens/SessionManagementScreen.js +11 -29
  121. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  122. package/lib/module/ui/screens/SignInScreen.js +32 -305
  123. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  124. package/lib/module/ui/screens/SignUpScreen.js +5 -5
  125. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  126. package/lib/module/ui/screens/internal/SignInPasswordStep.js +19 -31
  127. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  128. package/lib/module/ui/screens/internal/SignInUsernameStep.js +7 -10
  129. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  130. package/lib/module/ui/screens/internal/SignUpIdentityStep.js +11 -5
  131. package/lib/module/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
  132. package/lib/module/ui/screens/internal/SignUpSecurityStep.js +11 -4
  133. package/lib/module/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
  134. package/lib/module/ui/stores/authStore.js +12 -0
  135. package/lib/module/ui/stores/authStore.js.map +1 -1
  136. package/lib/module/ui/styles/authStyles.js +332 -0
  137. package/lib/module/ui/styles/authStyles.js.map +1 -0
  138. package/lib/module/ui/styles/index.js +1 -0
  139. package/lib/module/ui/styles/index.js.map +1 -1
  140. package/lib/typescript/core/index.d.ts +68 -24
  141. package/lib/typescript/core/index.d.ts.map +1 -1
  142. package/lib/typescript/index.d.ts +13 -3
  143. package/lib/typescript/index.d.ts.map +1 -1
  144. package/lib/typescript/node/createAuth.d.ts +112 -0
  145. package/lib/typescript/node/createAuth.d.ts.map +1 -1
  146. package/lib/typescript/node/index.d.ts +2 -0
  147. package/lib/typescript/node/index.d.ts.map +1 -1
  148. package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
  149. package/lib/typescript/ui/components/GroupedItem.d.ts +6 -0
  150. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
  151. package/lib/typescript/ui/components/GroupedSection.d.ts +6 -0
  152. package/lib/typescript/ui/components/GroupedSection.d.ts.map +1 -1
  153. package/lib/typescript/ui/components/Header.d.ts +22 -0
  154. package/lib/typescript/ui/components/Header.d.ts.map +1 -0
  155. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  156. package/lib/typescript/ui/components/index.d.ts +1 -0
  157. package/lib/typescript/ui/components/index.d.ts.map +1 -1
  158. package/lib/typescript/ui/components/internal/TextField.d.ts +31 -16
  159. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
  160. package/lib/typescript/ui/context/OxyContext.d.ts +5 -2
  161. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  162. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
  163. package/lib/typescript/ui/navigation/types.d.ts +9 -2
  164. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  165. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  166. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  167. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  168. package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
  169. package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  170. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts +5 -1
  171. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
  172. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  173. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  174. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +1 -1
  175. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
  176. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +0 -1
  177. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
  178. package/lib/typescript/ui/screens/internal/SignUpIdentityStep.d.ts.map +1 -1
  179. package/lib/typescript/ui/screens/internal/SignUpSecurityStep.d.ts.map +1 -1
  180. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  181. package/lib/typescript/ui/styles/authStyles.d.ts +326 -0
  182. package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -0
  183. package/lib/typescript/ui/styles/index.d.ts +1 -0
  184. package/lib/typescript/ui/styles/index.d.ts.map +1 -1
  185. package/package.json +1 -4
  186. package/src/core/index.ts +195 -41
  187. package/src/index.ts +72 -4
  188. package/src/node/createAuth.ts +623 -7
  189. package/src/node/index.ts +19 -1
  190. package/src/ui/components/Avatar.tsx +11 -5
  191. package/src/ui/components/GroupedItem.tsx +57 -9
  192. package/src/ui/components/GroupedSection.tsx +12 -0
  193. package/src/ui/components/Header.tsx +364 -0
  194. package/src/ui/components/OxyProvider.tsx +31 -15
  195. package/src/ui/components/index.ts +1 -0
  196. package/src/ui/components/internal/GroupedPillButtons.tsx +1 -1
  197. package/src/ui/components/internal/TextField.md +436 -0
  198. package/src/ui/components/internal/TextField.tsx +720 -620
  199. package/src/ui/context/OxyContext.tsx +150 -63
  200. package/src/ui/hooks/useSessionSocket.ts +5 -2
  201. package/src/ui/navigation/OxyRouter.tsx +1 -1
  202. package/src/ui/navigation/types.ts +10 -2
  203. package/src/ui/screens/AccountCenterScreen.tsx +5 -5
  204. package/src/ui/screens/AccountManagementDemo.tsx +9 -9
  205. package/src/ui/screens/AccountOverviewScreen.tsx +265 -414
  206. package/src/ui/screens/AccountSettingsScreen.tsx +1165 -403
  207. package/src/ui/screens/AccountSwitcherScreen.tsx +158 -202
  208. package/src/ui/screens/AppInfoScreen.tsx +270 -497
  209. package/src/ui/screens/FeedbackScreen.tsx +3 -3
  210. package/src/ui/screens/PaymentGatewayScreen.tsx +668 -365
  211. package/src/ui/screens/ProfileScreen.tsx +5 -5
  212. package/src/ui/screens/RecoverAccountScreen.tsx +46 -74
  213. package/src/ui/screens/SessionManagementScreen.tsx +14 -22
  214. package/src/ui/screens/SignInScreen.tsx +27 -294
  215. package/src/ui/screens/SignUpScreen.tsx +5 -5
  216. package/src/ui/screens/internal/SignInPasswordStep.tsx +11 -22
  217. package/src/ui/screens/internal/SignInUsernameStep.tsx +3 -10
  218. package/src/ui/screens/internal/SignUpIdentityStep.tsx +2 -5
  219. package/src/ui/screens/internal/SignUpSecurityStep.tsx +3 -4
  220. package/src/ui/stores/authStore.ts +12 -0
  221. package/src/ui/styles/authStyles.ts +352 -0
  222. package/src/ui/styles/index.ts +1 -0
  223. package/lib/commonjs/core/auth-manager.js +0 -440
  224. package/lib/commonjs/core/auth-manager.js.map +0 -1
  225. package/lib/commonjs/core/use-auth.js +0 -244
  226. package/lib/commonjs/core/use-auth.js.map +0 -1
  227. package/lib/module/core/auth-manager.js +0 -432
  228. package/lib/module/core/auth-manager.js.map +0 -1
  229. package/lib/module/core/use-auth.js +0 -235
  230. package/lib/module/core/use-auth.js.map +0 -1
  231. package/lib/typescript/core/auth-manager.d.ts +0 -136
  232. package/lib/typescript/core/auth-manager.d.ts.map +0 -1
  233. package/lib/typescript/core/use-auth.d.ts +0 -79
  234. package/lib/typescript/core/use-auth.d.ts.map +0 -1
  235. package/src/__tests__/middleware.test.ts +0 -105
  236. package/src/__tests__/setup.ts +0 -10
  237. package/src/__tests__/zero-config-auth.test.ts +0 -607
  238. package/src/core/auth-manager.ts +0 -500
  239. package/src/core/use-auth.tsx +0 -245
@@ -25,6 +25,7 @@ import { FAIRWalletIcon } from '../components/icon';
25
25
  import { toast } from 'sonner';
26
26
  import QRCode from 'react-native-qrcode-svg';
27
27
  import * as RNIap from 'react-native-iap';
28
+ import { GroupedSection } from '../components';
28
29
 
29
30
  // Restrict payment methods to Card, Oxy Pay, and FairCoin (QR)
30
31
  const PAYMENT_METHODS = [
@@ -209,12 +210,12 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
209
210
  Animated.timing(scaleAnim, {
210
211
  toValue: 0.95,
211
212
  duration: 150,
212
- useNativeDriver: true,
213
+ useNativeDriver: Platform.OS !== 'web',
213
214
  }).start();
214
215
  Animated.timing(fadeAnim, {
215
216
  toValue: 0,
216
217
  duration: 200,
217
- useNativeDriver: true,
218
+ useNativeDriver: Platform.OS !== 'web',
218
219
  }).start(() => {
219
220
  setCurrentStep(nextStep);
220
221
  slideAnim.setValue(-50);
@@ -223,19 +224,19 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
223
224
  Animated.timing(fadeAnim, {
224
225
  toValue: 1,
225
226
  duration: 300,
226
- useNativeDriver: true,
227
+ useNativeDriver: Platform.OS !== 'web',
227
228
  }),
228
229
  Animated.spring(slideAnim, {
229
230
  toValue: 0,
230
231
  tension: 80,
231
232
  friction: 8,
232
- useNativeDriver: true,
233
+ useNativeDriver: Platform.OS !== 'web',
233
234
  }),
234
235
  Animated.spring(scaleAnim, {
235
236
  toValue: 1,
236
237
  tension: 80,
237
238
  friction: 8,
238
- useNativeDriver: true,
239
+ useNativeDriver: Platform.OS !== 'web',
239
240
  })
240
241
  ]).start();
241
242
  });
@@ -409,69 +410,11 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
409
410
  'Review & Pay',
410
411
  'Success',
411
412
  ];
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
413
 
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
414
 
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
- };
415
+
416
+
417
+
475
418
 
476
419
  // Step 1: Summary step (new first step, no header/dots here)
477
420
  const renderSummaryStep = () => (
@@ -483,46 +426,97 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
483
426
  ]
484
427
  }]}
485
428
  >
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)}
429
+ <View style={styles.section}>
430
+ <Text style={styles.sectionTitle}>Payment Summary</Text>
431
+
432
+ <View style={styles.summaryCard}>
433
+ <View style={styles.summaryCardContent}>
434
+ <Ionicons name="receipt-outline" size={64} color={colors.primary} style={styles.summaryCardIcon} />
435
+ <Text style={styles.summaryCardMainTitle}>
436
+ {paymentItems && paymentItems.length > 0 ? 'Order Summary' : 'Payment'}
437
+ </Text>
438
+ <Text style={styles.summaryCardSubtitle}>
439
+ {paymentItems && paymentItems.length > 0 ? 'Review your payment details' : 'Complete your payment'}
503
440
  </Text>
441
+
442
+ {paymentItems && paymentItems.length > 0 ? (
443
+ <>
444
+ <View style={styles.summaryCardItems}>
445
+ <GroupedSection
446
+ items={paymentItems.map((item, idx) => ({
447
+ id: `item-${idx}`,
448
+ icon: getItemTypeIcon(item.type, colors.primary).props.name,
449
+ iconColor: colors.primary,
450
+ title: `${item.type === 'product' && item.quantity ? `${item.quantity} × ` : ''}${item.name}${item.type === 'subscription' && item.period ? ` (${item.period})` : ''}`,
451
+ subtitle: item.description || `${(item.currency ? (CURRENCY_SYMBOLS[item.currency.toUpperCase()] || item.currency) : currencySymbol)} ${item.price * (item.quantity ?? 1)}`,
452
+ customContent: (
453
+ <Text style={styles.summaryItemPrice}>
454
+ {(item.currency ? (CURRENCY_SYMBOLS[item.currency.toUpperCase()] || item.currency) : currencySymbol)} {item.price * (item.quantity ?? 1)}
455
+ </Text>
456
+ ),
457
+ }))}
458
+ theme={theme}
459
+ />
460
+ </View>
461
+
462
+ <View style={styles.summaryCardDivider} />
463
+
464
+ <View style={styles.summaryCardTotalSection}>
465
+ <View style={styles.summaryCardTotalRow}>
466
+ <Text style={styles.summaryCardTotalLabel}>Subtotal</Text>
467
+ <Text style={styles.summaryCardTotalValue}>{(currencySymbol)} {amount}</Text>
468
+ </View>
469
+ <View style={styles.summaryCardTotalRow}>
470
+ <Text style={styles.summaryCardTotalLabel}>Tax</Text>
471
+ <Text style={styles.summaryCardTotalValue}>{(currencySymbol)} 0.00</Text>
472
+ </View>
473
+ <View style={styles.summaryCardTotalRow}>
474
+ <Text style={styles.summaryCardTotalLabel}>Total</Text>
475
+ <Text style={styles.summaryCardTotalValue}>{(currencySymbol)} {amount}</Text>
476
+ </View>
477
+ </View>
478
+ </>
479
+ ) : (
480
+ <>
481
+ <View style={styles.summaryCardAmount}>
482
+ <Text style={styles.summaryCardAmountLabel}>Amount to Pay</Text>
483
+ <Text style={styles.summaryCardAmountValue}>{(currencySymbol)} {amount}</Text>
484
+ {description && (
485
+ <Text style={styles.summaryCardAmountDescription}>{description}</Text>
486
+ )}
487
+ </View>
488
+
489
+ <View style={styles.summaryCardDivider} />
490
+
491
+ <View style={styles.summaryCardTotalSection}>
492
+ <View style={styles.summaryCardTotalRow}>
493
+ <Text style={styles.summaryCardTotalLabel}>Total</Text>
494
+ <Text style={styles.summaryCardTotalValue}>{(currencySymbol)} {amount}</Text>
495
+ </View>
496
+ </View>
497
+ </>
498
+ )}
504
499
  </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>
500
+ </View>
501
+ </View>
502
+
503
+ <GroupedPillButtons
504
+ buttons={[
505
+ {
506
+ text: 'Close',
507
+ onPress: handleClose,
508
+ icon: 'close',
509
+ variant: 'transparent',
510
+ },
511
+ {
512
+ text: 'Continue',
513
+ onPress: nextStep,
514
+ icon: 'arrow-forward',
515
+ variant: 'primary',
516
+ },
517
+ ]}
518
+ colors={colors}
519
+ />
526
520
  </Animated.View>
527
521
  );
528
522
 
@@ -536,39 +530,29 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
536
530
  ]
537
531
  }]}
538
532
  >
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>
533
+ <View style={styles.section}>
534
+ <Text style={styles.sectionTitle}>Choose Payment Method</Text>
535
+
536
+ <GroupedSection
537
+ items={availablePaymentMethods.map(method => ({
538
+ id: method.key,
539
+ icon: method.key === 'faircoin' ? undefined : method.icon,
540
+ iconColor: method.key === 'card' ? '#007AFF' :
541
+ method.key === 'oxy' ? '#32D74B' :
542
+ method.key === 'faircoin' ? '#9ffb50' : colors.primary,
543
+ title: method.label,
544
+ subtitle: method.description,
545
+ onPress: () => setPaymentMethod(method.key),
546
+ selected: paymentMethod === method.key,
547
+ showChevron: false,
548
+ customIcon: method.key === 'faircoin' ? (
549
+ <FAIRWalletIcon size={20} />
550
+ ) : undefined,
551
+ }))}
552
+ theme={theme}
553
+ />
554
+ </View>
555
+
572
556
  <GroupedPillButtons
573
557
  buttons={[
574
558
  {
@@ -599,87 +583,123 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
599
583
  ]
600
584
  }]}
601
585
  >
602
- <Card
603
- style={paymentMethod === 'faircoin' ? { backgroundColor: '#f6fff0', paddingVertical: 24, paddingHorizontal: 0 } : undefined}
604
- >
586
+ <View style={styles.section}>
587
+ <Text style={styles.sectionTitle}>
588
+ {paymentMethod === 'card' ? 'Card Details' :
589
+ paymentMethod === 'oxy' ? 'Oxy Pay' :
590
+ paymentMethod === 'faircoin' ? 'FairCoin Payment' : 'Payment Details'}
591
+ </Text>
592
+
605
593
  {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
- />
594
+ <View style={styles.cardPaymentCard}>
595
+ <View style={styles.cardPaymentContent}>
596
+ <Ionicons name="card-outline" size={64} color={colors.primary} style={styles.cardPaymentIcon} />
597
+ <Text style={styles.cardPaymentMainTitle}>Credit Card</Text>
598
+ <Text style={styles.cardPaymentSubtitle}>Enter your card details securely</Text>
599
+
600
+ <View style={styles.cardPaymentFields}>
601
+ <View style={styles.cardRowInfo}>
602
+ <Ionicons name="card-outline" size={24} color={colors.primary} style={styles.cardRowIcon} />
603
+ <Text style={styles.cardRowText}>We accept Visa, Mastercard, and more</Text>
604
+ </View>
605
+ <TextField
606
+ value={cardDetails.number}
607
+ onChangeText={text => {
608
+ // Format card number with spaces
609
+ const formatted = text.replace(/\s/g, '').replace(/(\d{4})/g, '$1 ').trim();
610
+ setCardDetails({ ...cardDetails, number: formatted });
611
+ }}
612
+ placeholder="1234 5678 9012 3456"
613
+ keyboardType="numeric"
614
+ maxLength={19}
615
+ style={styles.cardFieldContainer}
616
+ leading={<Ionicons name="card-outline" size={18} color={colors.primary} />}
617
+ />
618
+ <View style={styles.cardFieldRow}>
619
+ <TextField
620
+ value={cardDetails.expiry}
621
+ onChangeText={text => {
622
+ // Format expiry date
623
+ const formatted = text.replace(/\D/g, '').replace(/(\d{2})(\d)/, '$1/$2');
624
+ setCardDetails({ ...cardDetails, expiry: formatted });
625
+ }}
626
+ placeholder="MM/YY"
627
+ maxLength={5}
628
+ style={styles.cardFieldHalfLeft}
629
+ leading={<Ionicons name="calendar-outline" size={16} color={colors.primary} />}
630
+ />
631
+ <TextField
632
+ value={cardDetails.cvv}
633
+ onChangeText={text => {
634
+ // Only allow numbers
635
+ const formatted = text.replace(/\D/g, '');
636
+ setCardDetails({ ...cardDetails, cvv: formatted });
637
+ }}
638
+ placeholder="123"
639
+ keyboardType="numeric"
640
+ maxLength={4}
641
+ style={styles.cardFieldHalfRight}
642
+ leading={<Ionicons name="lock-closed-outline" size={16} color={colors.primary} />}
643
+ />
644
+ </View>
645
+ </View>
646
+
647
+ <View style={{ height: 18 }} />
648
+ <Text style={styles.cardPaymentWaiting}>Ready to process payment...</Text>
635
649
  </View>
636
- </>
650
+ </View>
637
651
  )}
638
652
  {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>
653
+ <View style={styles.oxyPayCard}>
654
+ <View style={styles.oxyPayContent}>
655
+ <Ionicons name="wallet-outline" size={64} color={colors.primary} style={styles.oxyPayIcon} />
656
+ <Text style={styles.oxyPayMainTitle}>Oxy Pay</Text>
657
+ <Text style={styles.oxyPaySubtitle}>Pay with your in-app wallet</Text>
658
+ <View style={styles.oxyPayBalanceBox}>
659
+ <Text style={styles.oxyPayBalanceText}>Balance: ⊜ 123.45</Text>
660
+ </View>
661
+ <View style={{ height: 18 }} />
662
+ <Text style={styles.oxyPayWaiting}>Ready to process payment...</Text>
645
663
  </View>
646
664
  </View>
647
665
  )}
648
666
  {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} />
667
+ <View style={styles.faircoinCard}>
668
+ <View style={styles.faircoinContent}>
669
+ <FAIRWalletIcon size={64} style={styles.faircoinIcon} />
670
+ <Text style={styles.faircoinMainTitle}>FAIRWallet</Text>
671
+ <Text style={styles.faircoinSubtitle}>Pay with FairCoin</Text>
672
+ {!isMobile ? (
673
+ <>
674
+ <Text style={styles.faircoinScanText}>Scan to Pay</Text>
675
+ <View style={styles.faircoinQRCard}>
676
+ <QRCode value={faircoinAddress} size={qrSize - 32} />
677
+ <View style={styles.faircoinQRBadge}>
678
+ <FAIRWalletIcon size={28} />
679
+ </View>
660
680
  </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>
681
+ </>
682
+ ) : (
683
+ <>
684
+ <Text style={styles.faircoinTitle}>Use the options below to pay with FAIRWallet</Text>
685
+ <Text style={styles.faircoinAddress}>{faircoinAddress}</Text>
686
+ <TouchableOpacity style={[styles.faircoinButton, { backgroundColor: '#9ffb50', borderRadius: 18, marginTop: 12, width: '90%', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }]} onPress={handleOpenFairWallet}>
687
+ <FAIRWalletIcon size={20} style={{ marginRight: 8 }} />
688
+ <Text style={[styles.faircoinButtonText, { color: '#1b1f0a', fontWeight: 'bold', fontSize: 16 }]}>Open in FAIRWallet</Text>
689
+ </TouchableOpacity>
690
+ <TouchableOpacity style={[styles.faircoinButton, { backgroundColor: '#9ffb50', borderRadius: 18, marginTop: 10, width: '90%', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }]} onPress={handleCopyAddress}>
691
+ <FAIRWalletIcon size={20} style={{ marginRight: 8 }} />
692
+ <Text style={[styles.faircoinButtonText, { color: '#1b1f0a', fontWeight: 'bold', fontSize: 16 }]}>Copy Address</Text>
693
+ </TouchableOpacity>
694
+ </>
695
+ )}
696
+ <View style={{ height: 18 }} />
697
+ <Text style={styles.faircoinWaiting}>Waiting for payment...</Text>
698
+ <Text style={styles.faircoinPlaceholder}>(This is a placeholder. Integrate with a QR code generator for production.)</Text>
699
+ </View>
680
700
  </View>
681
701
  )}
682
- </Card>
702
+ </View>
683
703
  <GroupedPillButtons
684
704
  buttons={[
685
705
  {
@@ -712,41 +732,57 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
712
732
  ]
713
733
  }]}
714
734
  >
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>
735
+ <View style={styles.section}>
736
+ <Text style={styles.sectionTitle}>Review Payment</Text>
737
+
738
+ <GroupedSection
739
+ items={[
740
+ {
741
+ id: 'secure-payment',
742
+ icon: 'shield-checkmark',
743
+ iconColor: colors.success || '#4BB543',
744
+ title: 'Secure payment',
745
+ subtitle: 'Your payment is protected by industry-standard encryption',
746
+ },
747
+ {
748
+ id: 'amount',
749
+ icon: 'cash',
750
+ iconColor: colors.primary,
751
+ title: 'Amount',
752
+ subtitle: `${currencySymbol} ${amount}`,
753
+ },
754
+ {
755
+ id: 'payment-method',
756
+ icon: PAYMENT_METHODS.find(m => m.key === paymentMethod)?.icon as any,
757
+ iconColor: colors.primary,
758
+ title: 'Payment Method',
759
+ subtitle: PAYMENT_METHODS.find(m => m.key === paymentMethod)?.label,
760
+ },
761
+ ...(paymentMethod === 'card' ? [{
762
+ id: 'card-details',
763
+ icon: 'card',
764
+ iconColor: colors.primary,
765
+ title: 'Card',
766
+ subtitle: cardDetails.number.replace(/.(?=.{4})/g, '*'),
767
+ }] : []),
768
+ ...(paymentMethod === 'oxy' ? [{
769
+ id: 'oxy-balance',
770
+ icon: 'wallet',
771
+ iconColor: colors.primary,
772
+ title: 'Oxy Pay Account',
773
+ subtitle: 'Balance: ⊜ 123.45',
774
+ }] : []),
775
+ ...(paymentMethod === 'faircoin' ? [{
776
+ id: 'faircoin-wallet',
777
+ icon: 'qr-code',
778
+ iconColor: colors.primary,
779
+ title: 'FairCoin Wallet',
780
+ subtitle: 'Paid via QR',
781
+ }] : []),
782
+ ]}
783
+ theme={theme}
784
+ />
785
+ </View>
750
786
  <GroupedPillButtons
751
787
  buttons={[
752
788
  {
@@ -778,12 +814,18 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
778
814
  ]
779
815
  }]}
780
816
  >
781
- <View style={styles.successContainer}>
782
- <View style={styles.successIconBox}>
783
- <Ionicons name="checkmark-circle" size={64} color={colors.success || '#4BB543'} />
817
+ <View style={styles.section}>
818
+ <Text style={styles.sectionTitle}>Payment Complete</Text>
819
+
820
+ <View style={styles.successCard}>
821
+ <View style={styles.successContent}>
822
+ <Ionicons name="checkmark-circle" size={64} color={colors.success || '#4BB543'} style={styles.successIcon} />
823
+ <Text style={styles.successMainTitle}>Payment Successful!</Text>
824
+ <Text style={styles.successSubtitle}>Thank you for your payment.</Text>
825
+ <View style={{ height: 18 }} />
826
+ <Text style={styles.successMessage}>Your transaction has been processed successfully.</Text>
827
+ </View>
784
828
  </View>
785
- <Text style={styles.successTitle}>Payment Successful!</Text>
786
- <Text style={styles.successSubtitle}>Thank you for your payment.</Text>
787
829
  </View>
788
830
  <GroupedPillButtons
789
831
  buttons={[
@@ -809,24 +851,42 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
809
851
  ]
810
852
  }]}
811
853
  >
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
- ))}
854
+ <View style={styles.section}>
855
+ <Text style={styles.sectionTitle}>Google Play Products</Text>
856
+
857
+ {iapLoading && (
858
+ <View style={styles.loadingContainer}>
859
+ <Text style={styles.loadingText}>Loading products...</Text>
860
+ </View>
861
+ )}
862
+
863
+ {iapError && (
864
+ <View style={styles.paymentErrorContainer}>
865
+ <Text style={styles.paymentErrorText}>{iapError}</Text>
866
+ </View>
867
+ )}
868
+
869
+ {!iapLoading && !iapError && (
870
+ <GroupedSection
871
+ items={iapProducts.map(product => ({
872
+ id: product.productId,
873
+ icon: 'pricetag',
874
+ iconColor: colors.primary,
875
+ title: product.title,
876
+ subtitle: product.localizedPrice,
877
+ onPress: () => handleIapBuy(product.productId),
878
+ disabled: iapLoading,
879
+ }))}
880
+ theme={theme}
881
+ />
882
+ )}
883
+
826
884
  {iapPurchase && (
827
- <Text style={{ color: colors.success, marginTop: 10 }}>Purchase successful!</Text>
885
+ <View style={styles.iapSuccessContainer}>
886
+ <Text style={styles.iapSuccessText}>Purchase successful!</Text>
887
+ </View>
828
888
  )}
829
- </Card>
889
+ </View>
830
890
  <GroupedPillButtons
831
891
  buttons={[
832
892
  {
@@ -854,28 +914,23 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
854
914
  }
855
915
  };
856
916
 
917
+ // Memoize theme-related calculations to prevent unnecessary recalculations
918
+ const themeStyles = useMemo(() => {
919
+ const isDarkTheme = theme === 'dark';
920
+ return {
921
+ isDarkTheme,
922
+ backgroundColor: isDarkTheme ? '#121212' : '#f2f2f2',
923
+ primaryColor: '#007AFF',
924
+ };
925
+ }, [theme]);
926
+
857
927
  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
- >
928
+ <View style={[styles.container, { backgroundColor: themeStyles.backgroundColor }]}>
929
+ {/* Content */}
930
+ <ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
876
931
  {renderCurrentStep()}
877
932
  </ScrollView>
878
- </KeyboardAvoidingView>
933
+ </View>
879
934
  );
880
935
  };
881
936
 
@@ -883,17 +938,26 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
883
938
  container: {
884
939
  flex: 1,
885
940
  },
886
- scrollContent: {
887
- flexGrow: 1,
888
- paddingHorizontal: 24,
889
- paddingBottom: 20,
941
+ content: {
942
+ flex: 1,
943
+ padding: 16,
890
944
  },
891
945
  stepContainer: {
892
- flex: 1,
893
946
  justifyContent: 'flex-start',
894
947
  alignItems: 'flex-start',
895
948
  width: '100%',
896
949
  },
950
+ section: {
951
+ marginBottom: 24,
952
+ width: '100%',
953
+ },
954
+ sectionTitle: {
955
+ fontSize: 16,
956
+ fontWeight: '600',
957
+ color: colors.text,
958
+ marginBottom: 12,
959
+ fontFamily: fontFamilies.phuduSemiBold,
960
+ },
897
961
  stepIndicatorContainer: {
898
962
  flexDirection: 'row',
899
963
  justifyContent: 'center',
@@ -926,27 +990,7 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
926
990
  color: colors.text,
927
991
  letterSpacing: -0.5,
928
992
  },
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
- },
993
+
950
994
  paymentMethodButton: {
951
995
  flexDirection: 'row',
952
996
  alignItems: 'center',
@@ -1058,6 +1102,33 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
1058
1102
  color: colors.primary,
1059
1103
  fontWeight: '600',
1060
1104
  },
1105
+ oxyPayCard: {
1106
+ backgroundColor: '#fff',
1107
+ borderRadius: 16,
1108
+ padding: 24,
1109
+ marginBottom: 24,
1110
+ alignItems: 'center',
1111
+ width: '100%',
1112
+ },
1113
+ oxyPayContent: {
1114
+ alignItems: 'center',
1115
+ width: '100%',
1116
+ },
1117
+ oxyPayMainTitle: {
1118
+ fontFamily: fontFamilies.phuduBold,
1119
+ fontWeight: 'bold',
1120
+ fontSize: 28,
1121
+ color: colors.text,
1122
+ marginBottom: 2,
1123
+ textAlign: 'center',
1124
+ letterSpacing: 0.5,
1125
+ },
1126
+ oxyPayWaiting: {
1127
+ fontSize: 14,
1128
+ color: colors.secondaryText,
1129
+ textAlign: 'center',
1130
+ marginBottom: 8,
1131
+ },
1061
1132
  faircoinContainer: {
1062
1133
  alignItems: 'center',
1063
1134
  marginBottom: 24,
@@ -1066,6 +1137,60 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
1066
1137
  faircoinIcon: {
1067
1138
  marginBottom: 8,
1068
1139
  },
1140
+ faircoinMainTitle: {
1141
+ fontFamily: fontFamilies.phuduBold,
1142
+ fontWeight: 'bold',
1143
+ fontSize: 28,
1144
+ color: '#1b1f0a',
1145
+ marginBottom: 2,
1146
+ textAlign: 'center',
1147
+ letterSpacing: 0.5,
1148
+ },
1149
+ faircoinSubtitle: {
1150
+ color: '#1b1f0a',
1151
+ fontWeight: '700',
1152
+ fontSize: 17,
1153
+ marginBottom: 18,
1154
+ textAlign: 'center',
1155
+ letterSpacing: 0.2,
1156
+ },
1157
+ faircoinScanText: {
1158
+ color: '#1b1f0a',
1159
+ fontWeight: '600',
1160
+ fontSize: 15,
1161
+ marginBottom: 8,
1162
+ },
1163
+ faircoinQRCard: {
1164
+ width: 200,
1165
+ height: 200,
1166
+ backgroundColor: '#fff',
1167
+ borderRadius: 32,
1168
+ justifyContent: 'center',
1169
+ alignItems: 'center',
1170
+ marginBottom: 16,
1171
+ padding: 16,
1172
+ borderWidth: 3,
1173
+ borderColor: '#9ffb50',
1174
+ shadowColor: '#9ffb50',
1175
+ shadowOffset: { width: 0, height: 4 },
1176
+ shadowOpacity: 0.25,
1177
+ shadowRadius: 12,
1178
+ elevation: 8,
1179
+ position: 'relative',
1180
+ },
1181
+ faircoinQRBadge: {
1182
+ position: 'absolute',
1183
+ bottom: 12,
1184
+ right: 12,
1185
+ backgroundColor: '#fff',
1186
+ borderRadius: 16,
1187
+ padding: 4,
1188
+ shadowColor: '#000',
1189
+ shadowOffset: { width: 0, height: 2 },
1190
+ shadowOpacity: 0.1,
1191
+ shadowRadius: 4,
1192
+ elevation: 2,
1193
+ },
1069
1194
  faircoinTitle: {
1070
1195
  fontSize: 16,
1071
1196
  marginBottom: 8,
@@ -1098,66 +1223,42 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
1098
1223
  color: colors.secondaryText,
1099
1224
  textAlign: 'center',
1100
1225
  },
1101
- reviewSecureRow: {
1102
- flexDirection: 'row',
1226
+ faircoinCard: {
1227
+ backgroundColor: '#fff',
1228
+ borderRadius: 16,
1229
+ padding: 24,
1230
+ marginBottom: 24,
1103
1231
  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,
1232
+ width: '100%',
1113
1233
  },
1114
- reviewRow: {
1115
- flexDirection: 'row',
1116
- justifyContent: 'space-between',
1234
+ faircoinContent: {
1117
1235
  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,
1236
+ width: '100%',
1128
1237
  },
1129
- reviewMethodRow: {
1130
- flexDirection: 'row',
1238
+
1239
+ successCard: {
1240
+ backgroundColor: '#fff',
1241
+ borderRadius: 16,
1242
+ padding: 24,
1243
+ marginBottom: 24,
1131
1244
  alignItems: 'center',
1245
+ width: '100%',
1132
1246
  },
1133
- reviewMethodIcon: {
1134
- marginRight: 6,
1135
- },
1136
- reviewMethodText: {
1137
- fontSize: 16,
1138
- color: colors.text,
1139
- },
1140
- successContainer: {
1247
+ successContent: {
1141
1248
  alignItems: 'center',
1142
- justifyContent: 'center',
1143
- marginBottom: 24,
1144
1249
  width: '100%',
1145
1250
  },
1146
- successIconBox: {
1147
- backgroundColor: colors.success + '22',
1148
- borderRadius: 48,
1149
- padding: 18,
1150
- marginBottom: 12,
1151
- alignItems: 'center',
1152
- justifyContent: 'center',
1251
+ successIcon: {
1252
+ marginBottom: 8,
1153
1253
  },
1154
- successTitle: {
1155
- fontSize: 26,
1156
- fontWeight: '700',
1254
+ successMainTitle: {
1255
+ fontFamily: fontFamilies.phuduBold,
1256
+ fontWeight: 'bold',
1257
+ fontSize: 28,
1157
1258
  color: colors.success || '#4BB543',
1158
- marginBottom: 8,
1259
+ marginBottom: 2,
1159
1260
  textAlign: 'center',
1160
- width: '100%',
1261
+ letterSpacing: 0.5,
1161
1262
  },
1162
1263
  successSubtitle: {
1163
1264
  fontSize: 16,
@@ -1166,6 +1267,12 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
1166
1267
  marginBottom: 8,
1167
1268
  width: '100%',
1168
1269
  },
1270
+ successMessage: {
1271
+ fontSize: 14,
1272
+ color: colors.secondaryText,
1273
+ textAlign: 'center',
1274
+ marginBottom: 8,
1275
+ },
1169
1276
  methodCard: {
1170
1277
  flexDirection: 'row',
1171
1278
  alignItems: 'center',
@@ -1272,15 +1379,7 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
1272
1379
  minHeight: 36,
1273
1380
  marginBottom: 2,
1274
1381
  },
1275
- circleCheckOverlay: {
1276
- position: 'absolute',
1277
- bottom: -8,
1278
- right: -8,
1279
- backgroundColor: '#fff',
1280
- borderRadius: 16,
1281
- padding: 0,
1282
- zIndex: 2,
1283
- },
1382
+
1284
1383
  headerStepIndicatorContainer: {
1285
1384
  marginVertical: 2,
1286
1385
  flexDirection: 'row',
@@ -1310,6 +1409,210 @@ const createStyles = (colors: any, theme: string) => StyleSheet.create({
1310
1409
  marginTop: 6,
1311
1410
  marginBottom: 2,
1312
1411
  },
1412
+ // Google Play step styles
1413
+ loadingContainer: {
1414
+ padding: 16,
1415
+ alignItems: 'center',
1416
+ backgroundColor: '#fff',
1417
+ borderRadius: 12,
1418
+ marginBottom: 16,
1419
+ },
1420
+ loadingText: {
1421
+ color: colors.secondaryText,
1422
+ fontSize: 16,
1423
+ fontStyle: 'italic',
1424
+ },
1425
+ paymentErrorContainer: {
1426
+ padding: 16,
1427
+ backgroundColor: '#ffebee',
1428
+ borderRadius: 12,
1429
+ marginBottom: 16,
1430
+ borderWidth: 1,
1431
+ borderColor: '#ffcdd2',
1432
+ },
1433
+ paymentErrorText: {
1434
+ color: '#d32f2f',
1435
+ fontSize: 14,
1436
+ textAlign: 'center',
1437
+ },
1438
+ iapSuccessContainer: {
1439
+ padding: 16,
1440
+ backgroundColor: '#e8f5e8',
1441
+ borderRadius: 12,
1442
+ marginTop: 16,
1443
+ borderWidth: 1,
1444
+ borderColor: '#c8e6c9',
1445
+ },
1446
+ iapSuccessText: {
1447
+ color: colors.success || '#4BB543',
1448
+ fontSize: 16,
1449
+ textAlign: 'center',
1450
+ fontWeight: '600',
1451
+ },
1452
+ // Summary step styles
1453
+ summaryDescriptionContainer: {
1454
+ marginBottom: 16,
1455
+ },
1456
+ summaryDescriptionText: {
1457
+ color: colors.secondaryText,
1458
+ fontSize: 15,
1459
+ lineHeight: 20,
1460
+ },
1461
+ summaryItemPrice: {
1462
+ color: colors.text,
1463
+ fontWeight: '600',
1464
+ fontSize: 16,
1465
+ },
1466
+ summaryFallbackContainer: {
1467
+ padding: 16,
1468
+ backgroundColor: '#fff',
1469
+ borderRadius: 12,
1470
+ borderWidth: 1,
1471
+ borderColor: colors.border,
1472
+ },
1473
+ summaryFallbackText: {
1474
+ color: colors.text,
1475
+ fontSize: 16,
1476
+ textAlign: 'center',
1477
+ },
1478
+ // Card payment styles
1479
+ cardPaymentCard: {
1480
+ backgroundColor: '#fff',
1481
+ borderRadius: 16,
1482
+ padding: 24,
1483
+ marginBottom: 24,
1484
+ alignItems: 'center',
1485
+ width: '100%',
1486
+ },
1487
+ cardPaymentContent: {
1488
+ alignItems: 'center',
1489
+ width: '100%',
1490
+ },
1491
+ cardPaymentIcon: {
1492
+ marginBottom: 8,
1493
+ },
1494
+ cardPaymentMainTitle: {
1495
+ fontFamily: fontFamilies.phuduBold,
1496
+ fontWeight: 'bold',
1497
+ fontSize: 28,
1498
+ color: colors.text,
1499
+ marginBottom: 2,
1500
+ textAlign: 'center',
1501
+ letterSpacing: 0.5,
1502
+ },
1503
+ cardPaymentSubtitle: {
1504
+ fontSize: 16,
1505
+ color: colors.secondaryText,
1506
+ textAlign: 'center',
1507
+ marginBottom: 24,
1508
+ width: '100%',
1509
+ },
1510
+ cardPaymentFields: {
1511
+ width: '100%',
1512
+ marginBottom: 16,
1513
+ },
1514
+ cardPaymentWaiting: {
1515
+ fontSize: 14,
1516
+ color: colors.secondaryText,
1517
+ textAlign: 'center',
1518
+ marginBottom: 8,
1519
+ },
1520
+ // Summary card styles
1521
+ summaryCard: {
1522
+ backgroundColor: '#fff',
1523
+ borderRadius: 16,
1524
+ padding: 24,
1525
+ marginBottom: 24,
1526
+ alignItems: 'center',
1527
+ width: '100%',
1528
+ },
1529
+ summaryCardContent: {
1530
+ alignItems: 'center',
1531
+ width: '100%',
1532
+ },
1533
+ summaryCardIcon: {
1534
+ marginBottom: 8,
1535
+ },
1536
+ summaryCardMainTitle: {
1537
+ fontFamily: fontFamilies.phuduBold,
1538
+ fontWeight: 'bold',
1539
+ fontSize: 28,
1540
+ color: colors.text,
1541
+ marginBottom: 2,
1542
+ textAlign: 'center',
1543
+ letterSpacing: 0.5,
1544
+ },
1545
+ summaryCardSubtitle: {
1546
+ fontSize: 16,
1547
+ color: colors.secondaryText,
1548
+ textAlign: 'center',
1549
+ marginBottom: 24,
1550
+ width: '100%',
1551
+ },
1552
+ summaryCardItems: {
1553
+ width: '100%',
1554
+ marginBottom: 16,
1555
+ },
1556
+ summaryCardTotal: {
1557
+ fontSize: 18,
1558
+ fontWeight: 'bold',
1559
+ color: colors.text,
1560
+ textAlign: 'center',
1561
+ marginBottom: 8,
1562
+ },
1563
+ // Simple amount styles
1564
+ summaryCardAmount: {
1565
+ alignItems: 'center',
1566
+ width: '100%',
1567
+ marginBottom: 16,
1568
+ },
1569
+ summaryCardAmountLabel: {
1570
+ fontSize: 16,
1571
+ color: colors.secondaryText,
1572
+ textAlign: 'center',
1573
+ marginBottom: 8,
1574
+ },
1575
+ summaryCardAmountValue: {
1576
+ fontSize: 32,
1577
+ fontWeight: 'bold',
1578
+ color: colors.text,
1579
+ textAlign: 'center',
1580
+ marginBottom: 8,
1581
+ fontFamily: fontFamilies.phuduBold,
1582
+ },
1583
+ summaryCardAmountDescription: {
1584
+ fontSize: 14,
1585
+ color: colors.secondaryText,
1586
+ textAlign: 'center',
1587
+ lineHeight: 20,
1588
+ },
1589
+ // Enhanced summary styles
1590
+ summaryCardDivider: {
1591
+ height: 1,
1592
+ backgroundColor: colors.border,
1593
+ marginVertical: 16,
1594
+ width: '100%',
1595
+ },
1596
+ summaryCardTotalSection: {
1597
+ width: '100%',
1598
+ marginBottom: 8,
1599
+ },
1600
+ summaryCardTotalRow: {
1601
+ flexDirection: 'row',
1602
+ justifyContent: 'space-between',
1603
+ alignItems: 'center',
1604
+ paddingVertical: 4,
1605
+ },
1606
+ summaryCardTotalLabel: {
1607
+ fontSize: 16,
1608
+ color: colors.secondaryText,
1609
+ fontWeight: '500',
1610
+ },
1611
+ summaryCardTotalValue: {
1612
+ fontSize: 16,
1613
+ color: colors.text,
1614
+ fontWeight: '600',
1615
+ },
1313
1616
  });
1314
1617
 
1315
1618
  export default PaymentGatewayScreen;