@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.
- package/lib/commonjs/ui/components/OxyProvider.js +50 -30
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/OxySignInButton.js +4 -4
- package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +15 -7
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/navigation/OxyRouter.js +47 -7
- package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +346 -0
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/SignInScreen.js +82 -86
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +194 -103
- package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +88 -0
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +364 -0
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +202 -0
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +148 -0
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +127 -0
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +105 -0
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -0
- package/lib/commonjs/ui/styles/theme.js +1 -2
- package/lib/commonjs/ui/styles/theme.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +51 -31
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/OxySignInButton.js +4 -4
- package/lib/module/ui/components/OxySignInButton.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +15 -7
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/navigation/OxyRouter.js +47 -7
- package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +340 -0
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -0
- package/lib/module/ui/screens/SignInScreen.js +83 -87
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/SignUpScreen.js +194 -104
- package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js +83 -0
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -0
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js +358 -0
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -0
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js +197 -0
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -0
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +142 -0
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -0
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +122 -0
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -0
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js +100 -0
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -0
- package/lib/module/ui/styles/theme.js +1 -2
- package/lib/module/ui/styles/theme.js.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxySignInButton.d.ts +5 -0
- package/lib/typescript/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +4 -1
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
- package/lib/typescript/ui/screens/ProfileScreen.d.ts +9 -0
- package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts +5 -0
- package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts +5 -0
- package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts +5 -0
- package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts +5 -0
- package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts +5 -0
- package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts +5 -0
- package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -0
- package/lib/typescript/ui/styles/theme.d.ts +0 -1
- package/lib/typescript/ui/styles/theme.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/ui/components/OxyProvider.tsx +42 -29
- package/src/ui/components/OxySignInButton.tsx +9 -3
- package/src/ui/context/OxyContext.tsx +16 -8
- package/src/ui/navigation/OxyRouter.tsx +44 -7
- package/src/ui/screens/ProfileScreen.tsx +155 -0
- package/src/ui/screens/SignInScreen.tsx +68 -73
- package/src/ui/screens/SignUpScreen.tsx +140 -81
- package/src/ui/screens/karma/KarmaAboutScreen.tsx +45 -0
- package/src/ui/screens/karma/KarmaCenterScreen.tsx +271 -0
- package/src/ui/screens/karma/KarmaFAQScreen.tsx +164 -0
- package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +79 -0
- package/src/ui/screens/karma/KarmaRewardsScreen.tsx +55 -0
- package/src/ui/screens/karma/KarmaRulesScreen.tsx +65 -0
- package/src/ui/styles/theme.ts +1 -2
- package/lib/commonjs/ui/screens/AboutKarmaScreen.js +0 -50
- package/lib/commonjs/ui/screens/AboutKarmaScreen.js.map +0 -1
- package/lib/module/ui/screens/AboutKarmaScreen.js +0 -45
- package/lib/module/ui/screens/AboutKarmaScreen.js.map +0 -1
- package/lib/typescript/ui/screens/AboutKarmaScreen.d.ts +0 -5
- package/lib/typescript/ui/screens/AboutKarmaScreen.d.ts.map +0 -1
- 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
|
-
<
|
|
97
|
+
<BottomSheetScrollView style={[styles.scrollContainer, { backgroundColor, padding: 20 }]}>
|
|
95
98
|
<Text style={[
|
|
96
|
-
styles.
|
|
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
|
-
</
|
|
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
|
-
<
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
<
|
|
400
|
-
|
|
401
|
-
|
|
430
|
+
<BottomSheetScrollView
|
|
431
|
+
contentContainerStyle={styles.scrollContainer}
|
|
432
|
+
keyboardShouldPersistTaps="handled"
|
|
402
433
|
>
|
|
403
|
-
<
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
421
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
467
|
+
paddingVertical: 8,
|
|
468
|
+
paddingHorizontal: 0,
|
|
469
|
+
marginBottom: 8,
|
|
455
470
|
},
|
|
456
471
|
inputContainer: {
|
|
457
|
-
marginBottom:
|
|
472
|
+
marginBottom: 18,
|
|
458
473
|
},
|
|
459
474
|
label: {
|
|
460
|
-
fontSize:
|
|
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:
|
|
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:
|
|
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:
|
|
481
|
-
fontWeight: '
|
|
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:
|
|
512
|
+
marginTop: 28,
|
|
487
513
|
},
|
|
488
514
|
footerText: {
|
|
489
|
-
fontSize:
|
|
515
|
+
fontSize: 15,
|
|
516
|
+
color: '#888',
|
|
490
517
|
},
|
|
491
518
|
linkText: {
|
|
492
|
-
fontSize:
|
|
493
|
-
fontWeight: '
|
|
519
|
+
fontSize: 15,
|
|
520
|
+
fontWeight: '700',
|
|
521
|
+
color: '#d169e5',
|
|
494
522
|
},
|
|
495
523
|
errorContainer: {
|
|
496
|
-
backgroundColor: '#
|
|
497
|
-
padding:
|
|
498
|
-
borderRadius:
|
|
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:
|
|
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:
|
|
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:
|
|
527
|
-
|
|
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
|
-
|
|
538
|
-
|
|
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:
|
|
591
|
+
marginTop: 28,
|
|
546
592
|
},
|
|
547
593
|
navButton: {
|
|
548
|
-
borderRadius:
|
|
549
|
-
height:
|
|
594
|
+
borderRadius: 24,
|
|
595
|
+
height: 44,
|
|
550
596
|
alignItems: 'center',
|
|
551
597
|
justifyContent: 'center',
|
|
552
|
-
paddingHorizontal:
|
|
553
|
-
|
|
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: '
|
|
564
|
-
color: '#
|
|
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:
|
|
577
|
-
width:
|
|
578
|
-
borderRadius:
|
|
579
|
-
marginHorizontal:
|
|
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
|
-
|
|
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:
|
|
593
|
-
width:
|
|
649
|
+
fontSize: 15,
|
|
650
|
+
width: 90,
|
|
651
|
+
color: '#888',
|
|
594
652
|
},
|
|
595
653
|
summaryValue: {
|
|
596
|
-
fontSize:
|
|
597
|
-
fontWeight: '
|
|
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;
|