@oxyhq/services 5.8.1 → 5.8.3

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 (137) hide show
  1. package/lib/commonjs/index.js +9 -27
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/node/createAuth.js +7 -585
  4. package/lib/commonjs/node/createAuth.js.map +1 -1
  5. package/lib/commonjs/node/index.js +1 -38
  6. package/lib/commonjs/node/index.js.map +1 -1
  7. package/lib/commonjs/ui/components/FollowButton.js +100 -12
  8. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  9. package/lib/commonjs/ui/components/Header.js +40 -6
  10. package/lib/commonjs/ui/components/Header.js.map +1 -1
  11. package/lib/commonjs/ui/components/OxyProvider.js +5 -0
  12. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  13. package/lib/commonjs/ui/context/OxyContext.js +63 -125
  14. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  15. package/lib/commonjs/ui/hooks/index.js +6 -0
  16. package/lib/commonjs/ui/hooks/index.js.map +1 -1
  17. package/lib/commonjs/ui/hooks/useFollow.js +59 -2
  18. package/lib/commonjs/ui/hooks/useFollow.js.map +1 -1
  19. package/lib/commonjs/ui/navigation/OxyRouter.js +10 -0
  20. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  21. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +9 -0
  22. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  23. package/lib/commonjs/ui/screens/ProfileScreen.js +214 -37
  24. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  25. package/lib/commonjs/ui/screens/UserLinksScreen.js +90 -0
  26. package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -0
  27. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +9 -6
  28. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +3 -30
  30. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  31. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +37 -46
  32. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  33. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +9 -12
  34. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  35. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +9 -12
  36. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +9 -12
  38. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  39. package/lib/commonjs/ui/stores/authStore.js +24 -6
  40. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  41. package/lib/commonjs/ui/stores/followStore.js +106 -1
  42. package/lib/commonjs/ui/stores/followStore.js.map +1 -1
  43. package/lib/module/index.js +1 -3
  44. package/lib/module/index.js.map +1 -1
  45. package/lib/module/node/createAuth.js +7 -584
  46. package/lib/module/node/createAuth.js.map +1 -1
  47. package/lib/module/node/index.js +1 -7
  48. package/lib/module/node/index.js.map +1 -1
  49. package/lib/module/ui/components/FollowButton.js +101 -13
  50. package/lib/module/ui/components/FollowButton.js.map +1 -1
  51. package/lib/module/ui/components/Header.js +40 -6
  52. package/lib/module/ui/components/Header.js.map +1 -1
  53. package/lib/module/ui/components/OxyProvider.js +5 -0
  54. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  55. package/lib/module/ui/context/OxyContext.js +63 -125
  56. package/lib/module/ui/context/OxyContext.js.map +1 -1
  57. package/lib/module/ui/hooks/index.js +1 -1
  58. package/lib/module/ui/hooks/index.js.map +1 -1
  59. package/lib/module/ui/hooks/useFollow.js +57 -1
  60. package/lib/module/ui/hooks/useFollow.js.map +1 -1
  61. package/lib/module/ui/navigation/OxyRouter.js +10 -0
  62. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  63. package/lib/module/ui/screens/AccountSettingsScreen.js +9 -0
  64. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  65. package/lib/module/ui/screens/ProfileScreen.js +214 -37
  66. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  67. package/lib/module/ui/screens/UserLinksScreen.js +85 -0
  68. package/lib/module/ui/screens/UserLinksScreen.js.map +1 -0
  69. package/lib/module/ui/screens/karma/KarmaAboutScreen.js +9 -6
  70. package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  71. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +3 -30
  72. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  73. package/lib/module/ui/screens/karma/KarmaFAQScreen.js +37 -46
  74. package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  75. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +9 -12
  76. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  77. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +9 -12
  78. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  79. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +9 -12
  80. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  81. package/lib/module/ui/stores/authStore.js +24 -6
  82. package/lib/module/ui/stores/authStore.js.map +1 -1
  83. package/lib/module/ui/stores/followStore.js +106 -1
  84. package/lib/module/ui/stores/followStore.js.map +1 -1
  85. package/lib/typescript/index.d.ts +1 -1
  86. package/lib/typescript/index.d.ts.map +1 -1
  87. package/lib/typescript/node/createAuth.d.ts +0 -112
  88. package/lib/typescript/node/createAuth.d.ts.map +1 -1
  89. package/lib/typescript/node/index.d.ts +0 -2
  90. package/lib/typescript/node/index.d.ts.map +1 -1
  91. package/lib/typescript/ui/components/FollowButton.d.ts +1 -0
  92. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  93. package/lib/typescript/ui/components/Header.d.ts +2 -0
  94. package/lib/typescript/ui/components/Header.d.ts.map +1 -1
  95. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  96. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  97. package/lib/typescript/ui/hooks/index.d.ts +1 -1
  98. package/lib/typescript/ui/hooks/index.d.ts.map +1 -1
  99. package/lib/typescript/ui/hooks/useFollow.d.ts +20 -0
  100. package/lib/typescript/ui/hooks/useFollow.d.ts.map +1 -1
  101. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
  102. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  103. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
  104. package/lib/typescript/ui/screens/UserLinksScreen.d.ts +15 -0
  105. package/lib/typescript/ui/screens/UserLinksScreen.d.ts.map +1 -0
  106. package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -1
  107. package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -1
  108. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -1
  109. package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -1
  110. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
  111. package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -1
  112. package/lib/typescript/ui/stores/authStore.d.ts +3 -1
  113. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  114. package/lib/typescript/ui/stores/followStore.d.ts +10 -0
  115. package/lib/typescript/ui/stores/followStore.d.ts.map +1 -1
  116. package/package.json +3 -2
  117. package/src/index.ts +2 -10
  118. package/src/node/createAuth.ts +7 -623
  119. package/src/node/index.ts +1 -19
  120. package/src/ui/components/FollowButton.tsx +95 -11
  121. package/src/ui/components/Header.tsx +45 -4
  122. package/src/ui/components/OxyProvider.tsx +6 -0
  123. package/src/ui/context/OxyContext.tsx +65 -136
  124. package/src/ui/hooks/index.ts +1 -1
  125. package/src/ui/hooks/useFollow.ts +63 -0
  126. package/src/ui/navigation/OxyRouter.tsx +10 -0
  127. package/src/ui/screens/AccountSettingsScreen.tsx +8 -0
  128. package/src/ui/screens/ProfileScreen.tsx +191 -28
  129. package/src/ui/screens/UserLinksScreen.tsx +96 -0
  130. package/src/ui/screens/karma/KarmaAboutScreen.tsx +9 -2
  131. package/src/ui/screens/karma/KarmaCenterScreen.tsx +1 -20
  132. package/src/ui/screens/karma/KarmaFAQScreen.tsx +40 -24
  133. package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +9 -3
  134. package/src/ui/screens/karma/KarmaRewardsScreen.tsx +9 -3
  135. package/src/ui/screens/karma/KarmaRulesScreen.tsx +9 -3
  136. package/src/ui/stores/authStore.ts +22 -7
  137. package/src/ui/stores/followStore.ts +102 -1
