@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
package/src/node/index.ts
CHANGED
|
@@ -7,28 +7,10 @@ import { OxyServices, OXY_CLOUD_URL } from '../core'; // Adjusted path
|
|
|
7
7
|
import { createAuth } from './createAuth';
|
|
8
8
|
import * as Models from '../models/interfaces'; // Adjusted path
|
|
9
9
|
|
|
10
|
-
// ------------- Enhanced Authentication Imports -------------
|
|
11
|
-
import {
|
|
12
|
-
OxyAuth,
|
|
13
|
-
AuthRequest,
|
|
14
|
-
AuthOptions,
|
|
15
|
-
AuthMiddlewareOptions,
|
|
16
|
-
TokenValidationResult
|
|
17
|
-
} from './createAuth';
|
|
18
|
-
|
|
19
10
|
// ------------- Core Exports -------------
|
|
20
11
|
export { OxyServices, OXY_CLOUD_URL };
|
|
21
12
|
|
|
22
|
-
//
|
|
23
|
-
export {
|
|
24
|
-
OxyAuth,
|
|
25
|
-
AuthRequest,
|
|
26
|
-
AuthOptions,
|
|
27
|
-
AuthMiddlewareOptions,
|
|
28
|
-
TokenValidationResult
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// Zero-config auth and session router (legacy)
|
|
13
|
+
// Zero-config auth and session router
|
|
32
14
|
export { createAuth };
|
|
33
15
|
|
|
34
16
|
// ------------- Model Exports -------------
|
|
@@ -21,6 +21,7 @@ import { useOxy } from '../context/OxyContext';
|
|
|
21
21
|
import { fontFamilies } from '../styles/fonts';
|
|
22
22
|
import { toast } from '../../lib/sonner';
|
|
23
23
|
import { useFollow } from '../hooks/useFollow';
|
|
24
|
+
import { useThemeColors } from '../styles/theme';
|
|
24
25
|
|
|
25
26
|
export interface FollowButtonProps {
|
|
26
27
|
userId: string;
|
|
@@ -32,6 +33,7 @@ export interface FollowButtonProps {
|
|
|
32
33
|
disabled?: boolean;
|
|
33
34
|
showLoadingState?: boolean;
|
|
34
35
|
preventParentActions?: boolean;
|
|
36
|
+
theme?: 'light' | 'dark';
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
const FollowButton: React.FC<FollowButtonProps> = ({
|
|
@@ -44,8 +46,10 @@ const FollowButton: React.FC<FollowButtonProps> = ({
|
|
|
44
46
|
disabled = false,
|
|
45
47
|
showLoadingState = true,
|
|
46
48
|
preventParentActions = true,
|
|
49
|
+
theme = 'light',
|
|
47
50
|
}) => {
|
|
48
51
|
const { oxyServices, isAuthenticated } = useOxy();
|
|
52
|
+
const colors = useThemeColors(theme);
|
|
49
53
|
const {
|
|
50
54
|
isFollowing,
|
|
51
55
|
isLoading,
|
|
@@ -96,19 +100,93 @@ const FollowButton: React.FC<FollowButtonProps> = ({
|
|
|
96
100
|
}
|
|
97
101
|
}, [disabled, isLoading, toggleFollow, onFollowChange, isFollowing, preventParentActions]);
|
|
98
102
|
|
|
99
|
-
//
|
|
103
|
+
// Get button style based on size and follow state
|
|
100
104
|
const getButtonStyle = (): StyleProp<ViewStyle> => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
const baseStyle = {
|
|
106
|
+
flexDirection: 'row' as const,
|
|
107
|
+
alignItems: 'center' as const,
|
|
108
|
+
justifyContent: 'center' as const,
|
|
109
|
+
borderWidth: 1,
|
|
110
|
+
...Platform.select({
|
|
111
|
+
web: {
|
|
112
|
+
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
|
|
113
|
+
},
|
|
114
|
+
default: {
|
|
115
|
+
shadowOffset: { width: 0, height: 2 },
|
|
116
|
+
shadowOpacity: 0.1,
|
|
117
|
+
shadowRadius: 4,
|
|
118
|
+
elevation: 2,
|
|
119
|
+
}
|
|
120
|
+
}),
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Size-specific styles
|
|
124
|
+
let sizeStyle = {};
|
|
125
|
+
if (size === 'small') {
|
|
126
|
+
sizeStyle = {
|
|
127
|
+
paddingVertical: 6,
|
|
128
|
+
paddingHorizontal: 12,
|
|
129
|
+
minWidth: 70,
|
|
130
|
+
borderRadius: 35,
|
|
131
|
+
};
|
|
132
|
+
} else if (size === 'large') {
|
|
133
|
+
sizeStyle = {
|
|
134
|
+
paddingVertical: 12,
|
|
135
|
+
paddingHorizontal: 24,
|
|
136
|
+
minWidth: 120,
|
|
137
|
+
borderRadius: 35,
|
|
138
|
+
};
|
|
139
|
+
} else {
|
|
140
|
+
// medium
|
|
141
|
+
sizeStyle = {
|
|
142
|
+
paddingVertical: 8,
|
|
143
|
+
paddingHorizontal: 16,
|
|
144
|
+
minWidth: 90,
|
|
145
|
+
borderRadius: 35,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// State-specific colors
|
|
150
|
+
let stateStyle = {};
|
|
151
|
+
if (isFollowing) {
|
|
152
|
+
stateStyle = {
|
|
153
|
+
backgroundColor: colors.primary,
|
|
154
|
+
borderColor: colors.primary,
|
|
155
|
+
shadowColor: colors.primary,
|
|
156
|
+
};
|
|
157
|
+
} else {
|
|
158
|
+
stateStyle = {
|
|
159
|
+
backgroundColor: 'transparent',
|
|
160
|
+
borderColor: colors.border,
|
|
161
|
+
shadowColor: colors.border,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return [baseStyle, sizeStyle, stateStyle, style];
|
|
105
166
|
};
|
|
106
167
|
|
|
168
|
+
// Get text style based on size and follow state
|
|
107
169
|
const getTextStyle = (): StyleProp<TextStyle> => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
170
|
+
const baseTextStyle = {
|
|
171
|
+
fontFamily: fontFamilies.phuduSemiBold,
|
|
172
|
+
fontWeight: '600' as const,
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// Size-specific text styles
|
|
176
|
+
let sizeTextStyle = {};
|
|
177
|
+
if (size === 'small') {
|
|
178
|
+
sizeTextStyle = { fontSize: 13 };
|
|
179
|
+
} else if (size === 'large') {
|
|
180
|
+
sizeTextStyle = { fontSize: 16 };
|
|
181
|
+
} else {
|
|
182
|
+
// medium
|
|
183
|
+
sizeTextStyle = { fontSize: 15 };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// State-specific text color
|
|
187
|
+
const textColor = isFollowing ? '#FFFFFF' : colors.text;
|
|
188
|
+
|
|
189
|
+
return [baseTextStyle, sizeTextStyle, { color: textColor }, textStyle];
|
|
112
190
|
};
|
|
113
191
|
|
|
114
192
|
return (
|
|
@@ -119,15 +197,21 @@ const FollowButton: React.FC<FollowButtonProps> = ({
|
|
|
119
197
|
activeOpacity={0.8}
|
|
120
198
|
>
|
|
121
199
|
{showLoadingState && isLoading ? (
|
|
122
|
-
<ActivityIndicator
|
|
200
|
+
<ActivityIndicator
|
|
201
|
+
size={size === 'small' ? 'small' : 'small'}
|
|
202
|
+
color={isFollowing ? '#FFFFFF' : colors.primary}
|
|
203
|
+
/>
|
|
123
204
|
) : (
|
|
124
|
-
<Text style={getTextStyle()}>
|
|
205
|
+
<Text style={getTextStyle()}>
|
|
206
|
+
{isFollowing ? 'Following' : 'Follow'}
|
|
207
|
+
</Text>
|
|
125
208
|
)}
|
|
126
209
|
</TouchableOpacity>
|
|
127
210
|
);
|
|
128
211
|
};
|
|
129
212
|
|
|
130
213
|
const styles = StyleSheet.create({
|
|
214
|
+
// Legacy styles kept for backward compatibility but not used in new implementation
|
|
131
215
|
buttonSmall: {
|
|
132
216
|
paddingVertical: 4,
|
|
133
217
|
paddingHorizontal: 12,
|
|
@@ -28,6 +28,8 @@ export interface HeaderProps {
|
|
|
28
28
|
showCloseButton?: boolean;
|
|
29
29
|
variant?: 'default' | 'large' | 'minimal' | 'gradient';
|
|
30
30
|
elevation?: 'none' | 'subtle' | 'prominent';
|
|
31
|
+
subtitleVariant?: 'default' | 'small' | 'large' | 'muted';
|
|
32
|
+
titleAlignment?: 'left' | 'center' | 'right';
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
const Header: React.FC<HeaderProps> = ({
|
|
@@ -41,6 +43,8 @@ const Header: React.FC<HeaderProps> = ({
|
|
|
41
43
|
showCloseButton = false,
|
|
42
44
|
variant = 'default',
|
|
43
45
|
elevation = 'subtle',
|
|
46
|
+
subtitleVariant = 'default',
|
|
47
|
+
titleAlignment = 'left',
|
|
44
48
|
}) => {
|
|
45
49
|
const isDarkTheme = theme === 'dark';
|
|
46
50
|
|
|
@@ -139,11 +143,26 @@ const Header: React.FC<HeaderProps> = ({
|
|
|
139
143
|
|
|
140
144
|
const subtitleStyle = variant === 'large' ? styles.subtitleLarge :
|
|
141
145
|
variant === 'minimal' ? styles.subtitleMinimal :
|
|
142
|
-
styles.
|
|
146
|
+
subtitleVariant === 'small' ? styles.subtitleSmall :
|
|
147
|
+
subtitleVariant === 'large' ? styles.subtitleLarge :
|
|
148
|
+
subtitleVariant === 'muted' ? styles.subtitleMuted :
|
|
149
|
+
styles.subtitleDefault;
|
|
150
|
+
|
|
151
|
+
const getTitleAlignment = () => {
|
|
152
|
+
switch (titleAlignment) {
|
|
153
|
+
case 'center':
|
|
154
|
+
return styles.titleContainerCenter;
|
|
155
|
+
case 'right':
|
|
156
|
+
return styles.titleContainerRight;
|
|
157
|
+
default:
|
|
158
|
+
return styles.titleContainerLeft;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
143
161
|
|
|
144
162
|
return (
|
|
145
163
|
<View style={[
|
|
146
164
|
styles.titleContainer,
|
|
165
|
+
getTitleAlignment(),
|
|
147
166
|
variant === 'minimal' && styles.titleContainerMinimal
|
|
148
167
|
]}>
|
|
149
168
|
<Text style={[titleStyle, { color: colors.text.primary }]}>
|
|
@@ -281,6 +300,15 @@ const styles = StyleSheet.create({
|
|
|
281
300
|
alignItems: 'flex-start',
|
|
282
301
|
justifyContent: 'center',
|
|
283
302
|
},
|
|
303
|
+
titleContainerLeft: {
|
|
304
|
+
alignItems: 'flex-start',
|
|
305
|
+
},
|
|
306
|
+
titleContainerCenter: {
|
|
307
|
+
alignItems: 'center',
|
|
308
|
+
},
|
|
309
|
+
titleContainerRight: {
|
|
310
|
+
alignItems: 'flex-end',
|
|
311
|
+
},
|
|
284
312
|
titleContainerMinimal: {
|
|
285
313
|
alignItems: 'center',
|
|
286
314
|
marginHorizontal: 16,
|
|
@@ -309,22 +337,35 @@ const styles = StyleSheet.create({
|
|
|
309
337
|
},
|
|
310
338
|
subtitleDefault: {
|
|
311
339
|
fontSize: 14,
|
|
312
|
-
|
|
340
|
+
fontWeight: '400',
|
|
313
341
|
lineHeight: 17,
|
|
314
342
|
marginTop: 1,
|
|
315
343
|
},
|
|
316
344
|
subtitleLarge: {
|
|
317
345
|
fontSize: 16,
|
|
318
|
-
|
|
346
|
+
fontWeight: '400',
|
|
319
347
|
lineHeight: 19,
|
|
320
348
|
marginTop: 3,
|
|
321
349
|
},
|
|
322
350
|
subtitleMinimal: {
|
|
323
351
|
fontSize: 13,
|
|
324
|
-
|
|
352
|
+
fontWeight: '400',
|
|
325
353
|
lineHeight: 15,
|
|
326
354
|
marginTop: 1,
|
|
327
355
|
},
|
|
356
|
+
subtitleSmall: {
|
|
357
|
+
fontSize: 12,
|
|
358
|
+
fontWeight: '400',
|
|
359
|
+
lineHeight: 14,
|
|
360
|
+
marginTop: 0,
|
|
361
|
+
},
|
|
362
|
+
subtitleMuted: {
|
|
363
|
+
fontSize: 14,
|
|
364
|
+
fontWeight: '400',
|
|
365
|
+
lineHeight: 17,
|
|
366
|
+
marginTop: 1,
|
|
367
|
+
opacity: 0.7,
|
|
368
|
+
},
|
|
328
369
|
rightActionButton: {
|
|
329
370
|
alignItems: 'center',
|
|
330
371
|
justifyContent: 'center',
|
|
@@ -126,13 +126,17 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
|
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
});
|
|
129
|
+
|
|
129
130
|
// Add a method to navigate between screens
|
|
130
131
|
// @ts-ignore
|
|
131
132
|
bottomSheetRef.current._navigateToScreen = (screenName: string, props?: Record<string, any>) => {
|
|
133
|
+
console.log('_navigateToScreen called with:', screenName, props);
|
|
132
134
|
if (navigationRef.current) {
|
|
135
|
+
console.log('Using navigationRef.current');
|
|
133
136
|
navigationRef.current(screenName, props);
|
|
134
137
|
return;
|
|
135
138
|
}
|
|
139
|
+
console.log('navigationRef.current not available, using event system');
|
|
136
140
|
if (typeof document !== 'undefined') {
|
|
137
141
|
const event = new CustomEvent('oxy:navigate', { detail: { screen: screenName, props } });
|
|
138
142
|
document.dispatchEvent(event);
|
|
@@ -140,6 +144,8 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
|
|
|
140
144
|
(globalThis as any).oxyNavigateEvent = { screen: screenName, props };
|
|
141
145
|
}
|
|
142
146
|
};
|
|
147
|
+
|
|
148
|
+
console.log('Bottom sheet ref methods exposed:', Object.keys(bottomSheetRef.current));
|
|
143
149
|
}
|
|
144
150
|
}, [bottomSheetRef, modalRef]);
|
|
145
151
|
// Keyboard handling (unchanged)
|
|
@@ -112,8 +112,7 @@ const getStorage = async (): Promise<StorageInterface> => {
|
|
|
112
112
|
|
|
113
113
|
// Storage keys for secure sessions
|
|
114
114
|
const getSecureStorageKeys = (prefix = 'oxy_secure') => ({
|
|
115
|
-
|
|
116
|
-
activeSessionId: `${prefix}_active_session_id`, // ID of currently active session
|
|
115
|
+
activeSessionId: `${prefix}_active_session_id`, // Only store the active session ID
|
|
117
116
|
});
|
|
118
117
|
|
|
119
118
|
export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
@@ -175,94 +174,60 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
175
174
|
initStorage();
|
|
176
175
|
}, []);
|
|
177
176
|
|
|
178
|
-
// Effect to initialize authentication state
|
|
177
|
+
// Effect to initialize authentication state - only store session ID
|
|
179
178
|
useEffect(() => {
|
|
180
179
|
const initAuth = async () => {
|
|
181
180
|
if (!storage) return;
|
|
182
181
|
|
|
183
182
|
useAuthStore.setState({ isLoading: true });
|
|
184
183
|
try {
|
|
185
|
-
//
|
|
186
|
-
const sessionsData = await storage.getItem(keys.sessions);
|
|
184
|
+
// Only load the active session ID from storage
|
|
187
185
|
const storedActiveSessionId = await storage.getItem(keys.activeSessionId);
|
|
188
186
|
|
|
189
|
-
console.log('SecureAuth - sessionsData:', sessionsData);
|
|
190
187
|
console.log('SecureAuth - activeSessionId:', storedActiveSessionId);
|
|
191
188
|
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
189
|
+
if (storedActiveSessionId) {
|
|
190
|
+
// Validate the stored session with the backend
|
|
191
|
+
try {
|
|
192
|
+
const validation = await oxyServices.validateSession(storedActiveSessionId);
|
|
193
|
+
|
|
194
|
+
if (validation.valid) {
|
|
195
|
+
console.log('SecureAuth - session validated successfully');
|
|
196
|
+
setActiveSessionId(storedActiveSessionId);
|
|
197
|
+
|
|
198
|
+
// Get access token for API calls
|
|
199
|
+
await oxyServices.getTokenBySession(storedActiveSessionId);
|
|
200
|
+
|
|
201
|
+
// Load full user data from backend
|
|
202
|
+
const fullUser = await oxyServices.getUserBySession(storedActiveSessionId);
|
|
203
|
+
loginSuccess(fullUser);
|
|
204
|
+
setMinimalUser({
|
|
205
|
+
id: fullUser.id,
|
|
206
|
+
username: fullUser.username,
|
|
207
|
+
avatar: fullUser.avatar
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Load sessions from backend
|
|
211
|
+
const serverSessions = await oxyServices.getSessionsBySessionId(storedActiveSessionId);
|
|
212
|
+
const clientSessions: SecureClientSession[] = serverSessions.map(serverSession => ({
|
|
213
|
+
sessionId: serverSession.sessionId,
|
|
214
|
+
deviceId: serverSession.deviceId,
|
|
215
|
+
expiresAt: serverSession.expiresAt || new Date().toISOString(),
|
|
216
|
+
lastActive: serverSession.lastActive || new Date().toISOString(),
|
|
217
|
+
userId: serverSession.userId || fullUser.id
|
|
218
|
+
}));
|
|
219
|
+
setSessions(clientSessions);
|
|
220
|
+
|
|
221
|
+
if (onAuthStateChange) {
|
|
222
|
+
onAuthStateChange(fullUser);
|
|
214
223
|
}
|
|
215
224
|
} else {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Update storage if we made changes
|
|
222
|
-
if (shouldUpdateStorage) {
|
|
223
|
-
await saveSessionsToStorage(migratedSessions);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
setSessions(migratedSessions);
|
|
227
|
-
|
|
228
|
-
if (storedActiveSessionId && migratedSessions.length > 0) {
|
|
229
|
-
const activeSession = migratedSessions.find(s => s.sessionId === storedActiveSessionId);
|
|
230
|
-
|
|
231
|
-
if (activeSession) {
|
|
232
|
-
console.log('SecureAuth - activeSession found:', activeSession);
|
|
233
|
-
|
|
234
|
-
// Validate session
|
|
235
|
-
try {
|
|
236
|
-
const validation = await oxyServices.validateSession(activeSession.sessionId);
|
|
237
|
-
|
|
238
|
-
if (validation.valid) {
|
|
239
|
-
console.log('SecureAuth - session validated successfully');
|
|
240
|
-
setActiveSessionId(activeSession.sessionId);
|
|
241
|
-
|
|
242
|
-
// Get access token for API calls
|
|
243
|
-
await oxyServices.getTokenBySession(activeSession.sessionId);
|
|
244
|
-
|
|
245
|
-
// Load full user data
|
|
246
|
-
const fullUser = await oxyServices.getUserBySession(activeSession.sessionId);
|
|
247
|
-
loginSuccess(fullUser);
|
|
248
|
-
setMinimalUser({
|
|
249
|
-
id: fullUser.id,
|
|
250
|
-
username: fullUser.username,
|
|
251
|
-
avatar: fullUser.avatar
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
if (onAuthStateChange) {
|
|
255
|
-
onAuthStateChange(fullUser);
|
|
256
|
-
}
|
|
257
|
-
} else {
|
|
258
|
-
console.log('SecureAuth - session invalid, removing');
|
|
259
|
-
await removeInvalidSession(activeSession.sessionId);
|
|
260
|
-
}
|
|
261
|
-
} catch (error) {
|
|
262
|
-
console.error('SecureAuth - session validation error:', error);
|
|
263
|
-
await removeInvalidSession(activeSession.sessionId);
|
|
264
|
-
}
|
|
225
|
+
console.log('SecureAuth - session invalid, clearing storage');
|
|
226
|
+
await clearAllStorage();
|
|
265
227
|
}
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.error('SecureAuth - session validation error:', error);
|
|
230
|
+
await clearAllStorage();
|
|
266
231
|
}
|
|
267
232
|
}
|
|
268
233
|
} catch (err) {
|
|
@@ -276,15 +241,15 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
276
241
|
if (storage) {
|
|
277
242
|
initAuth();
|
|
278
243
|
}
|
|
279
|
-
}, [storage, oxyServices, keys, onAuthStateChange]);
|
|
244
|
+
}, [storage, oxyServices, keys, onAuthStateChange, loginSuccess, setMinimalUser]);
|
|
280
245
|
|
|
281
246
|
|
|
282
247
|
|
|
283
|
-
// Remove invalid session
|
|
248
|
+
// Remove invalid session - refresh sessions from backend
|
|
284
249
|
const removeInvalidSession = useCallback(async (sessionId: string): Promise<void> => {
|
|
250
|
+
// Remove from local state
|
|
285
251
|
const filteredSessions = sessions.filter(s => s.sessionId !== sessionId);
|
|
286
252
|
setSessions(filteredSessions);
|
|
287
|
-
await saveSessionsToStorage(filteredSessions);
|
|
288
253
|
|
|
289
254
|
// If there are other sessions, switch to the first one
|
|
290
255
|
if (filteredSessions.length > 0) {
|
|
@@ -302,13 +267,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
302
267
|
}
|
|
303
268
|
}, [sessions, storage, keys, onAuthStateChange, logoutStore]);
|
|
304
269
|
|
|
305
|
-
// Save
|
|
306
|
-
const saveSessionsToStorage = useCallback(async (sessionsList: SecureClientSession[]): Promise<void> => {
|
|
307
|
-
if (!storage) return;
|
|
308
|
-
await storage.setItem(keys.sessions, JSON.stringify(sessionsList));
|
|
309
|
-
}, [storage, keys.sessions]);
|
|
310
|
-
|
|
311
|
-
// Save active session ID to storage
|
|
270
|
+
// Save active session ID to storage (only session ID, no user data)
|
|
312
271
|
const saveActiveSessionId = useCallback(async (sessionId: string): Promise<void> => {
|
|
313
272
|
if (!storage) return;
|
|
314
273
|
await storage.setItem(keys.activeSessionId, sessionId);
|
|
@@ -318,7 +277,6 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
318
277
|
const clearAllStorage = useCallback(async (): Promise<void> => {
|
|
319
278
|
if (!storage) return;
|
|
320
279
|
try {
|
|
321
|
-
await storage.removeItem(keys.sessions);
|
|
322
280
|
await storage.removeItem(keys.activeSessionId);
|
|
323
281
|
} catch (err) {
|
|
324
282
|
console.error('Clear secure storage error:', err);
|
|
@@ -357,7 +315,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
357
315
|
}
|
|
358
316
|
}, [oxyServices, onAuthStateChange, loginSuccess, saveActiveSessionId]);
|
|
359
317
|
|
|
360
|
-
// Secure login method
|
|
318
|
+
// Secure login method - only store session ID, retrieve data from backend
|
|
361
319
|
const login = useCallback(async (username: string, password: string, deviceName?: string): Promise<User> => {
|
|
362
320
|
if (!storage) throw new Error('Storage not initialized');
|
|
363
321
|
useAuthStore.setState({ isLoading: true, error: null });
|
|
@@ -379,56 +337,29 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
379
337
|
deviceFingerprint
|
|
380
338
|
);
|
|
381
339
|
|
|
382
|
-
//
|
|
383
|
-
const clientSession: SecureClientSession = {
|
|
384
|
-
sessionId: response.sessionId,
|
|
385
|
-
deviceId: response.deviceId,
|
|
386
|
-
expiresAt: response.expiresAt,
|
|
387
|
-
lastActive: new Date().toISOString(),
|
|
388
|
-
userId: response.user.id
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
// Check if this user already has a session (prevent duplicate accounts)
|
|
392
|
-
const existingUserSessionIndex = sessions.findIndex(s =>
|
|
393
|
-
s.userId === response.user.id
|
|
394
|
-
);
|
|
395
|
-
|
|
396
|
-
let updatedSessions: SecureClientSession[];
|
|
397
|
-
|
|
398
|
-
if (existingUserSessionIndex !== -1) {
|
|
399
|
-
// User already has a session - replace it with the new one (reused session scenario)
|
|
400
|
-
const existingSession = sessions[existingUserSessionIndex];
|
|
401
|
-
updatedSessions = [...sessions];
|
|
402
|
-
updatedSessions[existingUserSessionIndex] = clientSession;
|
|
403
|
-
|
|
404
|
-
console.log(`Reusing/updating existing session for user ${response.user.id}. Previous session: ${existingSession.sessionId}, New session: ${response.sessionId}`);
|
|
405
|
-
|
|
406
|
-
// If the replaced session was the active one, update active session
|
|
407
|
-
if (activeSessionId === existingSession.sessionId) {
|
|
408
|
-
setActiveSessionId(response.sessionId);
|
|
409
|
-
await saveActiveSessionId(response.sessionId);
|
|
410
|
-
}
|
|
411
|
-
} else {
|
|
412
|
-
// Add new session for new user
|
|
413
|
-
updatedSessions = [...sessions, clientSession];
|
|
414
|
-
console.log(`Added new session for user ${response.user.id} on device ${response.deviceId}`);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
setSessions(updatedSessions);
|
|
418
|
-
await saveSessionsToStorage(updatedSessions);
|
|
419
|
-
|
|
420
|
-
// Set as active session
|
|
340
|
+
// Set as active session (only store session ID)
|
|
421
341
|
setActiveSessionId(response.sessionId);
|
|
422
342
|
await saveActiveSessionId(response.sessionId);
|
|
423
343
|
|
|
424
344
|
// Get access token for API calls
|
|
425
345
|
await oxyServices.getTokenBySession(response.sessionId);
|
|
426
346
|
|
|
427
|
-
// Load full user data
|
|
347
|
+
// Load full user data from backend
|
|
428
348
|
const fullUser = await oxyServices.getUserBySession(response.sessionId);
|
|
429
349
|
loginSuccess(fullUser);
|
|
430
350
|
setMinimalUser(response.user);
|
|
431
351
|
|
|
352
|
+
// Load sessions from backend
|
|
353
|
+
const serverSessions = await oxyServices.getSessionsBySessionId(response.sessionId);
|
|
354
|
+
const clientSessions: SecureClientSession[] = serverSessions.map(serverSession => ({
|
|
355
|
+
sessionId: serverSession.sessionId,
|
|
356
|
+
deviceId: serverSession.deviceId,
|
|
357
|
+
expiresAt: serverSession.expiresAt || new Date().toISOString(),
|
|
358
|
+
lastActive: serverSession.lastActive || new Date().toISOString(),
|
|
359
|
+
userId: serverSession.userId || fullUser.id
|
|
360
|
+
}));
|
|
361
|
+
setSessions(clientSessions);
|
|
362
|
+
|
|
432
363
|
if (onAuthStateChange) {
|
|
433
364
|
onAuthStateChange(fullUser);
|
|
434
365
|
}
|
|
@@ -440,7 +371,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
440
371
|
} finally {
|
|
441
372
|
useAuthStore.setState({ isLoading: false });
|
|
442
373
|
}
|
|
443
|
-
}, [storage, oxyServices,
|
|
374
|
+
}, [storage, oxyServices, saveActiveSessionId, loginSuccess, setMinimalUser, onAuthStateChange, loginFailure]);
|
|
444
375
|
|
|
445
376
|
// Logout method
|
|
446
377
|
const logout = useCallback(async (targetSessionId?: string): Promise<void> => {
|
|
@@ -450,10 +381,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
450
381
|
const sessionToLogout = targetSessionId || activeSessionId;
|
|
451
382
|
await oxyServices.logoutSecureSession(activeSessionId, sessionToLogout);
|
|
452
383
|
|
|
453
|
-
// Remove session from local
|
|
384
|
+
// Remove session from local state
|
|
454
385
|
const filteredSessions = sessions.filter(s => s.sessionId !== sessionToLogout);
|
|
455
386
|
setSessions(filteredSessions);
|
|
456
|
-
await saveSessionsToStorage(filteredSessions);
|
|
457
387
|
|
|
458
388
|
// If logging out active session
|
|
459
389
|
if (sessionToLogout === activeSessionId) {
|
|
@@ -476,7 +406,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
476
406
|
console.error('Logout error:', error);
|
|
477
407
|
useAuthStore.setState({ error: 'Logout failed' });
|
|
478
408
|
}
|
|
479
|
-
}, [activeSessionId, oxyServices, sessions,
|
|
409
|
+
}, [activeSessionId, oxyServices, sessions, switchToSession, logoutStore, setMinimalUser, storage, keys.activeSessionId, onAuthStateChange]);
|
|
480
410
|
|
|
481
411
|
// Logout all sessions
|
|
482
412
|
const logoutAll = useCallback(async (): Promise<void> => {
|
|
@@ -598,8 +528,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
598
528
|
|
|
599
529
|
console.log('refreshSessions: Updated sessions:', updatedSessions);
|
|
600
530
|
setSessions(updatedSessions);
|
|
601
|
-
|
|
602
|
-
console.log('refreshSessions: Sessions saved to storage');
|
|
531
|
+
console.log('refreshSessions: Sessions updated in state');
|
|
603
532
|
} catch (error) {
|
|
604
533
|
console.error('Refresh sessions error:', error);
|
|
605
534
|
|
|
@@ -634,7 +563,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
634
563
|
onAuthStateChange(null);
|
|
635
564
|
}
|
|
636
565
|
}
|
|
637
|
-
}, [activeSessionId, oxyServices, user?.id, sessions,
|
|
566
|
+
}, [activeSessionId, oxyServices, user?.id, sessions, switchToSession, logoutStore, setMinimalUser, clearAllStorage, onAuthStateChange]);
|
|
638
567
|
|
|
639
568
|
// Device management methods
|
|
640
569
|
const getDeviceSessions = useCallback(async (): Promise<any[]> => {
|
package/src/ui/hooks/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { useFollow } from './useFollow';
|
|
1
|
+
export { useFollow, useFollowerCounts } from './useFollow';
|