@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.
- package/lib/commonjs/index.js +9 -27
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/node/createAuth.js +7 -585
- package/lib/commonjs/node/createAuth.js.map +1 -1
- package/lib/commonjs/node/index.js +1 -38
- package/lib/commonjs/node/index.js.map +1 -1
- package/lib/commonjs/ui/components/FollowButton.js +100 -12
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/Header.js +40 -6
- package/lib/commonjs/ui/components/Header.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +5 -0
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +63 -125
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/index.js +6 -0
- package/lib/commonjs/ui/hooks/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/useFollow.js +59 -2
- package/lib/commonjs/ui/hooks/useFollow.js.map +1 -1
- package/lib/commonjs/ui/navigation/OxyRouter.js +10 -0
- package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +9 -0
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +214 -37
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/UserLinksScreen.js +90 -0
- package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -0
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +9 -6
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +3 -30
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +37 -46
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +9 -12
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +9 -12
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +9 -12
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/commonjs/ui/stores/authStore.js +24 -6
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/commonjs/ui/stores/followStore.js +106 -1
- package/lib/commonjs/ui/stores/followStore.js.map +1 -1
- package/lib/module/index.js +1 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/node/createAuth.js +7 -584
- package/lib/module/node/createAuth.js.map +1 -1
- package/lib/module/node/index.js +1 -7
- package/lib/module/node/index.js.map +1 -1
- package/lib/module/ui/components/FollowButton.js +101 -13
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/Header.js +40 -6
- package/lib/module/ui/components/Header.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +5 -0
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +63 -125
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/index.js +1 -1
- package/lib/module/ui/hooks/index.js.map +1 -1
- package/lib/module/ui/hooks/useFollow.js +57 -1
- package/lib/module/ui/hooks/useFollow.js.map +1 -1
- package/lib/module/ui/navigation/OxyRouter.js +10 -0
- package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +9 -0
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +214 -37
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/UserLinksScreen.js +85 -0
- package/lib/module/ui/screens/UserLinksScreen.js.map +1 -0
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js +9 -6
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js +3 -30
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js +37 -46
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +9 -12
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +9 -12
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js +9 -12
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/module/ui/stores/authStore.js +24 -6
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/module/ui/stores/followStore.js +106 -1
- package/lib/module/ui/stores/followStore.js.map +1 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/node/createAuth.d.ts +0 -112
- package/lib/typescript/node/createAuth.d.ts.map +1 -1
- package/lib/typescript/node/index.d.ts +0 -2
- package/lib/typescript/node/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/FollowButton.d.ts +1 -0
- package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/ui/components/Header.d.ts +2 -0
- package/lib/typescript/ui/components/Header.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/index.d.ts +1 -1
- package/lib/typescript/ui/hooks/index.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useFollow.d.ts +20 -0
- package/lib/typescript/ui/hooks/useFollow.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/UserLinksScreen.d.ts +15 -0
- package/lib/typescript/ui/screens/UserLinksScreen.d.ts.map +1 -0
- package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -1
- package/lib/typescript/ui/stores/authStore.d.ts +3 -1
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/ui/stores/followStore.d.ts +10 -0
- package/lib/typescript/ui/stores/followStore.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +2 -10
- package/src/node/createAuth.ts +7 -623
- package/src/node/index.ts +1 -19
- package/src/ui/components/FollowButton.tsx +95 -11
- package/src/ui/components/Header.tsx +45 -4
- package/src/ui/components/OxyProvider.tsx +6 -0
- package/src/ui/context/OxyContext.tsx +65 -136
- package/src/ui/hooks/index.ts +1 -1
- package/src/ui/hooks/useFollow.ts +63 -0
- package/src/ui/navigation/OxyRouter.tsx +10 -0
- package/src/ui/screens/AccountSettingsScreen.tsx +8 -0
- package/src/ui/screens/ProfileScreen.tsx +191 -28
- package/src/ui/screens/UserLinksScreen.tsx +96 -0
- package/src/ui/screens/karma/KarmaAboutScreen.tsx +9 -2
- package/src/ui/screens/karma/KarmaCenterScreen.tsx +1 -20
- package/src/ui/screens/karma/KarmaFAQScreen.tsx +40 -24
- package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +9 -3
- package/src/ui/screens/karma/KarmaRewardsScreen.tsx +9 -3
- package/src/ui/screens/karma/KarmaRulesScreen.tsx +9 -3
- package/src/ui/stores/authStore.ts +22 -7
- 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
|
-
<
|
|
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}
|
|
102
|
+
<ScrollView contentContainerStyle={styles.contentContainer}>
|
|
95
103
|
{filteredFaqs.length === 0 ? (
|
|
96
|
-
<Text style={[styles.noResults, { color: themeStyles.textColor }]}>
|
|
104
|
+
<Text style={[styles.noResults, { color: themeStyles.textColor }]}>
|
|
105
|
+
No FAQ items found matching "{search}"
|
|
106
|
+
</Text>
|
|
97
107
|
) : (
|
|
98
|
-
filteredFaqs.map((
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
</
|
|
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
|
-
<
|
|
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
|
-
|
|
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
|
-
<
|
|
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
|
-
|
|
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
|
-
<
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}));
|