@oxyhq/services 5.1.12 → 5.1.13

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 (102) hide show
  1. package/lib/commonjs/ui/components/OxyProvider.js +50 -30
  2. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  3. package/lib/commonjs/ui/components/OxySignInButton.js +4 -4
  4. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  5. package/lib/commonjs/ui/context/OxyContext.js +15 -7
  6. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  7. package/lib/commonjs/ui/navigation/OxyRouter.js +47 -7
  8. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  9. package/lib/commonjs/ui/screens/ProfileScreen.js +346 -0
  10. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -0
  11. package/lib/commonjs/ui/screens/SignInScreen.js +82 -86
  12. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  13. package/lib/commonjs/ui/screens/SignUpScreen.js +194 -103
  14. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  15. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +88 -0
  16. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -0
  17. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +364 -0
  18. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -0
  19. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +202 -0
  20. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -0
  21. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +148 -0
  22. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -0
  23. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +127 -0
  24. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -0
  25. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +105 -0
  26. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -0
  27. package/lib/commonjs/ui/styles/theme.js +1 -2
  28. package/lib/commonjs/ui/styles/theme.js.map +1 -1
  29. package/lib/module/ui/components/OxyProvider.js +51 -31
  30. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  31. package/lib/module/ui/components/OxySignInButton.js +4 -4
  32. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  33. package/lib/module/ui/context/OxyContext.js +15 -7
  34. package/lib/module/ui/context/OxyContext.js.map +1 -1
  35. package/lib/module/ui/navigation/OxyRouter.js +47 -7
  36. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  37. package/lib/module/ui/screens/ProfileScreen.js +340 -0
  38. package/lib/module/ui/screens/ProfileScreen.js.map +1 -0
  39. package/lib/module/ui/screens/SignInScreen.js +83 -87
  40. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  41. package/lib/module/ui/screens/SignUpScreen.js +194 -104
  42. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  43. package/lib/module/ui/screens/karma/KarmaAboutScreen.js +83 -0
  44. package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -0
  45. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +358 -0
  46. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -0
  47. package/lib/module/ui/screens/karma/KarmaFAQScreen.js +197 -0
  48. package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -0
  49. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +142 -0
  50. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -0
  51. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +122 -0
  52. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -0
  53. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +100 -0
  54. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -0
  55. package/lib/module/ui/styles/theme.js +1 -2
  56. package/lib/module/ui/styles/theme.js.map +1 -1
  57. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  58. package/lib/typescript/ui/components/OxySignInButton.d.ts +5 -0
  59. package/lib/typescript/ui/components/OxySignInButton.d.ts.map +1 -1
  60. package/lib/typescript/ui/context/OxyContext.d.ts +4 -1
  61. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  62. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
  63. package/lib/typescript/ui/screens/ProfileScreen.d.ts +9 -0
  64. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -0
  65. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  66. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  67. package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts +5 -0
  68. package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -0
  69. package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts +5 -0
  70. package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -0
  71. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts +5 -0
  72. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -0
  73. package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts +5 -0
  74. package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -0
  75. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts +5 -0
  76. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -0
  77. package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts +5 -0
  78. package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -0
  79. package/lib/typescript/ui/styles/theme.d.ts +0 -1
  80. package/lib/typescript/ui/styles/theme.d.ts.map +1 -1
  81. package/package.json +4 -3
  82. package/src/ui/components/OxyProvider.tsx +42 -29
  83. package/src/ui/components/OxySignInButton.tsx +9 -3
  84. package/src/ui/context/OxyContext.tsx +16 -8
  85. package/src/ui/navigation/OxyRouter.tsx +44 -7
  86. package/src/ui/screens/ProfileScreen.tsx +155 -0
  87. package/src/ui/screens/SignInScreen.tsx +68 -73
  88. package/src/ui/screens/SignUpScreen.tsx +140 -81
  89. package/src/ui/screens/karma/KarmaAboutScreen.tsx +45 -0
  90. package/src/ui/screens/karma/KarmaCenterScreen.tsx +271 -0
  91. package/src/ui/screens/karma/KarmaFAQScreen.tsx +164 -0
  92. package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +79 -0
  93. package/src/ui/screens/karma/KarmaRewardsScreen.tsx +55 -0
  94. package/src/ui/screens/karma/KarmaRulesScreen.tsx +65 -0
  95. package/src/ui/styles/theme.ts +1 -2
  96. package/lib/commonjs/ui/screens/AboutKarmaScreen.js +0 -50
  97. package/lib/commonjs/ui/screens/AboutKarmaScreen.js.map +0 -1
  98. package/lib/module/ui/screens/AboutKarmaScreen.js +0 -45
  99. package/lib/module/ui/screens/AboutKarmaScreen.js.map +0 -1
  100. package/lib/typescript/ui/screens/AboutKarmaScreen.d.ts +0 -5
  101. package/lib/typescript/ui/screens/AboutKarmaScreen.d.ts.map +0 -1
  102. package/src/ui/screens/AboutKarmaScreen.tsx +0 -58
