@oxyhq/services 10.2.0 → 10.2.2
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/README.md +9 -13
- package/lib/commonjs/index.js +10 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/AccountMenu.js +297 -226
- package/lib/commonjs/ui/components/AccountMenu.js.map +1 -1
- package/lib/commonjs/ui/components/AccountMenuButton.js.map +1 -1
- package/lib/commonjs/ui/components/FollowButton.js +3 -1
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/OxySignInButton.js +1 -1
- package/lib/commonjs/ui/components/SignInModal.js +11 -12
- package/lib/commonjs/ui/components/SignInModal.js.map +1 -1
- package/lib/commonjs/ui/components/accountMenuRows.js +18 -30
- package/lib/commonjs/ui/components/accountMenuRows.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +57 -78
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +7 -13
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/hooks/useAuth.js +10 -40
- package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
- package/lib/commonjs/ui/hooks/useDeviceAccounts.js +285 -0
- package/lib/commonjs/ui/hooks/useDeviceAccounts.js.map +1 -0
- package/lib/commonjs/ui/hooks/useFollow.js +21 -7
- package/lib/commonjs/ui/hooks/useFollow.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionManagement.js +5 -6
- package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionSocket.js +4 -5
- package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/commonjs/ui/hooks/useWebSSO.js +1 -1
- package/lib/commonjs/ui/navigation/routes.js +7 -7
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/screens/OxyAuthScreen.js +6 -7
- package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +18 -20
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +4 -4
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/{karma/KarmaAboutScreen.js → trust/TrustAboutScreen.js} +11 -11
- package/lib/commonjs/ui/screens/trust/TrustAboutScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/{karma/KarmaCenterScreen.js → trust/TrustCenterScreen.js} +91 -41
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/{karma/KarmaFAQScreen.js → trust/TrustFAQScreen.js} +11 -11
- package/lib/commonjs/ui/screens/{karma/KarmaFAQScreen.js.map → trust/TrustFAQScreen.js.map} +1 -1
- package/lib/commonjs/ui/screens/{karma/KarmaLeaderboardScreen.js → trust/TrustLeaderboardScreen.js} +63 -42
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/{karma/KarmaRewardsScreen.js → trust/TrustRewardsScreen.js} +54 -54
- package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/{karma/KarmaRulesScreen.js → trust/TrustRulesScreen.js} +45 -16
- package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/trust/trustTier.js +23 -0
- package/lib/commonjs/ui/screens/trust/trustTier.js.map +1 -0
- package/lib/commonjs/utils/deviceFlowSignIn.js +12 -10
- package/lib/commonjs/utils/deviceFlowSignIn.js.map +1 -1
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/AccountMenu.js +297 -226
- package/lib/module/ui/components/AccountMenu.js.map +1 -1
- package/lib/module/ui/components/AccountMenuButton.js.map +1 -1
- package/lib/module/ui/components/FollowButton.js +3 -1
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/OxySignInButton.js +1 -1
- package/lib/module/ui/components/SignInModal.js +11 -12
- package/lib/module/ui/components/SignInModal.js.map +1 -1
- package/lib/module/ui/components/accountMenuRows.js +18 -30
- package/lib/module/ui/components/accountMenuRows.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +58 -79
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +7 -13
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/hooks/useAuth.js +10 -40
- package/lib/module/ui/hooks/useAuth.js.map +1 -1
- package/lib/module/ui/hooks/useDeviceAccounts.js +281 -0
- package/lib/module/ui/hooks/useDeviceAccounts.js.map +1 -0
- package/lib/module/ui/hooks/useFollow.js +21 -7
- package/lib/module/ui/hooks/useFollow.js.map +1 -1
- package/lib/module/ui/hooks/useSessionManagement.js +5 -6
- package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/module/ui/hooks/useSessionSocket.js +4 -5
- package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/module/ui/hooks/useWebSSO.js +1 -1
- package/lib/module/ui/navigation/routes.js +7 -7
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/screens/OxyAuthScreen.js +6 -7
- package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +18 -20
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +4 -4
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/{karma/KarmaAboutScreen.js → trust/TrustAboutScreen.js} +11 -11
- package/lib/module/ui/screens/trust/TrustAboutScreen.js.map +1 -0
- package/lib/module/ui/screens/{karma/KarmaCenterScreen.js → trust/TrustCenterScreen.js} +92 -42
- package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -0
- package/lib/module/ui/screens/{karma/KarmaFAQScreen.js → trust/TrustFAQScreen.js} +11 -11
- package/lib/module/ui/screens/{karma/KarmaFAQScreen.js.map → trust/TrustFAQScreen.js.map} +1 -1
- package/lib/module/ui/screens/{karma/KarmaLeaderboardScreen.js → trust/TrustLeaderboardScreen.js} +63 -42
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -0
- package/lib/module/ui/screens/{karma/KarmaRewardsScreen.js → trust/TrustRewardsScreen.js} +54 -54
- package/lib/module/ui/screens/trust/TrustRewardsScreen.js.map +1 -0
- package/lib/module/ui/screens/{karma/KarmaRulesScreen.js → trust/TrustRulesScreen.js} +45 -16
- package/lib/module/ui/screens/trust/TrustRulesScreen.js.map +1 -0
- package/lib/module/ui/screens/trust/trustTier.js +19 -0
- package/lib/module/ui/screens/trust/trustTier.js.map +1 -0
- package/lib/module/utils/deviceFlowSignIn.js +13 -10
- package/lib/module/utils/deviceFlowSignIn.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +3 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts +30 -10
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/SignInModal.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/SignInModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/accountMenuRows.d.ts +19 -12
- package/lib/typescript/commonjs/ui/components/accountMenuRows.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +3 -3
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +1 -7
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts +3 -7
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useDeviceAccounts.d.ts +133 -0
- package/lib/typescript/commonjs/ui/hooks/useDeviceAccounts.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useFollow.d.ts +1 -1
- package/lib/typescript/commonjs/ui/hooks/useFollow.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSessionSocket.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useWebSSO.d.ts +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustAboutScreen.d.ts +5 -0
- package/lib/typescript/commonjs/ui/screens/{karma/KarmaAboutScreen.d.ts.map → trust/TrustAboutScreen.d.ts.map} +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustCenterScreen.d.ts +5 -0
- package/lib/typescript/commonjs/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -0
- package/lib/typescript/{module/ui/screens/karma/KarmaFAQScreen.d.ts → commonjs/ui/screens/trust/TrustFAQScreen.d.ts} +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/trust/TrustLeaderboardScreen.d.ts +5 -0
- package/lib/typescript/commonjs/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/trust/TrustRewardsScreen.d.ts +5 -0
- package/lib/typescript/commonjs/ui/screens/{karma/KarmaRewardsScreen.d.ts.map → trust/TrustRewardsScreen.d.ts.map} +1 -1
- package/lib/typescript/commonjs/ui/screens/trust/TrustRulesScreen.d.ts +5 -0
- package/lib/typescript/commonjs/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/screens/trust/trustTier.d.ts +9 -0
- package/lib/typescript/commonjs/ui/screens/trust/trustTier.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +1 -1
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts +11 -9
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +3 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/AccountMenu.d.ts +30 -10
- package/lib/typescript/module/ui/components/AccountMenu.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/SignInModal.d.ts +1 -1
- package/lib/typescript/module/ui/components/SignInModal.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/accountMenuRows.d.ts +19 -12
- package/lib/typescript/module/ui/components/accountMenuRows.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts +3 -3
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +1 -7
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts +3 -7
- package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useDeviceAccounts.d.ts +133 -0
- package/lib/typescript/module/ui/hooks/useDeviceAccounts.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useFollow.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/useFollow.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSessionSocket.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useWebSSO.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustAboutScreen.d.ts +5 -0
- package/lib/typescript/module/ui/screens/{karma/KarmaAboutScreen.d.ts.map → trust/TrustAboutScreen.d.ts.map} +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustCenterScreen.d.ts +5 -0
- package/lib/typescript/module/ui/screens/trust/TrustCenterScreen.d.ts.map +1 -0
- package/lib/typescript/{commonjs/ui/screens/karma/KarmaFAQScreen.d.ts → module/ui/screens/trust/TrustFAQScreen.d.ts} +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustFAQScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts +5 -0
- package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/trust/TrustRewardsScreen.d.ts +5 -0
- package/lib/typescript/module/ui/screens/{karma/KarmaRewardsScreen.d.ts.map → trust/TrustRewardsScreen.d.ts.map} +1 -1
- package/lib/typescript/module/ui/screens/trust/TrustRulesScreen.d.ts +5 -0
- package/lib/typescript/module/ui/screens/trust/TrustRulesScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/screens/trust/trustTier.d.ts +9 -0
- package/lib/typescript/module/ui/screens/trust/trustTier.d.ts.map +1 -0
- package/lib/typescript/module/ui/types/navigation.d.ts +1 -1
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts +11 -9
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +10 -1
- package/src/ui/components/AccountMenu.tsx +311 -253
- package/src/ui/components/AccountMenuButton.tsx +2 -2
- package/src/ui/components/FollowButton.tsx +2 -2
- package/src/ui/components/OxySignInButton.tsx +1 -1
- package/src/ui/components/SignInModal.tsx +13 -14
- package/src/ui/components/accountMenuRows.ts +28 -40
- package/src/ui/context/OxyContext.tsx +71 -74
- package/src/ui/context/hooks/useAuthOperations.ts +7 -13
- package/src/ui/hooks/useAuth.ts +12 -49
- package/src/ui/hooks/useDeviceAccounts.ts +348 -0
- package/src/ui/hooks/useFollow.ts +16 -8
- package/src/ui/hooks/useSessionManagement.ts +5 -14
- package/src/ui/hooks/useSessionSocket.ts +4 -5
- package/src/ui/hooks/useWebSSO.ts +1 -1
- package/src/ui/navigation/routes.ts +13 -13
- package/src/ui/screens/OxyAuthScreen.tsx +6 -7
- package/src/ui/screens/ProfileScreen.tsx +15 -17
- package/src/ui/screens/WelcomeNewUserScreen.tsx +2 -2
- package/src/ui/screens/{karma/KarmaAboutScreen.tsx → trust/TrustAboutScreen.tsx} +15 -15
- package/src/ui/screens/{karma/KarmaCenterScreen.tsx → trust/TrustCenterScreen.tsx} +87 -41
- package/src/ui/screens/{karma/KarmaFAQScreen.tsx → trust/TrustFAQScreen.tsx} +10 -10
- package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +101 -0
- package/src/ui/screens/{karma/KarmaRewardsScreen.tsx → trust/TrustRewardsScreen.tsx} +54 -54
- package/src/ui/screens/{karma/KarmaRulesScreen.tsx → trust/TrustRulesScreen.tsx} +27 -13
- package/src/ui/screens/trust/trustTier.ts +20 -0
- package/src/ui/types/navigation.ts +1 -2
- package/src/utils/__tests__/deviceFlowSignIn.test.ts +2 -3
- package/src/utils/deviceFlowSignIn.ts +18 -12
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +0 -1
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +0 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +0 -1
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +0 -1
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +0 -1
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +0 -1
- package/lib/typescript/commonjs/ui/screens/karma/KarmaAboutScreen.d.ts +0 -5
- package/lib/typescript/commonjs/ui/screens/karma/KarmaCenterScreen.d.ts +0 -5
- package/lib/typescript/commonjs/ui/screens/karma/KarmaCenterScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/karma/KarmaFAQScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/karma/KarmaLeaderboardScreen.d.ts +0 -5
- package/lib/typescript/commonjs/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/karma/KarmaRewardsScreen.d.ts +0 -5
- package/lib/typescript/commonjs/ui/screens/karma/KarmaRulesScreen.d.ts +0 -5
- package/lib/typescript/commonjs/ui/screens/karma/KarmaRulesScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/karma/KarmaAboutScreen.d.ts +0 -5
- package/lib/typescript/module/ui/screens/karma/KarmaCenterScreen.d.ts +0 -5
- package/lib/typescript/module/ui/screens/karma/KarmaCenterScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/karma/KarmaFAQScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/karma/KarmaLeaderboardScreen.d.ts +0 -5
- package/lib/typescript/module/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/karma/KarmaRewardsScreen.d.ts +0 -5
- package/lib/typescript/module/ui/screens/karma/KarmaRulesScreen.d.ts +0 -5
- package/lib/typescript/module/ui/screens/karma/KarmaRulesScreen.d.ts.map +0 -1
- package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +0 -88
|
@@ -142,13 +142,12 @@ const OxyAuthScreen: React.FC<BaseScreenProps> = ({
|
|
|
142
142
|
// `claimSessionByToken` — the device-flow equivalent of OAuth's
|
|
143
143
|
// code-for-token exchange (RFC 8628 §3.4).
|
|
144
144
|
//
|
|
145
|
-
// Without that exchange the SDK has no bearer token
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
// `switchSession` path. This mirrors `SignInModal`'s web flow exactly.
|
|
145
|
+
// Without that exchange the SDK has no bearer token — the session is
|
|
146
|
+
// authorized server-side but the app never becomes authenticated and the
|
|
147
|
+
// sheet sits "Waiting for authorization..." forever. Once
|
|
148
|
+
// `claimSessionByToken` plants the tokens in the HttpService, the rest of the
|
|
149
|
+
// session wiring flows through the normal `switchSession` path. This mirrors
|
|
150
|
+
// `SignInModal`'s web flow exactly.
|
|
152
151
|
const handleAuthSuccess = useCallback(async (sessionId: string, sessionToken: string) => {
|
|
153
152
|
if (isProcessingRef.current) return;
|
|
154
153
|
isProcessingRef.current = true;
|
|
@@ -32,7 +32,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
|
|
|
32
32
|
// Use useOxy() hook for OxyContext values
|
|
33
33
|
const { oxyServices, user: currentUser } = useOxy();
|
|
34
34
|
const [profile, setProfile] = useState<User | null>(null);
|
|
35
|
-
const [
|
|
35
|
+
const [reputationTotal, setReputationTotal] = useState<number | null>(null);
|
|
36
36
|
const [postsCount, setPostsCount] = useState<number | null>(null);
|
|
37
37
|
const [commentsCount, setCommentsCount] = useState<number | null>(null);
|
|
38
38
|
const [isLoading, setIsLoading] = useState(true);
|
|
@@ -77,7 +77,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
|
|
|
77
77
|
setIsLoading(true);
|
|
78
78
|
setError(null);
|
|
79
79
|
|
|
80
|
-
// Load user profile,
|
|
80
|
+
// Load user profile, reputation total, and stats
|
|
81
81
|
Promise.all([
|
|
82
82
|
oxyServices.getUserById(userId).catch((err: unknown) => {
|
|
83
83
|
// If this is the current user and the API call fails, use current user data as fallback
|
|
@@ -88,18 +88,16 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
|
|
|
88
88
|
}
|
|
89
89
|
throw err;
|
|
90
90
|
}),
|
|
91
|
-
oxyServices.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}) :
|
|
95
|
-
Promise.resolve({ total: undefined }),
|
|
91
|
+
oxyServices.getReputationBalance(userId)
|
|
92
|
+
.then((balance): { total: number | undefined } => ({ total: balance.total }))
|
|
93
|
+
.catch((): { total: number | undefined } => ({ total: undefined })),
|
|
96
94
|
oxyServices.getUserStats ?
|
|
97
95
|
oxyServices.getUserStats(userId).catch(() => {
|
|
98
96
|
return { postCount: 0, commentCount: 0 };
|
|
99
97
|
}) :
|
|
100
98
|
Promise.resolve({ postCount: 0, commentCount: 0 })
|
|
101
99
|
])
|
|
102
|
-
.then(([profileRes,
|
|
100
|
+
.then(([profileRes, reputationRes, statsRes]) => {
|
|
103
101
|
if (!profileRes) {
|
|
104
102
|
setError('Profile data is not available');
|
|
105
103
|
setIsLoading(false);
|
|
@@ -107,7 +105,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
|
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
setProfile(profileRes);
|
|
110
|
-
|
|
108
|
+
setReputationTotal(typeof reputationRes.total === 'number' ? reputationRes.total : null);
|
|
111
109
|
|
|
112
110
|
// Extract links from profile data
|
|
113
111
|
if (profileRes.linksMetadata && Array.isArray(profileRes.linksMetadata)) {
|
|
@@ -326,24 +324,24 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
|
|
|
326
324
|
{/* All Stats in one row */}
|
|
327
325
|
<View style={styles.statsRow}>
|
|
328
326
|
<View style={styles.statItem}>
|
|
329
|
-
<Text style={styles.
|
|
330
|
-
<Text style={styles.
|
|
327
|
+
<Text style={styles.statAmount} className="text-primary">{reputationTotal !== null && reputationTotal !== undefined ? reputationTotal : '--'}</Text>
|
|
328
|
+
<Text style={styles.statLabel} className="text-muted-foreground">{t('profile.reputation') || 'Reputation'}</Text>
|
|
331
329
|
</View>
|
|
332
330
|
<View style={styles.statItem}>
|
|
333
331
|
{isLoadingCounts ? (
|
|
334
332
|
<ActivityIndicator size="small" color={bloomTheme.colors.text} />
|
|
335
333
|
) : (
|
|
336
|
-
<Text style={styles.
|
|
334
|
+
<Text style={styles.statAmount} className="text-foreground">{followerCount !== null ? followerCount : '--'}</Text>
|
|
337
335
|
)}
|
|
338
|
-
<Text style={styles.
|
|
336
|
+
<Text style={styles.statLabel} className="text-muted-foreground">{t('profile.followers') || 'Followers'}</Text>
|
|
339
337
|
</View>
|
|
340
338
|
<View style={styles.statItem}>
|
|
341
339
|
{isLoadingCounts ? (
|
|
342
340
|
<ActivityIndicator size="small" color={bloomTheme.colors.text} />
|
|
343
341
|
) : (
|
|
344
|
-
<Text style={styles.
|
|
342
|
+
<Text style={styles.statAmount} className="text-foreground">{followingCount !== null ? followingCount : '--'}</Text>
|
|
345
343
|
)}
|
|
346
|
-
<Text style={styles.
|
|
344
|
+
<Text style={styles.statLabel} className="text-muted-foreground">{t('profile.following') || 'Following'}</Text>
|
|
347
345
|
</View>
|
|
348
346
|
</View>
|
|
349
347
|
</View>
|
|
@@ -401,8 +399,8 @@ const createStyles = () => StyleSheet.create({
|
|
|
401
399
|
},
|
|
402
400
|
statsRow: { width: '100%', flex: 1, flexDirection: 'row', alignItems: 'center', marginTop: 6, marginBottom: 2, justifyContent: 'space-between' },
|
|
403
401
|
statItem: { flex: 1, alignItems: 'center', minWidth: 50, marginBottom: 12 },
|
|
404
|
-
|
|
405
|
-
|
|
402
|
+
statLabel: { fontSize: 14, marginBottom: 2, textAlign: 'center' },
|
|
403
|
+
statAmount: { fontSize: 24, fontWeight: 'bold', textAlign: 'center', letterSpacing: 0.2 },
|
|
406
404
|
// Error handling styles
|
|
407
405
|
errorHeader: {
|
|
408
406
|
flexDirection: 'row',
|
|
@@ -115,9 +115,9 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: any }> = ({
|
|
|
115
115
|
t('welcomeNew.principles.bullets.3') || 'No selling your data',
|
|
116
116
|
]
|
|
117
117
|
},
|
|
118
|
-
{ key: '
|
|
118
|
+
{ key: 'trust', title: t('welcomeNew.trust.title') || 'Oxy Trust = Trust & Growth', body: t('welcomeNew.trust.body') || 'Oxy Trust is a reputation system that reacts to what you do. Helpful, respectful, constructive actions earn reputation. Harmful or low‑effort stuff chips it away. More reputation raises your trust tier and can unlock benefits; low reputation can limit features. It keeps things fair and rewards real contribution.' },
|
|
119
119
|
{ key: 'avatar', title: t('welcomeNew.avatar.title') || 'Make It Yours', body: t('welcomeNew.avatar.body') || 'Add an avatar so people recognize you. It will show anywhere you show up here. Skip if you want — you can add it later.', showAvatar: true },
|
|
120
|
-
{ key: 'ready', title: t('welcomeNew.ready.title') || "You're Ready", body: t('welcomeNew.ready.body') || 'Explore. Contribute. Earn
|
|
120
|
+
{ key: 'ready', title: t('welcomeNew.ready.title') || "You're Ready", body: t('welcomeNew.ready.body') || 'Explore. Contribute. Earn reputation. Stay in control.' }
|
|
121
121
|
];
|
|
122
122
|
const totalSteps = steps.length;
|
|
123
123
|
const avatarStepIndex = steps.findIndex(s => s.showAvatar);
|
|
@@ -5,40 +5,40 @@ import Header from '../../components/Header';
|
|
|
5
5
|
import { useI18n } from '../../hooks/useI18n';
|
|
6
6
|
import { useTheme } from '@oxyhq/bloom/theme';
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const TrustAboutScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
9
9
|
const { t } = useI18n();
|
|
10
10
|
const bloomTheme = useTheme();
|
|
11
|
-
// Override primaryColor for
|
|
11
|
+
// Override primaryColor for Oxy Trust screens (purple instead of blue)
|
|
12
12
|
const primaryColor = '#d169e5';
|
|
13
13
|
|
|
14
14
|
return (
|
|
15
15
|
<View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
|
|
16
16
|
<Header
|
|
17
|
-
title={t('
|
|
18
|
-
subtitle={t('
|
|
19
|
-
|
|
17
|
+
title={t('trust.about.title') || 'About Oxy Trust'}
|
|
18
|
+
subtitle={t('trust.about.subtitle') || 'Learn about the reputation system'}
|
|
19
|
+
|
|
20
20
|
onBack={goBack}
|
|
21
21
|
elevation="subtle"
|
|
22
22
|
/>
|
|
23
23
|
<ScrollView contentContainerStyle={styles.contentContainer}>
|
|
24
24
|
<Text style={[styles.paragraph, { color: bloomTheme.colors.text }]}>
|
|
25
|
-
{t('
|
|
25
|
+
{t('trust.about.intro') || 'Oxy Trust is a recognition of your positive actions in the Oxy Ecosystem. Reputation cannot be sent or received directly, only earned by contributing to the community.'}
|
|
26
26
|
</Text>
|
|
27
27
|
<Text style={[styles.section, { color: primaryColor }]}>
|
|
28
|
-
{t('
|
|
28
|
+
{t('trust.about.how.title') || 'How to Earn Reputation'}
|
|
29
29
|
</Text>
|
|
30
30
|
<Text style={[styles.paragraph, { color: bloomTheme.colors.text }]}>
|
|
31
|
-
• {t('
|
|
32
|
-
• {t('
|
|
33
|
-
• {t('
|
|
34
|
-
• {t('
|
|
35
|
-
• {t('
|
|
31
|
+
• {t('trust.about.how.help') || 'Helping other users'}{'\n'}
|
|
32
|
+
• {t('trust.about.how.report') || 'Reporting bugs'}{'\n'}
|
|
33
|
+
• {t('trust.about.how.contribute') || 'Contributing content'}{'\n'}
|
|
34
|
+
• {t('trust.about.how.participate') || 'Participating in events'}{'\n'}
|
|
35
|
+
• {t('trust.about.how.other') || 'Other positive actions'}
|
|
36
36
|
</Text>
|
|
37
37
|
<Text style={[styles.section, { color: primaryColor }]}>
|
|
38
|
-
{t('
|
|
38
|
+
{t('trust.about.why.title') || 'Why Oxy Trust?'}
|
|
39
39
|
</Text>
|
|
40
40
|
<Text style={[styles.paragraph, { color: bloomTheme.colors.text }]}>
|
|
41
|
-
{t('
|
|
41
|
+
{t('trust.about.why.text') || 'Your reputation and trust tier unlock special features and recognition in the Oxy Ecosystem. The more you contribute, the more you earn!'}
|
|
42
42
|
</Text>
|
|
43
43
|
</ScrollView>
|
|
44
44
|
</View>
|
|
@@ -63,4 +63,4 @@ const styles = StyleSheet.create({
|
|
|
63
63
|
paragraph: { fontSize: 16, marginBottom: 12 },
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
export default
|
|
66
|
+
export default TrustAboutScreen;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import {
|
|
4
4
|
View,
|
|
5
5
|
Text,
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
StyleSheet,
|
|
8
8
|
ActivityIndicator,
|
|
9
9
|
ScrollView,
|
|
10
|
-
Alert,
|
|
11
10
|
Platform,
|
|
12
11
|
} from 'react-native';
|
|
12
|
+
import type { ReputationTransaction, TrustTier } from '@oxyhq/core';
|
|
13
13
|
import type { BaseScreenProps } from '../../types/navigation';
|
|
14
14
|
import { Ionicons } from '@expo/vector-icons';
|
|
15
15
|
import { useI18n } from '../../hooks/useI18n';
|
|
@@ -19,8 +19,9 @@ import { Colors } from '../../constants/theme';
|
|
|
19
19
|
import { normalizeColorScheme } from '../../utils/themeUtils';
|
|
20
20
|
import { darkenColor } from '../../utils/colorUtils';
|
|
21
21
|
import { useOxy } from '../../context/OxyContext';
|
|
22
|
+
import { getTrustTierLabel } from './trustTier';
|
|
22
23
|
|
|
23
|
-
const
|
|
24
|
+
const TrustCenterScreen: React.FC<BaseScreenProps> = ({
|
|
24
25
|
theme,
|
|
25
26
|
navigate,
|
|
26
27
|
goBack,
|
|
@@ -28,8 +29,9 @@ const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
|
|
|
28
29
|
// Use useOxy() hook for OxyContext values
|
|
29
30
|
const { user, oxyServices, isAuthenticated } = useOxy();
|
|
30
31
|
const { t } = useI18n();
|
|
31
|
-
const [
|
|
32
|
-
const [
|
|
32
|
+
const [reputationTotal, setReputationTotal] = useState<number | null>(null);
|
|
33
|
+
const [trustTier, setTrustTier] = useState<TrustTier | null>(null);
|
|
34
|
+
const [transactions, setTransactions] = useState<ReputationTransaction[]>([]);
|
|
33
35
|
const [isLoading, setIsLoading] = useState(true);
|
|
34
36
|
const [error, setError] = useState<string | null>(null);
|
|
35
37
|
|
|
@@ -37,7 +39,7 @@ const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
|
|
|
37
39
|
const colorScheme = useColorScheme();
|
|
38
40
|
const normalizedColorScheme = normalizeColorScheme(colorScheme);
|
|
39
41
|
const themeColors = Colors[normalizedColorScheme];
|
|
40
|
-
// Override primaryColor for
|
|
42
|
+
// Override primaryColor for Oxy Trust screens (purple instead of blue)
|
|
41
43
|
const primaryColor = '#d169e5';
|
|
42
44
|
const dangerColor = bloomTheme.colors.error;
|
|
43
45
|
const mutedTextColor = bloomTheme.colors.textTertiary;
|
|
@@ -54,18 +56,27 @@ const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
|
|
|
54
56
|
setIsLoading(true);
|
|
55
57
|
setError(null);
|
|
56
58
|
Promise.all([
|
|
57
|
-
oxyServices.
|
|
58
|
-
oxyServices.
|
|
59
|
+
oxyServices.getReputationBalance(user.id),
|
|
60
|
+
oxyServices.getReputationTransactions(user.id, 20, 0),
|
|
59
61
|
])
|
|
60
|
-
.then(([
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
.then(([balance, txns]) => {
|
|
63
|
+
setReputationTotal(balance.total);
|
|
64
|
+
setTrustTier(balance.trustTier);
|
|
65
|
+
setTransactions(Array.isArray(txns) ? txns : []);
|
|
63
66
|
})
|
|
64
|
-
.catch((err) => {
|
|
65
|
-
setError(
|
|
67
|
+
.catch((err: unknown) => {
|
|
68
|
+
setError(
|
|
69
|
+
(err instanceof Error ? err.message : null) ||
|
|
70
|
+
(t('trust.center.loadError') || 'Failed to load reputation data'),
|
|
71
|
+
);
|
|
66
72
|
})
|
|
67
73
|
.finally(() => setIsLoading(false));
|
|
68
|
-
}, [user]);
|
|
74
|
+
}, [user, oxyServices, t]);
|
|
75
|
+
|
|
76
|
+
const trustTierLabel = useMemo(
|
|
77
|
+
() => (trustTier ? getTrustTierLabel(trustTier, t) : null),
|
|
78
|
+
[trustTier, t],
|
|
79
|
+
);
|
|
69
80
|
|
|
70
81
|
if (!isAuthenticated) {
|
|
71
82
|
return (
|
|
@@ -87,70 +98,81 @@ const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
|
|
|
87
98
|
<View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
|
|
88
99
|
<ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContainer}>
|
|
89
100
|
<View style={styles.walletHeader}>
|
|
90
|
-
<Text style={[styles.
|
|
91
|
-
<Text style={[styles.
|
|
92
|
-
{t('
|
|
101
|
+
<Text style={[styles.reputationAmount, { color: primaryColor }]}>{reputationTotal ?? 0}</Text>
|
|
102
|
+
<Text style={[styles.reputationLabel, { color: bloomTheme.colors.textTertiary }]}>
|
|
103
|
+
{t('trust.center.balance') || 'Reputation Balance'}
|
|
93
104
|
</Text>
|
|
105
|
+
{trustTierLabel && (
|
|
106
|
+
<View style={[styles.tierBadge, { borderColor: primaryColor }]}>
|
|
107
|
+
<Ionicons name="shield-checkmark-outline" size={14} color={primaryColor} />
|
|
108
|
+
<Text style={[styles.tierBadgeText, { color: primaryColor }]}>{trustTierLabel}</Text>
|
|
109
|
+
</View>
|
|
110
|
+
)}
|
|
94
111
|
<View style={styles.actionContainer}>
|
|
95
112
|
<View style={styles.actionRow}>
|
|
96
|
-
<TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate?.('
|
|
113
|
+
<TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate?.('TrustLeaderboard')}>
|
|
97
114
|
<View style={[styles.actionIcon, { backgroundColor: iconLeaderboard }]}>
|
|
98
115
|
<Ionicons name="trophy-outline" size={28} color={darkenColor(iconLeaderboard)} />
|
|
99
116
|
</View>
|
|
100
|
-
<Text style={[styles.actionLabel, { color: mutedTextColor }]}>{t('
|
|
117
|
+
<Text style={[styles.actionLabel, { color: mutedTextColor }]}>{t('trust.center.actions.leaderboard') || 'Leaderboard'}</Text>
|
|
101
118
|
</TouchableOpacity>
|
|
102
|
-
<TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate?.('
|
|
119
|
+
<TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate?.('TrustRules')}>
|
|
103
120
|
<View style={[styles.actionIcon, { backgroundColor: iconRules }]}>
|
|
104
121
|
<Ionicons name="document-text-outline" size={28} color={darkenColor(iconRules)} />
|
|
105
122
|
</View>
|
|
106
|
-
<Text style={[styles.actionLabel, { color: mutedTextColor }]}>{t('
|
|
123
|
+
<Text style={[styles.actionLabel, { color: mutedTextColor }]}>{t('trust.center.actions.rules') || 'Rules'}</Text>
|
|
107
124
|
</TouchableOpacity>
|
|
108
|
-
<TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate?.('
|
|
125
|
+
<TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate?.('AboutTrust')}>
|
|
109
126
|
<View style={[styles.actionIcon, { backgroundColor: iconAbout }]}>
|
|
110
127
|
<Ionicons name="star-outline" size={28} color={darkenColor(iconAbout)} />
|
|
111
128
|
</View>
|
|
112
|
-
<Text style={[styles.actionLabel, { color: mutedTextColor }]}>{t('
|
|
129
|
+
<Text style={[styles.actionLabel, { color: mutedTextColor }]}>{t('trust.center.actions.about') || 'About'}</Text>
|
|
113
130
|
</TouchableOpacity>
|
|
114
131
|
</View>
|
|
115
132
|
<View style={styles.actionRow}>
|
|
116
|
-
<TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate?.('
|
|
133
|
+
<TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate?.('TrustRewards')}>
|
|
117
134
|
<View style={[styles.actionIcon, { backgroundColor: iconRewards }]}>
|
|
118
135
|
<Ionicons name="gift-outline" size={28} color={darkenColor(iconRewards)} />
|
|
119
136
|
</View>
|
|
120
|
-
<Text style={[styles.actionLabel, { color: mutedTextColor }]}>{t('
|
|
137
|
+
<Text style={[styles.actionLabel, { color: mutedTextColor }]}>{t('trust.center.actions.rewards') || 'Rewards'}</Text>
|
|
121
138
|
</TouchableOpacity>
|
|
122
|
-
<TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate?.('
|
|
139
|
+
<TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate?.('TrustFAQ')}>
|
|
123
140
|
<View style={[styles.actionIcon, { backgroundColor: iconFAQ }]}>
|
|
124
141
|
<Ionicons name="help-circle-outline" size={28} color={darkenColor(iconFAQ)} />
|
|
125
142
|
</View>
|
|
126
|
-
<Text style={[styles.actionLabel, { color: mutedTextColor }]}>{t('
|
|
143
|
+
<Text style={[styles.actionLabel, { color: mutedTextColor }]}>{t('trust.center.actions.faq') || 'FAQ'}</Text>
|
|
127
144
|
</TouchableOpacity>
|
|
128
145
|
</View>
|
|
129
146
|
</View>
|
|
130
147
|
<Text style={[styles.infoText, { color: mutedTextColor }]}>
|
|
131
|
-
{t('
|
|
148
|
+
{t('trust.center.info') || 'Reputation can only be earned by positive actions in the Oxy Ecosystem. It cannot be sent or received directly.'}
|
|
132
149
|
</Text>
|
|
133
150
|
</View>
|
|
134
151
|
<Text style={[styles.sectionTitle, { color: bloomTheme.colors.text }]}>
|
|
135
|
-
{t('
|
|
152
|
+
{t('trust.center.history') || 'Reputation History'}
|
|
136
153
|
</Text>
|
|
137
154
|
<View style={styles.historyContainer}>
|
|
138
|
-
{
|
|
155
|
+
{transactions.length === 0 ? (
|
|
139
156
|
<Text style={{ color: bloomTheme.colors.text, textAlign: 'center', marginTop: 16 }}>
|
|
140
|
-
{t('
|
|
157
|
+
{t('trust.center.noHistory') || 'No reputation history yet.'}
|
|
141
158
|
</Text>
|
|
142
159
|
) : (
|
|
143
|
-
|
|
160
|
+
transactions.map((entry) => (
|
|
144
161
|
<View key={entry.id} style={[styles.historyItem, { borderColor: bloomTheme.colors.border }]}>
|
|
145
162
|
<Text style={[styles.historyPoints, { color: entry.points > 0 ? primaryColor : dangerColor }]}>
|
|
146
163
|
{entry.points > 0 ? '+' : ''}{entry.points}
|
|
147
164
|
</Text>
|
|
148
165
|
<Text style={[styles.historyDesc, { color: bloomTheme.colors.text }]}>
|
|
149
|
-
{entry.reason || (t('
|
|
150
|
-
</Text>
|
|
151
|
-
<Text style={[styles.historyDate, { color: bloomTheme.colors.textTertiary }]}>
|
|
152
|
-
{entry.createdAt ? new Date(entry.createdAt).toLocaleString() : ''}
|
|
166
|
+
{entry.reason || entry.actionType || (t('trust.center.noDescription') || 'No description')}
|
|
153
167
|
</Text>
|
|
168
|
+
<View style={styles.historyMetaRow}>
|
|
169
|
+
<Text style={[styles.historyCategory, { color: primaryColor }]}>
|
|
170
|
+
{entry.category}
|
|
171
|
+
</Text>
|
|
172
|
+
<Text style={[styles.historyDate, { color: bloomTheme.colors.textTertiary }]}>
|
|
173
|
+
{entry.createdAt ? new Date(entry.createdAt).toLocaleString() : ''}
|
|
174
|
+
</Text>
|
|
175
|
+
</View>
|
|
154
176
|
</View>
|
|
155
177
|
))
|
|
156
178
|
)}
|
|
@@ -179,15 +201,29 @@ const styles = StyleSheet.create({
|
|
|
179
201
|
width: '100%',
|
|
180
202
|
backgroundColor: 'transparent',
|
|
181
203
|
},
|
|
182
|
-
|
|
204
|
+
reputationLabel: {
|
|
183
205
|
fontSize: 16,
|
|
184
|
-
marginBottom:
|
|
206
|
+
marginBottom: 12,
|
|
185
207
|
},
|
|
186
|
-
|
|
208
|
+
reputationAmount: {
|
|
187
209
|
fontSize: 48,
|
|
188
210
|
fontWeight: 'bold',
|
|
189
211
|
marginBottom: 4,
|
|
190
212
|
},
|
|
213
|
+
tierBadge: {
|
|
214
|
+
flexDirection: 'row',
|
|
215
|
+
alignItems: 'center',
|
|
216
|
+
gap: 6,
|
|
217
|
+
borderWidth: 1,
|
|
218
|
+
borderRadius: 999,
|
|
219
|
+
paddingHorizontal: 12,
|
|
220
|
+
paddingVertical: 5,
|
|
221
|
+
marginBottom: 18,
|
|
222
|
+
},
|
|
223
|
+
tierBadgeText: {
|
|
224
|
+
fontSize: 13,
|
|
225
|
+
fontWeight: '600',
|
|
226
|
+
},
|
|
191
227
|
actionContainer: {
|
|
192
228
|
marginBottom: 18,
|
|
193
229
|
gap: 8,
|
|
@@ -248,9 +284,19 @@ const styles = StyleSheet.create({
|
|
|
248
284
|
fontSize: 15,
|
|
249
285
|
marginTop: 2,
|
|
250
286
|
},
|
|
287
|
+
historyMetaRow: {
|
|
288
|
+
flexDirection: 'row',
|
|
289
|
+
alignItems: 'center',
|
|
290
|
+
justifyContent: 'space-between',
|
|
291
|
+
marginTop: 2,
|
|
292
|
+
},
|
|
293
|
+
historyCategory: {
|
|
294
|
+
fontSize: 12,
|
|
295
|
+
fontWeight: '600',
|
|
296
|
+
textTransform: 'capitalize',
|
|
297
|
+
},
|
|
251
298
|
historyDate: {
|
|
252
299
|
fontSize: 13,
|
|
253
|
-
marginTop: 2,
|
|
254
300
|
},
|
|
255
301
|
|
|
256
302
|
message: {
|
|
@@ -260,4 +306,4 @@ const styles = StyleSheet.create({
|
|
|
260
306
|
},
|
|
261
307
|
});
|
|
262
308
|
|
|
263
|
-
export default
|
|
309
|
+
export default TrustCenterScreen;
|
|
@@ -13,15 +13,15 @@ import { Colors } from '../../constants/theme';
|
|
|
13
13
|
const FAQ_KEYS = ['what', 'earn', 'lose', 'use', 'transfer', 'support'] as const;
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* TrustFAQScreen - Optimized for performance
|
|
17
|
+
*
|
|
18
18
|
* Performance optimizations implemented:
|
|
19
19
|
* - useMemo for theme calculations (only recalculates when theme changes)
|
|
20
20
|
* - useMemo for filtered FAQs (only recalculates when search changes)
|
|
21
21
|
* - useCallback for event handlers to prevent unnecessary re-renders
|
|
22
22
|
* - React.memo wrapper to prevent re-renders when props haven't changed
|
|
23
23
|
*/
|
|
24
|
-
const
|
|
24
|
+
const TrustFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
25
25
|
const { t } = useI18n();
|
|
26
26
|
const [expanded, setExpanded] = useState<string | null>(null);
|
|
27
27
|
const [search, setSearch] = useState('');
|
|
@@ -35,8 +35,8 @@ const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
35
35
|
// Memoize filtered FAQs to prevent filtering on every render
|
|
36
36
|
const faqs = useMemo(() => FAQ_KEYS.map(key => ({
|
|
37
37
|
id: key,
|
|
38
|
-
q: t(`
|
|
39
|
-
a: t(`
|
|
38
|
+
q: t(`trust.faq.items.${key}.q`) || '',
|
|
39
|
+
a: t(`trust.faq.items.${key}.a`) || '',
|
|
40
40
|
})), [t]);
|
|
41
41
|
|
|
42
42
|
const filteredFaqs = useMemo(() => {
|
|
@@ -57,8 +57,8 @@ const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
57
57
|
return (
|
|
58
58
|
<View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
|
|
59
59
|
<Header
|
|
60
|
-
title={t('
|
|
61
|
-
subtitle={t('
|
|
60
|
+
title={t('trust.faq.title') || 'Trust FAQ'}
|
|
61
|
+
subtitle={t('trust.faq.subtitle') || 'Frequently asked questions about Oxy Trust'}
|
|
62
62
|
subtitleVariant="muted"
|
|
63
63
|
|
|
64
64
|
onBack={goBack}
|
|
@@ -72,7 +72,7 @@ const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
72
72
|
<Ionicons name="search" size={22} color={colors.icon} />
|
|
73
73
|
<TextInput
|
|
74
74
|
style={[styles.searchInput, { color: bloomTheme.colors.text }]}
|
|
75
|
-
placeholder={t('
|
|
75
|
+
placeholder={t('trust.faq.search') || 'Search FAQ...'}
|
|
76
76
|
placeholderTextColor={bloomTheme.colors.textTertiary}
|
|
77
77
|
value={search}
|
|
78
78
|
onChangeText={setSearch}
|
|
@@ -81,7 +81,7 @@ const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
81
81
|
</View>
|
|
82
82
|
{filteredFaqs.length === 0 ? (
|
|
83
83
|
<Text style={[styles.noResults, { color: colors.secondaryText }]}>
|
|
84
|
-
{t('
|
|
84
|
+
{t('trust.faq.noResults', { query: search }) || `No FAQ items found matching "${search}"`}
|
|
85
85
|
</Text>
|
|
86
86
|
) : (
|
|
87
87
|
<View style={styles.groupedSectionContainer}>
|
|
@@ -167,4 +167,4 @@ const styles = StyleSheet.create({
|
|
|
167
167
|
},
|
|
168
168
|
});
|
|
169
169
|
|
|
170
|
-
export default React.memo(
|
|
170
|
+
export default React.memo(TrustFAQScreen);
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { View, Text, StyleSheet, ScrollView, ActivityIndicator, TouchableOpacity } from 'react-native';
|
|
4
|
+
import type { ReputationLeaderboardEntry } from '@oxyhq/core';
|
|
5
|
+
import type { BaseScreenProps } from '../../types/navigation';
|
|
6
|
+
import Avatar from '../../components/Avatar';
|
|
7
|
+
import Header from '../../components/Header';
|
|
8
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
9
|
+
import { useTheme } from '@oxyhq/bloom/theme';
|
|
10
|
+
import { useOxy } from '../../context/OxyContext';
|
|
11
|
+
import { getTrustTierLabel } from './trustTier';
|
|
12
|
+
|
|
13
|
+
const TrustLeaderboardScreen: React.FC<BaseScreenProps> = ({ goBack, theme, navigate }) => {
|
|
14
|
+
// Use useOxy() hook for OxyContext values
|
|
15
|
+
const { oxyServices } = useOxy();
|
|
16
|
+
const { t } = useI18n();
|
|
17
|
+
const [leaderboard, setLeaderboard] = useState<ReputationLeaderboardEntry[]>([]);
|
|
18
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
19
|
+
const [error, setError] = useState<string | null>(null);
|
|
20
|
+
|
|
21
|
+
const bloomTheme = useTheme();
|
|
22
|
+
// Override primaryColor for Oxy Trust screens (purple instead of blue)
|
|
23
|
+
const primaryColor = '#d169e5';
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
setIsLoading(true);
|
|
27
|
+
setError(null);
|
|
28
|
+
oxyServices.getReputationLeaderboard()
|
|
29
|
+
.then((data) => setLeaderboard(Array.isArray(data) ? data : []))
|
|
30
|
+
.catch((err: unknown) => setError((err instanceof Error ? err.message : null) || 'Failed to load leaderboard'))
|
|
31
|
+
.finally(() => setIsLoading(false));
|
|
32
|
+
}, [oxyServices]);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
|
|
36
|
+
<Header
|
|
37
|
+
title={t('trust.leaderboard.title') || 'Trust Leaderboard'}
|
|
38
|
+
subtitle={t('trust.leaderboard.subtitle') || 'Top contributors in the community'}
|
|
39
|
+
|
|
40
|
+
onBack={goBack}
|
|
41
|
+
elevation="subtle"
|
|
42
|
+
/>
|
|
43
|
+
{isLoading ? (
|
|
44
|
+
<ActivityIndicator size="large" color={primaryColor} style={{ marginTop: 40 }} />
|
|
45
|
+
) : error ? (
|
|
46
|
+
<Text style={[styles.error, { color: bloomTheme.colors.error }]}>{error}</Text>
|
|
47
|
+
) : (
|
|
48
|
+
<ScrollView contentContainerStyle={styles.listContainer}>
|
|
49
|
+
{leaderboard.length === 0 ? (
|
|
50
|
+
<Text style={[styles.placeholder, { color: bloomTheme.colors.text }]}>{t('trust.leaderboard.empty') || 'No leaderboard data.'}</Text>
|
|
51
|
+
) : (
|
|
52
|
+
leaderboard.map((entry) => {
|
|
53
|
+
const username = entry.user.username;
|
|
54
|
+
const displayName = username || entry.user.id;
|
|
55
|
+
return (
|
|
56
|
+
<TouchableOpacity
|
|
57
|
+
key={entry.user.id}
|
|
58
|
+
style={[styles.row, { borderColor: bloomTheme.colors.border }, entry.rank <= 3 && { backgroundColor: bloomTheme.colors.primarySubtle }]}
|
|
59
|
+
onPress={() => navigate?.('Profile', { userId: entry.user.id, username })}
|
|
60
|
+
activeOpacity={0.7}
|
|
61
|
+
>
|
|
62
|
+
<Text style={[styles.rank, { color: primaryColor }]}>{entry.rank}</Text>
|
|
63
|
+
<Avatar name={username || 'User'} size={40} style={styles.avatar} />
|
|
64
|
+
<View style={styles.userColumn}>
|
|
65
|
+
<Text style={[styles.username, { color: bloomTheme.colors.text }]} numberOfLines={1}>{displayName}</Text>
|
|
66
|
+
<Text style={[styles.tier, { color: bloomTheme.colors.textTertiary }]} numberOfLines={1}>
|
|
67
|
+
{getTrustTierLabel(entry.trustTier, t)}
|
|
68
|
+
</Text>
|
|
69
|
+
</View>
|
|
70
|
+
<Text style={[styles.reputation, { color: primaryColor }]}>{entry.total}</Text>
|
|
71
|
+
</TouchableOpacity>
|
|
72
|
+
);
|
|
73
|
+
})
|
|
74
|
+
)}
|
|
75
|
+
</ScrollView>
|
|
76
|
+
)}
|
|
77
|
+
</View>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const styles = StyleSheet.create({
|
|
82
|
+
container: { flex: 1 },
|
|
83
|
+
listContainer: { paddingBottom: 40, paddingTop: 20 },
|
|
84
|
+
row: {
|
|
85
|
+
flexDirection: 'row',
|
|
86
|
+
alignItems: 'center',
|
|
87
|
+
paddingVertical: 12,
|
|
88
|
+
paddingHorizontal: 20,
|
|
89
|
+
borderBottomWidth: 1,
|
|
90
|
+
},
|
|
91
|
+
rank: { fontSize: 20, width: 32, textAlign: 'center', fontWeight: 'bold' },
|
|
92
|
+
avatar: { marginHorizontal: 8 },
|
|
93
|
+
userColumn: { flex: 1, marginLeft: 8 },
|
|
94
|
+
username: { fontSize: 16 },
|
|
95
|
+
tier: { fontSize: 12, marginTop: 1 },
|
|
96
|
+
reputation: { fontSize: 18, fontWeight: 'bold', marginLeft: 12 },
|
|
97
|
+
placeholder: { fontSize: 16, textAlign: 'center', marginTop: 40 },
|
|
98
|
+
error: { fontSize: 16, textAlign: 'center', marginTop: 40 },
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
export default TrustLeaderboardScreen;
|