@@ -2,6 +2,7 @@ import React, { useState, useMemo, useCallback } from 'react';
2
2
  import { View, Text, StyleSheet, ScrollView, Platform, TouchableOpacity, TextInput, LayoutAnimation, UIManager } from 'react-native';
3
3
  import { BaseScreenProps } from '../../navigation/types';
4
4
  import { Ionicons } from '@expo/vector-icons';
5
+ import { Header } from '../../components';
5
6
 
6
7
  if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
7
8
  UIManager.setLayoutAnimationEnabledExperimental(true);
@@ -79,7 +80,14 @@ const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
79
80
 
80
81
  return (
81
82
  <View style={[styles.container, { backgroundColor: themeStyles.backgroundColor }]}>
82
- <Text style={[styles.title, { color: themeStyles.textColor }]}>Karma FAQ</Text>
83
+ <Header
84
+ title="Karma FAQ"
85
+ subtitle="Frequently asked questions about karma"
86
+ subtitleVariant="muted"
87
+ theme={theme}
88
+ onBack={goBack}
89
+ elevation="subtle"
90
+ />
83
91
  <View style={[styles.searchBar, { backgroundColor: themeStyles.inputBg, borderColor: themeStyles.inputBorder }]}>
84
92
  <Ionicons name="search-outline" size={20} color={themeStyles.primaryColor} style={{ marginRight: 8 }} />
85
93
  <TextInput
@@ -91,31 +99,37 @@ const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
91
99
  returnKeyType="search"
92
100
  />
93
101
  </View>
94
- <ScrollView contentContainerStyle={styles.contentContainer} keyboardShouldPersistTaps="handled">
102
+ <ScrollView contentContainerStyle={styles.contentContainer}>
95
103
  {filteredFaqs.length === 0 ? (
96
- <Text style={[styles.noResults, { color: themeStyles.textColor }]}>No results found.</Text>
104
+ <Text style={[styles.noResults, { color: themeStyles.textColor }]}>
105
+ No FAQ items found matching "{search}"
106
+ </Text>
97
107
  ) : (
98
- filteredFaqs.map((item, idx) => {
99
- const isOpen = expanded === idx;
100
- return (
101
- <TouchableOpacity
102
- key={idx}
103
- style={[styles.card, { backgroundColor: themeStyles.cardColor, shadowColor: themeStyles.isDarkTheme ? '#000' : '#d169e5' }]}
104
- activeOpacity={0.95}
105
- onPress={() => handleToggle(idx)}
106
- >
107
- <View style={styles.questionRow}>
108
- <Ionicons name={isOpen ? 'chevron-down' : 'chevron-forward'} size={22} color={themeStyles.primaryColor} style={{ marginRight: 8 }} />
109
- <Text style={[styles.question, { color: themeStyles.primaryColor }]}>{item.q}</Text>
110
- </View>
111
- {isOpen && (
112
- <Text style={[styles.answer, { color: themeStyles.textColor }]}>{item.a}</Text>
113
- )}
114
- </TouchableOpacity>
115
- );
116
- })
108
+ filteredFaqs.map((faq, idx) => (
109
+ <TouchableOpacity
110
+ key={idx}
111
+ style={[styles.card, { backgroundColor: themeStyles.cardColor }]}
112
+ onPress={() => handleToggle(idx)}
113
+ activeOpacity={0.7}
114
+ >
115
+ <View style={styles.questionRow}>
116
+ <Text style={[styles.question, { color: themeStyles.textColor }]}>
117
+ {faq.q}
118
+ </Text>
119
+ <Ionicons
120
+ name={expanded === idx ? 'chevron-up' : 'chevron-down'}
121
+ size={20}
122
+ color={themeStyles.primaryColor}
123
+ />
124
+ </View>
125
+ {expanded === idx && (
126
+ <Text style={[styles.answer, { color: themeStyles.textColor }]}>
127
+ {faq.a}
128
+ </Text>
129
+ )}
130
+ </TouchableOpacity>
131
+ ))
117
132
  )}
118
- <Text style={[styles.paragraph, { color: themeStyles.textColor, marginTop: 32, textAlign: 'center' }]}>Still have questions? Contact support!</Text>
119
133
  </ScrollView>
120
134
  </View>
121
135
  );