@@ -17,6 +17,9 @@ import { BaseScreenProps } from '../navigation/types';
17
17
  import { useOxy } from '../context/OxyContext';
18
18
  import { fontFamilies } from '../styles/fonts';
19
19
  import OxyLogo from '../components/OxyLogo';
20
+ import { BottomSheetScrollView, BottomSheetView } from '@gorhom/bottom-sheet';
21
+ import { Ionicons } from '@expo/vector-icons'; // Add icon import
22
+ import Svg, { Path, Circle } from 'react-native-svg';
20
23
 
21
24
  const SignUpScreen: React.FC<BaseScreenProps> = ({
22
25
  navigate,
@@ -91,9 +94,9 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
91
94
 
92
95
  if (user && isAuthenticated) {
93
96
  return (
94
- <View style={[styles.container, { backgroundColor, padding: 20 }]}>
97
+ <BottomSheetScrollView style={[styles.scrollContainer, { backgroundColor, padding: 20 }]}>
95
98
  <Text style={[
96
- styles.title,
99
+ styles.welcomeTitle,
97
100
  {
98
101
  color: textColor,
99
102
  textAlign: 'center'
@@ -119,7 +122,7 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
119
122
  <Text style={styles.buttonText}>Go to Account Center</Text>
120
123
  </TouchableOpacity>
121
124
  </View>
122
- </View>
125
+ </BottomSheetScrollView>
123
126
  );
124
127
  }
125
128
 
@@ -165,10 +168,38 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
165
168
  styles.stepContainer,
166
169
  { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }
167
170
  ]}>
171
+ <View style={styles.welcomeImageContainer}>
172
+ {/* Large illustration, not inside a circle */}
173
+ <Svg width={220} height={120} viewBox="0 0 220 120">
174
+ {/* Example: Abstract friendly illustration */}
175
+ <Path
176
+ d="M30 100 Q60 20 110 60 Q160 100 190 40"
177
+ stroke="#d169e5"
178
+ strokeWidth="8"
179
+ fill="none"
180
+ />
181
+ <Circle cx="60" cy="60" r="18" fill="#d169e5" opacity="0.18" />
182
+ <Circle cx="110" cy="60" r="24" fill="#d169e5" opacity="0.25" />
183
+ <Circle cx="170" cy="50" r="14" fill="#d169e5" opacity="0.15" />
184
+ {/* Smiling face */}
185
+ <Circle cx="110" cy="60" r="32" fill="#fff" opacity="0.7" />
186
+ <Circle cx="100" cy="55" r="4" fill="#d169e5" />
187
+ <Circle cx="120" cy="55" r="4" fill="#d169e5" />
188
+ <Path
189
+ d="M104 68 Q110 75 116 68"
190
+ stroke="#d169e5"
191
+ strokeWidth="2"
192
+ fill="none"
193
+ strokeLinecap="round"
194
+ />
195
+ </Svg>
196
+ </View>
168
197
 
169
- <Text style={[styles.welcomeTitle, { color: textColor }]}>
170
- Welcome to Oxy
171
- </Text>
198
+ <View style={styles.header}>
199
+ {/* Add a close/back icon for better navigation */}
200
+ <Text style={[styles.welcomeTitle]}>Create a Oxy Account</Text>
201
+ <View style={styles.placeholder} />
202
+ </View>
172
203
 
173
204
  <Text style={[styles.welcomeText, { color: textColor }]}>
174
205
  We're excited to have you join us. Let's get your account set up in just a few easy steps.
@@ -396,118 +427,123 @@ const SignUpScreen: React.FC<BaseScreenProps> = ({
396
427
  };
397
428
 
398
429
  return (
399
- <KeyboardAvoidingView
400
- behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
401
- style={[styles.container, { backgroundColor }]}
430
+ <BottomSheetScrollView
431
+ contentContainerStyle={styles.scrollContainer}
432
+ keyboardShouldPersistTaps="handled"
402
433
  >
403
- <ScrollView
404
- contentContainerStyle={styles.scrollContainer}
405
- keyboardShouldPersistTaps="handled"
406
- >
407
- <View style={styles.header}>
408
- <OxyLogo
409
- style={{ marginBottom: 24 }}
410
- width={50}
411
- height={50}
412
- />
413
- <Text style={[styles.title]}>Create Account</Text>
414
- <View style={styles.placeholder} /></View>
415
-
416
- <View style={styles.formContainer}>
417
- {renderCurrentStep()}
418
- </View>
434
+ <OxyLogo
435
+ style={{ marginBottom: 24 }}
436
+ width={50}
437
+ height={50}
438
+ />
439
+
440
+ <View style={styles.formContainer}>
441
+ {renderCurrentStep()}
442
+ </View>
419
443
 
420
- {currentStep > 0 && renderProgressIndicators()}
421
- </ScrollView>
422
- </KeyboardAvoidingView>
444
+ {currentStep > 0 && renderProgressIndicators()}
445
+ </BottomSheetScrollView>
423
446
  );
424
447
  };
425
448
 
426
449
  const styles = StyleSheet.create({
427
- container: {
428
- flex: 1,
429
- },
430
450
  scrollContainer: {
431
- flexGrow: 1,
432
- padding: 10,
451
+ padding: 20,
433
452
  },
434
453
  header: {
435
454
  flexDirection: 'row',
455
+ alignItems: 'center',
436
456
  justifyContent: 'space-between',
437
- marginBottom: 24,
438
- },
439
- title: {
440
- fontFamily: Platform.OS === 'web'
441
- ? 'Phudu' // Use CSS font name directly for web
442
- : 'Phudu-Bold', // Use exact font name as registered with Font.loadAsync
443
- fontWeight: Platform.OS === 'web' ? 'bold' : undefined, // Only apply fontWeight on web
444
- fontSize: 54,
445
457
  },
446
458
  placeholder: {
447
- width: 50, // To balance the header
459
+ width: 40,
448
460
  },
449
461
  formContainer: {
450
462
  width: '100%',
463
+ marginTop: 8,
451
464
  },
452
465
  stepContainer: {
453
466
  width: '100%',
454
- paddingVertical: 20,
467
+ paddingVertical: 8,
468
+ paddingHorizontal: 0,
469
+ marginBottom: 8,
455
470
  },
456
471
  inputContainer: {
457
- marginBottom: 16,
472
+ marginBottom: 18,
458
473
  },
459
474
  label: {
460
- fontSize: 14,
475
+ fontSize: 15,
461
476
  marginBottom: 8,
477
+ fontWeight: '500',
478
+ letterSpacing: 0.1,
462
479
  },
463
480
  input: {
464
481
  height: 48,
465
- borderRadius: 35,
482
+ borderRadius: 16,
466
483
  paddingHorizontal: 16,
467
484
  borderWidth: 1,
468
485
  fontSize: 16,
486
+ backgroundColor: '#F5F5F5',
487
+ borderColor: '#E0E0E0',
488
+ marginBottom: 2,
469
489
  },
470
490
  button: {
471
491
  backgroundColor: '#d169e5',
472
492
  height: 48,
473
- borderRadius: 35,
493
+ borderRadius: 24,
474
494
  alignItems: 'center',
475
495
  justifyContent: 'center',
476
496
  marginTop: 24,
497
+ shadowColor: '#d169e5',
498
+ shadowOpacity: 0.12,
499
+ shadowOffset: { width: 0, height: 2 },
500
+ shadowRadius: 8,
501
+ elevation: 2,
477
502
  },
478
503
  buttonText: {
479
504
  color: '#FFFFFF',
480
- fontSize: 16,
481
- fontWeight: '600',
505
+ fontSize: 17,
506
+ fontWeight: '700',
507
+ letterSpacing: 0.2,
482
508
  },
483
509
  footerTextContainer: {
484
510
  flexDirection: 'row',
485
511
  justifyContent: 'center',
486
- marginTop: 24,
512
+ marginTop: 28,
487
513
  },
488
514
  footerText: {
489
- fontSize: 14,
515
+ fontSize: 15,
516
+ color: '#888',
490
517
  },
491
518
  linkText: {
492
- fontSize: 14,
493
- fontWeight: '600',
519
+ fontSize: 15,
520
+ fontWeight: '700',
521
+ color: '#d169e5',
494
522
  },
495
523
  errorContainer: {
496
- backgroundColor: '#FFEBEE',
497
- padding: 12,
498
- borderRadius: 35,
524
+ backgroundColor: '#FFE4EC',
525
+ padding: 14,
526
+ borderRadius: 18,
499
527
  marginBottom: 16,
528
+ borderWidth: 1,
529
+ borderColor: '#F8BBD0',
500
530
  },
501
531
  errorText: {
502
532
  color: '#D32F2F',
503
- fontSize: 14,
533
+ fontSize: 15,
534
+ fontWeight: '500',
504
535
  },
505
536
  userInfoContainer: {
506
537
  padding: 20,
507
538
  marginVertical: 20,
508
539
  backgroundColor: '#F5F5F5',
509
- borderRadius: 35,
540
+ borderRadius: 24,
510
541
  alignItems: 'center',
542
+ shadowColor: '#000',
543
+ shadowOpacity: 0.04,
544
+ shadowOffset: { width: 0, height: 1 },
545
+ shadowRadius: 4,
546
+ elevation: 1,
511
547
  },
512
548
  userInfoText: {
513
549
  fontSize: 16,
@@ -523,65 +559,86 @@ const styles = StyleSheet.create({
523
559
  ? 'Phudu' // Use CSS font name directly for web
524
560
  : 'Phudu-Bold', // Use exact font name as registered with Font.loadAsync
525
561
  fontWeight: Platform.OS === 'web' ? 'bold' : undefined, // Only apply fontWeight on web
526
- fontSize: 32,
527
- textAlign: 'left',
528
- marginBottom: 20,
562
+ fontSize: 54,
563
+ marginBottom: 24,
529
564
  },
530
565
  welcomeText: {
531
566
  fontSize: 16,
532
567
  textAlign: 'left',
533
568
  marginBottom: 30,
534
569
  lineHeight: 24,
570
+ color: '#444',
571
+ },
572
+ welcomeImageContainer: {
573
+ alignItems: 'center',
574
+ justifyContent: 'center',
575
+ marginVertical: 30,
535
576
  },
536
577
  stepTitle: {
537
- fontSize: 24,
538
- fontWeight: '600',
578
+ fontFamily: Platform.OS === 'web'
579
+ ? 'Phudu' // Use CSS font name directly for web
580
+ : 'Phudu-Bold', // Use exact font name as registered with Font.loadAsync
581
+ fontWeight: Platform.OS === 'web' ? 'bold' : undefined, // Only apply fontWeight on web
582
+ fontSize: 34,
539
583
  marginBottom: 20,
584
+ color: '#d169e5',
585
+ maxWidth: '90%',
540
586
  },
541
587
  navigationButtons: {
542
588
  flexDirection: 'row',
543
589
  justifyContent: 'space-between',
544
590
  alignItems: 'center',
545
- marginTop: 24,
591
+ marginTop: 28,
546
592
  },
547
593
  navButton: {
548
- borderRadius: 35,
549
- height: 48,
594
+ borderRadius: 24,
595
+ height: 44,
550
596
  alignItems: 'center',
551
597
  justifyContent: 'center',
552
- paddingHorizontal: 24,
553
- marginRight: 'auto',
598
+ paddingHorizontal: 28,
599
+ backgroundColor: '#F3E5F5',
554
600
  },
555
601
  backButton: {
556
602
  backgroundColor: 'transparent',
603
+ borderWidth: 1,
604
+ borderColor: '#E0E0E0',
557
605
  },
558
606
  nextButton: {
559
607
  minWidth: 100,
608
+ backgroundColor: '#d169e5',
560
609
  },
561
610
  navButtonText: {
562
611
  fontSize: 16,
563
- fontWeight: '600',
564
- color: '#FFFFFF',
612
+ fontWeight: '700',
613
+ color: '#d169e5',
565
614
  },
566
615
  passwordHint: {
567
616
  fontSize: 12,
568
617
  marginTop: 4,
618
+ color: '#888',
569
619
  },
570
620
  progressContainer: {
571
621
  flexDirection: 'row',
572
622
  justifyContent: 'center',
573
623
  marginBottom: 20,
624
+ marginTop: 8,
574
625
  },
575
626
  progressDot: {
576
- height: 8,
577
- width: 8,
578
- borderRadius: 4,
579
- marginHorizontal: 4,
627
+ height: 10,
628
+ width: 10,
629
+ borderRadius: 5,
630
+ marginHorizontal: 6,
631
+ backgroundColor: '#E0E0E0',
632
+ borderWidth: 2,
633
+ borderColor: '#fff',
634
+ shadowColor: '#d169e5',
635
+ shadowOpacity: 0.08,
636
+ shadowOffset: { width: 0, height: 1 },
637
+ shadowRadius: 2,
638
+ elevation: 1,
580
639
  },
581
640
  summaryContainer: {
582
- backgroundColor: '#F5F5F5',
583
- borderRadius: 15,
584
- padding: 16,
641
+ padding: 0,
585
642
  marginBottom: 24,
586
643
  },
587
644
  summaryRow: {
@@ -589,13 +646,15 @@ const styles = StyleSheet.create({
589
646
  marginBottom: 10,
590
647
  },
591
648
  summaryLabel: {
592
- fontSize: 14,
593
- width: 80,
649
+ fontSize: 15,
650
+ width: 90,
651
+ color: '#888',
594
652
  },
595
653
  summaryValue: {
596
- fontSize: 14,
597
- fontWeight: '500',
654
+ fontSize: 15,
655
+ fontWeight: '600',
598
656
  flex: 1,
657
+ color: '#222',
599
658
  },
600
659
  });
601
660
 
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { View, Text, StyleSheet, ScrollView, Platform } from 'react-native';
3
+ import { BaseScreenProps } from '../../navigation/types';
4
+
5
+ const KarmaAboutScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
6
+ const isDarkTheme = theme === 'dark';
7
+ const backgroundColor = isDarkTheme ? '#121212' : '#FFFFFF';
8
+ const textColor = isDarkTheme ? '#FFFFFF' : '#000000';
9
+ const primaryColor = '#d169e5';
10
+
11
+ return (
12
+ <View style={[styles.container, { backgroundColor }]}>
13
+ <Text style={[styles.title, { color: textColor }]}>About Karma</Text>
14
+ <ScrollView contentContainerStyle={styles.contentContainer}>
15
+ <Text style={[styles.paragraph, { color: textColor }]}>Karma is a recognition of your positive actions in the Oxy Ecosystem. It cannot be sent or received directly, only earned by contributing to the community.</Text>
16
+ <Text style={[styles.section, { color: primaryColor }]}>How to Earn Karma</Text>
17
+ <Text style={[styles.paragraph, { color: textColor }]}>• Helping other users{'\n'}
18
+ • Reporting bugs{'\n'}
19
+ • Contributing content{'\n'}
20
+ • Participating in events{'\n'}
21
+ • Other positive actions</Text>
22
+ <Text style={[styles.section, { color: primaryColor }]}>Why Karma?</Text>
23
+ <Text style={[styles.paragraph, { color: textColor }]}>Karma unlocks special features and recognition in the Oxy Ecosystem. The more you contribute, the more you earn!</Text>
24
+ </ScrollView>
25
+ </View>
26
+ );
27
+ };
28
+
29
+ const styles = StyleSheet.create({
30
+ container: { flex: 1 },
31
+ title: {
32
+ fontFamily: Platform.OS === 'web'
33
+ ? 'Phudu' // Use CSS font name directly for web
34
+ : 'Phudu-Bold', // Use exact font name as registered with Font.loadAsync
35
+ fontWeight: Platform.OS === 'web' ? 'bold' : undefined, // Only apply fontWeight on web
36
+ fontSize: 54,
37
+ margin: 24,
38
+ marginBottom: 24,
39
+ },
40
+ contentContainer: { padding: 24 },
41
+ section: { fontSize: 18, fontWeight: 'bold', marginTop: 24, marginBottom: 8 },
42
+ paragraph: { fontSize: 16, marginBottom: 12 },
43
+ });
44
+
45
+ export default KarmaAboutScreen;
@@ -0,0 +1,271 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ TouchableOpacity,
6
+ StyleSheet,
7
+ ActivityIndicator,
8
+ ScrollView,
9
+ Alert,
10
+ Platform,
11
+ } from 'react-native';
12
+ import { BaseScreenProps } from '../../navigation/types';
13
+ import { useOxy } from '../../context/OxyContext';
14
+ import { fontFamilies } from '../../styles/fonts';
15
+ import Avatar from '../../components/Avatar';
16
+ import { Ionicons } from '@expo/vector-icons';
17
+
18
+ const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
19
+ onClose,
20
+ theme,
21
+ navigate,
22
+ goBack,
23
+ }) => {
24
+ const { user, oxyServices } = useOxy();
25
+ const [karmaTotal, setKarmaTotal] = useState<number | null>(null);
26
+ const [karmaHistory, setKarmaHistory] = useState<any[]>([]);
27
+ const [isLoading, setIsLoading] = useState(true);
28
+ const [error, setError] = useState<string | null>(null);
29
+
30
+ const isDarkTheme = theme === 'dark';
31
+ const textColor = isDarkTheme ? '#FFFFFF' : '#000000';
32
+ const backgroundColor = isDarkTheme ? '#121212' : '#FFFFFF';
33
+ const secondaryBackgroundColor = isDarkTheme ? '#222222' : '#F5F5F5';
34
+ const borderColor = isDarkTheme ? '#444444' : '#E0E0E0';
35
+ const primaryColor = '#d169e5';
36
+
37
+ useEffect(() => {
38
+ if (!user) return;
39
+ setIsLoading(true);
40
+ setError(null);
41
+ Promise.all([
42
+ oxyServices.getUserKarmaTotal(user.id),
43
+ oxyServices.getUserKarmaHistory(user.id, 20, 0),
44
+ ])
45
+ .then(([totalRes, historyRes]) => {
46
+ setKarmaTotal(totalRes.total);
47
+ setKarmaHistory(Array.isArray(historyRes.history) ? historyRes.history : []);
48
+ })
49
+ .catch((err) => {
50
+ setError(err.message || 'Failed to load karma data');
51
+ })
52
+ .finally(() => setIsLoading(false));
53
+ }, [user]);
54
+
55
+ if (!user) {
56
+ return (
57
+ <View style={[styles.container, { backgroundColor }]}>
58
+ <Text style={[styles.message, { color: textColor }]}>Not signed in</Text>
59
+ </View>
60
+ );
61
+ }
62
+
63
+ if (isLoading) {
64
+ return (
65
+ <View style={[styles.container, { backgroundColor, justifyContent: 'center' }]}>
66
+ <ActivityIndicator size="large" color={primaryColor} />
67
+ </View>
68
+ );
69
+ }
70
+
71
+ return (
72
+ <View style={[styles.container, { backgroundColor }]}>
73
+ <ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContainer}>
74
+ <View style={styles.walletHeader}>
75
+ <Avatar
76
+ imageUrl={user.avatarUrl}
77
+ name={user.username}
78
+ size={60}
79
+ theme={theme}
80
+ style={styles.avatar}
81
+ />
82
+ <Text style={[styles.karmaLabel, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>Karma Balance</Text>
83
+ <Text style={[styles.karmaAmount, { color: primaryColor }]}>{karmaTotal ?? 0}</Text>
84
+ <View style={styles.actionRow}>
85
+ <TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate && navigate('KarmaLeaderboard')}>
86
+ <View style={[styles.actionIcon, { backgroundColor: '#E0E0E0' }]}>
87
+ <Ionicons name="trophy-outline" size={28} color="#888" />
88
+ </View>
89
+ <Text style={styles.actionLabel}>Leaderboard</Text>
90
+ </TouchableOpacity>
91
+ <TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate && navigate('KarmaRules')}>
92
+ <View style={[styles.actionIcon, { backgroundColor: '#E0E0E0' }]}>
93
+ <Ionicons name="document-text-outline" size={28} color="#888" />
94
+ </View>
95
+ <Text style={styles.actionLabel}>Rules</Text>
96
+ </TouchableOpacity>
97
+ <TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate && navigate('AboutKarma')}>
98
+ <View style={[styles.actionIcon, { backgroundColor: '#E0E0E0' }]}>
99
+ <Ionicons name="star-outline" size={28} color="#888" />
100
+ </View>
101
+ <Text style={styles.actionLabel}>About</Text>
102
+ </TouchableOpacity>
103
+ <TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate && navigate('KarmaRewards')}>
104
+ <View style={[styles.actionIcon, { backgroundColor: '#E0E0E0' }]}>
105
+ <Ionicons name="gift-outline" size={28} color="#888" />
106
+ </View>
107
+ <Text style={styles.actionLabel}>Rewards</Text>
108
+ </TouchableOpacity>
109
+ <TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate && navigate('KarmaFAQ')}>
110
+ <View style={[styles.actionIcon, { backgroundColor: '#E0E0E0' }]}>
111
+ <Ionicons name="help-circle-outline" size={28} color="#888" />
112
+ </View>
113
+ <Text style={styles.actionLabel}>FAQ</Text>
114
+ </TouchableOpacity>
115
+ </View>
116
+ <Text style={styles.infoText}>Karma can only be earned by positive actions in the Oxy Ecosystem. It cannot be sent or received directly.</Text>
117
+ </View>
118
+ <Text style={[styles.sectionTitle, { color: textColor }]}>Karma History</Text>
119
+ <View style={styles.historyContainer}>
120
+ {karmaHistory.length === 0 ? (
121
+ <Text style={{ color: textColor, textAlign: 'center', marginTop: 16 }}>No karma history yet.</Text>
122
+ ) : (
123
+ karmaHistory.map((entry: any) => (
124
+ <View key={entry.id} style={[styles.historyItem, { borderColor }]}>
125
+ <Text style={[styles.historyPoints, { color: entry.points > 0 ? primaryColor : '#D32F2F' }]}>
126
+ {entry.points > 0 ? '+' : ''}{entry.points}
127
+ </Text>
128
+ <Text style={[styles.historyDesc, { color: textColor }]}>
129
+ {entry.reason || 'No description'}
130
+ </Text>
131
+ <Text style={[styles.historyDate, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>
132
+ {entry.createdAt ? new Date(entry.createdAt).toLocaleString() : ''}
133
+ </Text>
134
+ </View>
135
+ ))
136
+ )}
137
+ </View>
138
+ {error && <Text style={{ color: '#D32F2F', marginTop: 16, textAlign: 'center' }}>{error}</Text>}
139
+ </ScrollView>
140
+ <View style={styles.footer}>
141
+ <TouchableOpacity style={styles.closeButton} onPress={onClose}>
142
+ <Text style={[styles.closeButtonText, { color: primaryColor }]}>Close</Text>
143
+ </TouchableOpacity>
144
+ </View>
145
+ </View>
146
+ );
147
+ };
148
+
149
+ const styles = StyleSheet.create({
150
+ container: {
151
+ flex: 1,
152
+ },
153
+ scrollView: {
154
+ flex: 1,
155
+ },
156
+ scrollContainer: {
157
+ padding: 0,
158
+ alignItems: 'center',
159
+ },
160
+ walletHeader: {
161
+ alignItems: 'center',
162
+ paddingTop: 36,
163
+ paddingBottom: 24,
164
+ width: '100%',
165
+ backgroundColor: 'transparent',
166
+ },
167
+ avatar: {
168
+ marginBottom: 12,
169
+ },
170
+ karmaLabel: {
171
+ fontSize: 16,
172
+ marginBottom: 4,
173
+ fontFamily: fontFamilies.phudu,
174
+ },
175
+ karmaAmount: {
176
+ fontSize: 48,
177
+ fontWeight: 'bold',
178
+ marginBottom: 18,
179
+ fontFamily: fontFamilies.phuduBold,
180
+ },
181
+ actionRow: {
182
+ flexDirection: 'row',
183
+ justifyContent: 'center',
184
+ marginBottom: 18,
185
+ flexWrap: 'wrap',
186
+ rowGap: 0,
187
+ columnGap: 0,
188
+ },
189
+ actionIconWrapper: {
190
+ alignItems: 'center',
191
+ marginHorizontal: 8,
192
+ marginVertical: 4,
193
+ width: 72,
194
+ },
195
+ actionIcon: {
196
+ width: 56,
197
+ height: 56,
198
+ borderRadius: 28,
199
+ alignItems: 'center',
200
+ justifyContent: 'center',
201
+ marginBottom: 6,
202
+ opacity: 0.5,
203
+ },
204
+ actionIconText: {
205
+ fontSize: 28,
206
+ },
207
+ actionLabel: {
208
+ fontSize: 13,
209
+ color: '#888',
210
+ },
211
+ infoText: {
212
+ fontSize: 13,
213
+ color: '#888',
214
+ textAlign: 'center',
215
+ marginTop: 8,
216
+ marginBottom: 8,
217
+ maxWidth: 320,
218
+ },
219
+ sectionTitle: {
220
+ fontSize: 18,
221
+ fontWeight: '600',
222
+ marginBottom: 12,
223
+ marginTop: 8,
224
+ alignSelf: 'flex-start',
225
+ marginLeft: 24,
226
+ },
227
+ historyContainer: {
228
+ borderRadius: 15,
229
+ overflow: 'hidden',
230
+ marginBottom: 20,
231
+ width: '100%',
232
+ paddingHorizontal: 12,
233
+ },
234
+ historyItem: {
235
+ padding: 14,
236
+ borderBottomWidth: 1,
237
+ },
238
+ historyPoints: {
239
+ fontSize: 16,
240
+ fontWeight: '700',
241
+ },
242
+ historyDesc: {
243
+ fontSize: 15,
244
+ marginTop: 2,
245
+ },
246
+ historyDate: {
247
+ fontSize: 13,
248
+ marginTop: 2,
249
+ },
250
+ footer: {
251
+ padding: 16,
252
+ borderTopWidth: 1,
253
+ borderTopColor: '#E0E0E0',
254
+ alignItems: 'center',
255
+ },
256
+ closeButton: {
257
+ paddingVertical: 8,
258
+ paddingHorizontal: 16,
259
+ },
260
+ closeButtonText: {
261
+ fontSize: 16,
262
+ fontWeight: '600',
263
+ },
264
+ message: {
265
+ fontSize: 16,
266
+ textAlign: 'center',
267
+ marginTop: 24,
268
+ },
269
+ });
270
+
271
+ export default KarmaCenterScreen;