@@ -146,7 +160,7 @@ const styles = StyleSheet.create({
146
160
  fontSize: 16,
147
161
  height: 44,
148
162
  },
149
- contentContainer: { padding: 24, paddingBottom: 40 },
163
+ contentContainer: { padding: 24, paddingTop: 20, paddingBottom: 40 },
150
164
  card: {
151
165
  borderRadius: 18,
152
166
  padding: 20,
@@ -159,11 +173,13 @@ const styles = StyleSheet.create({
159
173
  questionRow: {
160
174
  flexDirection: 'row',
161
175
  alignItems: 'center',
176
+ justifyContent: 'space-between',
162
177
  marginBottom: 8,
163
178
  },
164
179
  question: {
165
180
  fontSize: 17,
166
181
  fontWeight: 'bold',
182
+ flex: 1,
167
183
  },
168
184
  answer: {
169
185
  fontSize: 16,
@@ -3,6 +3,7 @@ import { View, Text, StyleSheet, ScrollView, ActivityIndicator, TouchableOpacity
3
3
  import { BaseScreenProps } from '../../navigation/types';
4
4
  import { useOxy } from '../../context/OxyContext';
5
5
  import Avatar from '../../components/Avatar';
6
+ import { Header } from '../../components';
6
7
 
7
8
  const KarmaLeaderboardScreen: React.FC<BaseScreenProps> = ({ goBack, theme, navigate }) => {
8
9
  const { oxyServices } = useOxy();
@@ -26,7 +27,13 @@ const KarmaLeaderboardScreen: React.FC<BaseScreenProps> = ({ goBack, theme, navi
26
27
 
27
28
  return (
28
29
  <View style={[styles.container, { backgroundColor }]}>
29
- <Text style={[styles.title, { color: textColor }]}>Karma Leaderboard</Text>
30
+ <Header
31
+ title="Karma Leaderboard"
32
+ subtitle="Top contributors in the community"
33
+ theme={theme}
34
+ onBack={goBack}
35
+ elevation="subtle"
36
+ />
30
37
  {isLoading ? (
31
38
  <ActivityIndicator size="large" color={primaryColor} style={{ marginTop: 40 }} />
32
39
  ) : error ? (
@@ -58,8 +65,7 @@ const KarmaLeaderboardScreen: React.FC<BaseScreenProps> = ({ goBack, theme, navi
58
65
 
59
66
  const styles = StyleSheet.create({
60
67
  container: { flex: 1 },
61
- title: { fontSize: 24, fontWeight: 'bold', margin: 24, textAlign: 'center' },
62
- listContainer: { paddingBottom: 40 },
68
+ listContainer: { paddingBottom: 40, paddingTop: 20 },
63
69
  row: {
64
70
  flexDirection: 'row',
65
71
  alignItems: 'center',
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { View, Text, StyleSheet, ScrollView, Platform } from 'react-native';
3
3
  import { BaseScreenProps } from '../../navigation/types';
4
+ import { Header } from '../../components';
4
5
 
5
6
  const KarmaRewardsScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
6
7
  const isDarkTheme = theme === 'dark';
@@ -11,7 +12,13 @@ const KarmaRewardsScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
11
12
  // Placeholder: In a real app, fetch rewards from API
12
13
  return (
13
14
  <View style={[styles.container, { backgroundColor }]}>
14
- <Text style={[styles.title, { color: textColor }]}>Karma Rewards</Text>
15
+ <Header
16
+ title="Karma Rewards"
17
+ subtitle="Unlock special features and recognition"
18
+ theme={theme}
19
+ onBack={goBack}
20
+ elevation="subtle"
21
+ />
15
22
  <ScrollView contentContainerStyle={styles.contentContainer}>
16
23
  <Text style={[styles.paragraph, { color: textColor }]}>Unlock special features and recognition by earning karma!</Text>
17
24
  <View style={styles.rewardBox}>
@@ -34,8 +41,7 @@ const KarmaRewardsScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
34
41
 
35
42
  const styles = StyleSheet.create({
36
43
  container: { flex: 1 },
37
- title: { fontSize: 24, fontWeight: 'bold', margin: 24, textAlign: 'center' },
38
- contentContainer: { padding: 24 },
44
+ contentContainer: { padding: 24, paddingTop: 20 },
39
45
  rewardBox: {
40
46
  backgroundColor: '#f7eaff',
41
47
  borderRadius: 16,
@@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react';
2
2
  import { View, Text, StyleSheet, ScrollView, ActivityIndicator } from 'react-native';
3
3
  import { BaseScreenProps } from '../../navigation/types';
4
4
  import { useOxy } from '../../context/OxyContext';
5
+ import { Header } from '../../components';
5
6
 
6
7
  const KarmaRulesScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
7
8
  const { oxyServices } = useOxy();
@@ -25,7 +26,13 @@ const KarmaRulesScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
25
26
 
26
27
  return (
27
28
  <View style={[styles.container, { backgroundColor }]}>
28
- <Text style={[styles.title, { color: textColor }]}>Karma Rules</Text>
29
+ <Header
30
+ title="Karma Rules"
31
+ subtitle="How to earn karma points"
32
+ theme={theme}
33
+ onBack={goBack}
34
+ elevation="subtle"
35
+ />
29
36
  {isLoading ? (
30
37
  <ActivityIndicator size="large" color={primaryColor} style={{ marginTop: 40 }} />
31
38
  ) : error ? (
@@ -49,8 +56,7 @@ const KarmaRulesScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
49
56
 
50
57
  const styles = StyleSheet.create({
51
58
  container: { flex: 1 },
52
- title: { fontSize: 24, fontWeight: 'bold', margin: 24, textAlign: 'center' },
53
- listContainer: { paddingBottom: 40 },
59
+ listContainer: { paddingBottom: 40, paddingTop: 20 },
54
60
  ruleRow: {
55
61
  paddingVertical: 14,
56
62
  paddingHorizontal: 24,
@@ -6,24 +6,39 @@ interface AuthState {
6
6
  isAuthenticated: boolean;
7
7
  isLoading: boolean;
8
8
  error: string | null;
9
+ lastUserFetch: number | null; // Timestamp of last user fetch for caching
9
10
  loginStart: () => void;
10
11
  loginSuccess: (user: User) => void;
11
12
  loginFailure: (error: string) => void;
12
13
  logout: () => void;
13
- fetchUser: (oxyServices: any) => Promise<void>;
14
+ fetchUser: (oxyServices: any, forceRefresh?: boolean) => Promise<void>;
14
15
  updateUser: (updates: Partial<User>, oxyServices: any) => Promise<void>;
16
+ setUser: (user: User) => void; // Direct user setter for caching
15
17
  }
16
18
 
17
- export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>) => void) => ({
19
+ export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>) => void, get: () => AuthState) => ({
18
20
  user: null,
19
21
  isAuthenticated: false,
20
22
  isLoading: false,
21
23
  error: null,
24
+ lastUserFetch: null,
22
25
  loginStart: () => set({ isLoading: true, error: null }),
23
- loginSuccess: (user: User) => set({ isLoading: false, isAuthenticated: true, user }),
26
+ loginSuccess: (user: User) => set({ isLoading: false, isAuthenticated: true, user, lastUserFetch: Date.now() }),
24
27
  loginFailure: (error: string) => set({ isLoading: false, error }),
25
- logout: () => set({ user: null, isAuthenticated: false }),
26
- fetchUser: async (oxyServices) => {
28
+ logout: () => set({ user: null, isAuthenticated: false, lastUserFetch: null }),
29
+ setUser: (user: User) => set({ user, lastUserFetch: Date.now() }),
30
+ fetchUser: async (oxyServices, forceRefresh = false) => {
31
+ const state = get();
32
+ const now = Date.now();
33
+ const cacheAge = state.lastUserFetch ? now - state.lastUserFetch : Infinity;
34
+ const cacheValid = cacheAge < 5 * 60 * 1000; // 5 minutes cache
35
+
36
+ // Use cached data if available and not forcing refresh
37
+ if (!forceRefresh && state.user && cacheValid) {
38
+ console.log('AuthStore: Using cached user data (age:', cacheAge, 'ms)');
39
+ return;
40
+ }
41
+
27
42
  set({ isLoading: true, error: null });
28
43
  try {
29
44
  console.log('AuthStore: Fetching user data...');
@@ -34,7 +49,7 @@ export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>)
34
49
  userLinks: user?.links,
35
50
  userWebsite: user?.website
36
51
  });
37
- set({ user, isLoading: false, isAuthenticated: true });
52
+ set({ user, isLoading: false, isAuthenticated: true, lastUserFetch: now });
38
53
  } catch (error: any) {
39
54
  console.error('AuthStore: Error fetching user:', error);
40
55
  set({ error: error.message || 'Failed to fetch user', isLoading: false });
@@ -47,7 +62,7 @@ export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>)
47
62
  await oxyServices.updateProfile(updates);
48
63
  console.log('AuthStore: Profile updated successfully');
49
64
  // Immediately fetch the latest user data after update
50
- await useAuthStore.getState().fetchUser(oxyServices);
65
+ await useAuthStore.getState().fetchUser(oxyServices, true); // Force refresh
51
66
  console.log('AuthStore: User data refreshed');
52
67
  } catch (error: any) {
53
68
  console.error('AuthStore: Error updating user:', error);
@@ -6,11 +6,21 @@ interface FollowState {
6
6
  loadingUsers: Record<string, boolean>;
7
7
  fetchingUsers: Record<string, boolean>;
8
8
  errors: Record<string, string | null>;
9
+ // Follower counts for each user
10
+ followerCounts: Record<string, number>;
11
+ followingCounts: Record<string, number>;
12
+ // Loading states for counts
13
+ loadingCounts: Record<string, boolean>;
9
14
  setFollowingStatus: (userId: string, isFollowing: boolean) => void;
10
15
  clearFollowError: (userId: string) => void;
11
16
  resetFollowState: () => void;
12
17
  fetchFollowStatus: (userId: string, oxyServices: OxyServices) => Promise<void>;
13
18
  toggleFollowUser: (userId: string, oxyServices: OxyServices, isCurrentlyFollowing: boolean) => Promise<void>;
19
+ // New methods for follower counts
20
+ setFollowerCount: (userId: string, count: number) => void;
21
+ setFollowingCount: (userId: string, count: number) => void;
22
+ updateCountsFromFollowAction: (targetUserId: string, action: 'follow' | 'unfollow', counts: { followers: number; following: number }, currentUserId?: string) => void;
23
+ fetchUserCounts: (userId: string, oxyServices: OxyServices) => Promise<void>;
14
24
  }
15
25
 
16
26
  export const useFollowStore = create<FollowState>((set: any, get: any) => ({
@@ -18,6 +28,9 @@ export const useFollowStore = create<FollowState>((set: any, get: any) => ({
18
28
  loadingUsers: {},
19
29
  fetchingUsers: {},
20
30
  errors: {},
31
+ followerCounts: {},
32
+ followingCounts: {},
33
+ loadingCounts: {},
21
34
  setFollowingStatus: (userId: string, isFollowing: boolean) => set((state: FollowState) => ({
22
35
  followingUsers: { ...state.followingUsers, [userId]: isFollowing },
23
36
  errors: { ...state.errors, [userId]: null },
@@ -30,6 +43,9 @@ export const useFollowStore = create<FollowState>((set: any, get: any) => ({
30
43
  loadingUsers: {},
31
44
  fetchingUsers: {},
32
45
  errors: {},
46
+ followerCounts: {},
47
+ followingCounts: {},
48
+ loadingCounts: {},
33
49
  }),
34
50
  fetchFollowStatus: async (userId: string, oxyServices: OxyServices) => {
35
51
  set((state: FollowState) => ({
@@ -56,7 +72,7 @@ export const useFollowStore = create<FollowState>((set: any, get: any) => ({
56
72
  errors: { ...state.errors, [userId]: null },
57
73
  }));
58
74
  try {
59
- let response;
75
+ let response: any;
60
76
  let newFollowState;
61
77
  if (isCurrentlyFollowing) {
62
78
  response = await oxyServices.unfollowUser(userId);
@@ -65,11 +81,44 @@ export const useFollowStore = create<FollowState>((set: any, get: any) => ({
65
81
  response = await oxyServices.followUser(userId);
66
82
  newFollowState = true;
67
83
  }
84
+
85
+ // Update follow status
68
86
  set((state: FollowState) => ({
69
87
  followingUsers: { ...state.followingUsers, [userId]: newFollowState },
70
88
  loadingUsers: { ...state.loadingUsers, [userId]: false },
71
89
  errors: { ...state.errors, [userId]: null },
72
90
  }));
91
+
92
+ // Update counts if the response includes them
93
+ // The API returns counts for both users:
94
+ // - followers: target user's follower count (the user being followed)
95
+ // - following: current user's following count (the user doing the following)
96
+ if (response && response.counts) {
97
+ const { counts } = response;
98
+
99
+ // Get current user ID from oxyServices
100
+ const currentUserId = oxyServices.getCurrentUserId();
101
+
102
+ set((state: FollowState) => {
103
+ const updates: any = {};
104
+
105
+ // Update target user's follower count (the user being followed)
106
+ updates.followerCounts = {
107
+ ...state.followerCounts,
108
+ [userId]: counts.followers
109
+ };
110
+
111
+ // Update current user's following count (the user doing the following)
112
+ if (currentUserId) {
113
+ updates.followingCounts = {
114
+ ...state.followingCounts,
115
+ [currentUserId]: counts.following
116
+ };
117
+ }
118
+
119
+ return updates;
120
+ });
121
+ }
73
122
  } catch (error: any) {
74
123
  set((state: FollowState) => ({
75
124
  loadingUsers: { ...state.loadingUsers, [userId]: false },
@@ -77,4 +126,56 @@ export const useFollowStore = create<FollowState>((set: any, get: any) => ({
77
126
  }));
78
127
  }
79
128
  },
129
+ setFollowerCount: (userId: string, count: number) => set((state: FollowState) => ({
130
+ followerCounts: { ...state.followerCounts, [userId]: count },
131
+ })),
132
+ setFollowingCount: (userId: string, count: number) => set((state: FollowState) => ({
133
+ followingCounts: { ...state.followingCounts, [userId]: count },
134
+ })),
135
+ updateCountsFromFollowAction: (targetUserId: string, action: 'follow' | 'unfollow', counts: { followers: number; following: number }, currentUserId?: string) => {
136
+ set((state: FollowState) => {
137
+ const updates: any = {};
138
+
139
+ // Update target user's follower count (the user being followed)
140
+ updates.followerCounts = {
141
+ ...state.followerCounts,
142
+ [targetUserId]: counts.followers
143
+ };
144
+
145
+ // Update current user's following count (the user doing the following)
146
+ if (currentUserId) {
147
+ updates.followingCounts = {
148
+ ...state.followingCounts,
149
+ [currentUserId]: counts.following
150
+ };
151
+ }
152
+
153
+ return updates;
154
+ });
155
+ },
156
+ fetchUserCounts: async (userId: string, oxyServices: OxyServices) => {
157
+ set((state: FollowState) => ({
158
+ loadingCounts: { ...state.loadingCounts, [userId]: true },
159
+ }));
160
+ try {
161
+ const user = await oxyServices.getUserById(userId);
162
+ if (user && user._count) {
163
+ set((state: FollowState) => ({
164
+ followerCounts: {
165
+ ...state.followerCounts,
166
+ [userId]: user._count.followers || 0
167
+ },
168
+ followingCounts: {
169
+ ...state.followingCounts,
170
+ [userId]: user._count.following || 0
171
+ },
172
+ loadingCounts: { ...state.loadingCounts, [userId]: false },
173
+ }));
174
+ }
175
+ } catch (error: any) {
176
+ set((state: FollowState) => ({
177
+ loadingCounts: { ...state.loadingCounts, [userId]: false },
178
+ }));
179
+ }
180
+ },
80
181
  }));