@oxyhq/services 5.4.8 → 5.5.1

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 (154) hide show
  1. package/lib/commonjs/core/index.js +0 -59
  2. package/lib/commonjs/core/index.js.map +1 -1
  3. package/lib/commonjs/index.js +174 -17
  4. package/lib/commonjs/index.js.map +1 -1
  5. package/lib/commonjs/ui/components/FollowButton.js +8 -23
  6. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  7. package/lib/commonjs/ui/components/OxyProvider.js +49 -38
  8. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  9. package/lib/commonjs/ui/components/OxySignInButton.js +2 -8
  10. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  11. package/lib/commonjs/ui/hooks/index.js +15 -2
  12. package/lib/commonjs/ui/hooks/index.js.map +1 -1
  13. package/lib/commonjs/ui/hooks/useAuthFetch.js +182 -0
  14. package/lib/commonjs/ui/hooks/useAuthFetch.js.map +1 -0
  15. package/lib/commonjs/ui/hooks/useFollow.js +10 -29
  16. package/lib/commonjs/ui/hooks/useFollow.js.map +1 -1
  17. package/lib/commonjs/ui/hooks/useOxyFollow.js +190 -0
  18. package/lib/commonjs/ui/hooks/useOxyFollow.js.map +1 -0
  19. package/lib/commonjs/ui/index.js +183 -0
  20. package/lib/commonjs/ui/index.js.map +1 -1
  21. package/lib/commonjs/ui/screens/AccountCenterScreen.js +18 -14
  22. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  23. package/lib/commonjs/ui/screens/AppInfoScreen.js +37 -19
  24. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  25. package/lib/commonjs/ui/screens/FileManagementScreen.js +27 -9
  26. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  27. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +2 -8
  28. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  29. package/lib/commonjs/ui/store/index.js +51 -255
  30. package/lib/commonjs/ui/store/index.js.map +1 -1
  31. package/lib/commonjs/ui/store/setupOxyStore.js +63 -0
  32. package/lib/commonjs/ui/store/setupOxyStore.js.map +1 -0
  33. package/lib/commonjs/ui/store/slices/authSlice.js +56 -0
  34. package/lib/commonjs/ui/store/slices/authSlice.js.map +1 -0
  35. package/lib/commonjs/ui/store/slices/followSlice.js +238 -0
  36. package/lib/commonjs/ui/store/slices/followSlice.js.map +1 -0
  37. package/lib/commonjs/ui/store/slices/index.js +129 -0
  38. package/lib/commonjs/ui/store/slices/index.js.map +1 -0
  39. package/lib/commonjs/ui/store/slices/types.js +19 -0
  40. package/lib/commonjs/ui/store/slices/types.js.map +1 -0
  41. package/lib/commonjs/ui/styles/index.js +11 -0
  42. package/lib/commonjs/ui/styles/index.js.map +1 -1
  43. package/lib/commonjs/ui/styles/shadows.js +123 -0
  44. package/lib/commonjs/ui/styles/shadows.js.map +1 -0
  45. package/lib/module/core/index.js +0 -59
  46. package/lib/module/core/index.js.map +1 -1
  47. package/lib/module/index.js +14 -10
  48. package/lib/module/index.js.map +1 -1
  49. package/lib/module/ui/components/FollowButton.js +8 -23
  50. package/lib/module/ui/components/FollowButton.js.map +1 -1
  51. package/lib/module/ui/components/OxyProvider.js +49 -38
  52. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  53. package/lib/module/ui/components/OxySignInButton.js +2 -8
  54. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  55. package/lib/module/ui/hooks/index.js +2 -1
  56. package/lib/module/ui/hooks/index.js.map +1 -1
  57. package/lib/module/ui/hooks/useAuthFetch.js +177 -0
  58. package/lib/module/ui/hooks/useAuthFetch.js.map +1 -0
  59. package/lib/module/ui/hooks/useFollow.js +10 -29
  60. package/lib/module/ui/hooks/useFollow.js.map +1 -1
  61. package/lib/module/ui/hooks/useOxyFollow.js +186 -0
  62. package/lib/module/ui/hooks/useOxyFollow.js.map +1 -0
  63. package/lib/module/ui/index.js +12 -2
  64. package/lib/module/ui/index.js.map +1 -1
  65. package/lib/module/ui/screens/AccountCenterScreen.js +5 -1
  66. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  67. package/lib/module/ui/screens/AppInfoScreen.js +37 -19
  68. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  69. package/lib/module/ui/screens/FileManagementScreen.js +27 -9
  70. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  71. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +2 -8
  72. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  73. package/lib/module/ui/store/index.js +23 -249
  74. package/lib/module/ui/store/index.js.map +1 -1
  75. package/lib/module/ui/store/setupOxyStore.js +59 -0
  76. package/lib/module/ui/store/setupOxyStore.js.map +1 -0
  77. package/lib/module/ui/store/slices/authSlice.js +48 -0
  78. package/lib/module/ui/store/slices/authSlice.js.map +1 -0
  79. package/lib/module/ui/store/slices/followSlice.js +232 -0
  80. package/lib/module/ui/store/slices/followSlice.js.map +1 -0
  81. package/lib/module/ui/store/slices/index.js +11 -0
  82. package/lib/module/ui/store/slices/index.js.map +1 -0
  83. package/lib/module/ui/store/slices/types.js +15 -0
  84. package/lib/module/ui/store/slices/types.js.map +1 -0
  85. package/lib/module/ui/styles/index.js +1 -0
  86. package/lib/module/ui/styles/index.js.map +1 -1
  87. package/lib/module/ui/styles/shadows.js +119 -0
  88. package/lib/module/ui/styles/shadows.js.map +1 -0
  89. package/lib/typescript/core/index.d.ts +0 -28
  90. package/lib/typescript/core/index.d.ts.map +1 -1
  91. package/lib/typescript/index.d.ts +3 -5
  92. package/lib/typescript/index.d.ts.map +1 -1
  93. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  94. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  95. package/lib/typescript/ui/components/OxySignInButton.d.ts.map +1 -1
  96. package/lib/typescript/ui/hooks/index.d.ts +2 -1
  97. package/lib/typescript/ui/hooks/index.d.ts.map +1 -1
  98. package/lib/typescript/ui/hooks/useAuthFetch.d.ts +33 -0
  99. package/lib/typescript/ui/hooks/useAuthFetch.d.ts.map +1 -0
  100. package/lib/typescript/ui/hooks/useFollow.d.ts.map +1 -1
  101. package/lib/typescript/ui/hooks/useOxyFollow.d.ts +81 -0
  102. package/lib/typescript/ui/hooks/useOxyFollow.d.ts.map +1 -0
  103. package/lib/typescript/ui/index.d.ts +3 -1
  104. package/lib/typescript/ui/index.d.ts.map +1 -1
  105. package/lib/typescript/ui/navigation/types.d.ts +22 -4
  106. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  107. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  108. package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
  109. package/lib/typescript/ui/screens/FileManagementScreen.d.ts.map +1 -1
  110. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
  111. package/lib/typescript/ui/store/index.d.ts +19 -58
  112. package/lib/typescript/ui/store/index.d.ts.map +1 -1
  113. package/lib/typescript/ui/store/setupOxyStore.d.ts +29 -0
  114. package/lib/typescript/ui/store/setupOxyStore.d.ts.map +1 -0
  115. package/lib/typescript/ui/store/slices/authSlice.d.ts +32 -0
  116. package/lib/typescript/ui/store/slices/authSlice.d.ts.map +1 -0
  117. package/lib/typescript/ui/store/slices/followSlice.d.ts +120 -0
  118. package/lib/typescript/ui/store/slices/followSlice.d.ts.map +1 -0
  119. package/lib/typescript/ui/store/slices/index.d.ts +9 -0
  120. package/lib/typescript/ui/store/slices/index.d.ts.map +1 -0
  121. package/lib/typescript/ui/store/slices/types.d.ts +16 -0
  122. package/lib/typescript/ui/store/slices/types.d.ts.map +1 -0
  123. package/lib/typescript/ui/styles/index.d.ts +1 -0
  124. package/lib/typescript/ui/styles/index.d.ts.map +1 -1
  125. package/lib/typescript/ui/styles/shadows.d.ts +233 -0
  126. package/lib/typescript/ui/styles/shadows.d.ts.map +1 -0
  127. package/package.json +14 -15
  128. package/src/__tests__/ui/hooks/useOxyFollow.test.tsx +92 -0
  129. package/src/__tests__/ui/store/setupOxyStore.test.ts +50 -0
  130. package/src/__tests__/validate-structure.js +91 -0
  131. package/src/__tests__/validation.js +42 -0
  132. package/src/core/index.ts +0 -66
  133. package/src/index.ts +36 -4
  134. package/src/ui/components/FollowButton.tsx +11 -25
  135. package/src/ui/components/OxyProvider.tsx +48 -33
  136. package/src/ui/components/OxySignInButton.tsx +2 -6
  137. package/src/ui/hooks/index.ts +2 -1
  138. package/src/ui/hooks/useAuthFetch.ts +200 -0
  139. package/src/ui/hooks/useFollow.ts +10 -30
  140. package/src/ui/hooks/useOxyFollow.ts +188 -0
  141. package/src/ui/index.ts +34 -2
  142. package/src/ui/navigation/types.ts +24 -4
  143. package/src/ui/screens/AccountCenterScreen.tsx +5 -7
  144. package/src/ui/screens/AppInfoScreen.tsx +40 -23
  145. package/src/ui/screens/FileManagementScreen.tsx +268 -248
  146. package/src/ui/screens/karma/KarmaRewardsScreen.tsx +2 -5
  147. package/src/ui/store/index.ts +31 -245
  148. package/src/ui/store/setupOxyStore.ts +58 -0
  149. package/src/ui/store/slices/authSlice.ts +43 -0
  150. package/src/ui/store/slices/followSlice.ts +207 -0
  151. package/src/ui/store/slices/index.ts +31 -0
  152. package/src/ui/store/slices/types.ts +33 -0
  153. package/src/ui/styles/index.ts +1 -0
  154. package/src/ui/styles/shadows.ts +112 -0
@@ -0,0 +1,92 @@
1
+ import { renderHook } from '@testing-library/react-native';
2
+ import { Provider } from 'react-redux';
3
+ import { configureStore } from '@reduxjs/toolkit';
4
+ import { useOxyFollow } from '../../../ui/hooks/useOxyFollow';
5
+ import { setupOxyStore } from '../../../ui/store/setupOxyStore';
6
+ import { OxyContextProvider } from '../../../ui/context/OxyContext';
7
+ import React from 'react';
8
+
9
+ // Mock OxyServices
10
+ const mockOxyServices = {
11
+ getFollowStatus: jest.fn(),
12
+ followUser: jest.fn(),
13
+ unfollowUser: jest.fn(),
14
+ };
15
+
16
+ const createTestStore = () => {
17
+ return configureStore({
18
+ reducer: {
19
+ ...setupOxyStore(),
20
+ },
21
+ });
22
+ };
23
+
24
+ const createWrapper = (store: ReturnType<typeof createTestStore>) => {
25
+ return ({ children }: { children: React.ReactNode }) => (
26
+ <Provider store={store}>
27
+ <OxyContextProvider oxyServices={mockOxyServices}>
28
+ {children}
29
+ </OxyContextProvider>
30
+ </Provider>
31
+ );
32
+ };
33
+
34
+ describe('useOxyFollow', () => {
35
+ beforeEach(() => {
36
+ jest.clearAllMocks();
37
+ });
38
+
39
+ test('should work with external store containing Oxy reducers', () => {
40
+ const store = createTestStore();
41
+ const wrapper = createWrapper(store);
42
+
43
+ const { result } = renderHook(() => useOxyFollow('user1'), { wrapper });
44
+
45
+ expect(result.current).toHaveProperty('isFollowing');
46
+ expect(result.current).toHaveProperty('isLoading');
47
+ expect(result.current).toHaveProperty('error');
48
+ expect(result.current).toHaveProperty('toggleFollow');
49
+ expect(result.current).toHaveProperty('setFollowStatus');
50
+ expect(result.current).toHaveProperty('fetchStatus');
51
+ expect(result.current).toHaveProperty('clearError');
52
+ });
53
+
54
+ test('should support multiple users mode', () => {
55
+ const store = createTestStore();
56
+ const wrapper = createWrapper(store);
57
+
58
+ const { result } = renderHook(() => useOxyFollow(['user1', 'user2']), { wrapper });
59
+
60
+ expect(result.current).toHaveProperty('followData');
61
+ expect(result.current).toHaveProperty('toggleFollowForUser');
62
+ expect(result.current).toHaveProperty('setFollowStatusForUser');
63
+ expect(result.current).toHaveProperty('fetchStatusForUser');
64
+ expect(result.current).toHaveProperty('fetchAllStatuses');
65
+ expect(result.current).toHaveProperty('clearErrorForUser');
66
+ expect(result.current).toHaveProperty('isAnyLoading');
67
+ expect(result.current).toHaveProperty('hasAnyError');
68
+ expect(result.current).toHaveProperty('allFollowing');
69
+ expect(result.current).toHaveProperty('allNotFollowing');
70
+ });
71
+
72
+ test('should integrate with custom app reducers', () => {
73
+ const store = configureStore({
74
+ reducer: {
75
+ ...setupOxyStore(),
76
+ customApp: (state = { feature: 'enabled' }) => state,
77
+ },
78
+ });
79
+
80
+ const wrapper = createWrapper(store);
81
+
82
+ const { result } = renderHook(() => useOxyFollow('user1'), { wrapper });
83
+
84
+ // Should still work with Oxy features
85
+ expect(result.current.isFollowing).toBe(false);
86
+ expect(result.current.isLoading).toBe(false);
87
+
88
+ // Custom app state should also be accessible in the store
89
+ const state = store.getState();
90
+ expect(state.customApp.feature).toBe('enabled');
91
+ });
92
+ });
@@ -0,0 +1,50 @@
1
+ import { configureStore } from '@reduxjs/toolkit';
2
+ import { setupOxyStore, oxyReducers } from '../../../ui/store/setupOxyStore';
3
+ import { authSlice, followSlice } from '../../../ui/store/slices';
4
+
5
+ describe('setupOxyStore', () => {
6
+ test('should return all Oxy reducers', () => {
7
+ const reducers = setupOxyStore();
8
+
9
+ expect(reducers).toHaveProperty('auth');
10
+ expect(reducers).toHaveProperty('follow');
11
+ expect(reducers.auth).toBe(authSlice.reducer);
12
+ expect(reducers.follow).toBe(followSlice.reducer);
13
+ });
14
+
15
+ test('should work with configureStore', () => {
16
+ const store = configureStore({
17
+ reducer: {
18
+ ...setupOxyStore(),
19
+ customReducer: (state = { test: true }) => state,
20
+ },
21
+ });
22
+
23
+ const state = store.getState();
24
+ expect(state).toHaveProperty('auth');
25
+ expect(state).toHaveProperty('follow');
26
+ expect(state).toHaveProperty('customReducer');
27
+ expect(state.customReducer.test).toBe(true);
28
+ });
29
+
30
+ test('should support tree-shaking with pick method', () => {
31
+ const authOnly = setupOxyStore.pick('auth');
32
+ expect(authOnly).toHaveProperty('auth');
33
+ expect(authOnly).not.toHaveProperty('follow');
34
+
35
+ const followOnly = setupOxyStore.pick('follow');
36
+ expect(followOnly).toHaveProperty('follow');
37
+ expect(followOnly).not.toHaveProperty('auth');
38
+
39
+ const both = setupOxyStore.pick('auth', 'follow');
40
+ expect(both).toHaveProperty('auth');
41
+ expect(both).toHaveProperty('follow');
42
+ });
43
+
44
+ test('should export individual reducers', () => {
45
+ expect(oxyReducers).toHaveProperty('auth');
46
+ expect(oxyReducers).toHaveProperty('follow');
47
+ expect(oxyReducers.auth).toBe(authSlice.reducer);
48
+ expect(oxyReducers.follow).toBe(followSlice.reducer);
49
+ });
50
+ });
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Simple file structure validation for the new Redux architecture
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const requiredFiles = [
9
+ 'src/ui/store/setupOxyStore.ts',
10
+ 'src/ui/store/slices/authSlice.ts',
11
+ 'src/ui/store/slices/followSlice.ts',
12
+ 'src/ui/store/slices/types.ts',
13
+ 'src/ui/store/slices/index.ts',
14
+ 'src/ui/hooks/useOxyFollow.ts',
15
+ 'docs/redux-integration.md',
16
+ 'docs/migration-guide-redux.md',
17
+ ];
18
+
19
+ const requiredExports = [
20
+ 'setupOxyStore',
21
+ 'authSlice',
22
+ 'followSlice',
23
+ 'authReducer',
24
+ 'followReducer',
25
+ 'useOxyFollow',
26
+ ];
27
+
28
+ console.log('🔍 Validating new Redux architecture...\n');
29
+
30
+ // Check required files exist
31
+ let filesValid = true;
32
+ for (const file of requiredFiles) {
33
+ const fullPath = path.join(__dirname, '..', '..', file);
34
+ if (fs.existsSync(fullPath)) {
35
+ console.log(`✅ ${file}`);
36
+ } else {
37
+ console.log(`❌ ${file} - MISSING`);
38
+ filesValid = false;
39
+ }
40
+ }
41
+
42
+ // Check key exports in files
43
+ const setupOxyStoreFile = path.join(__dirname, '..', 'ui', 'store', 'setupOxyStore.ts');
44
+ if (fs.existsSync(setupOxyStoreFile)) {
45
+ const content = fs.readFileSync(setupOxyStoreFile, 'utf8');
46
+ if (content.includes('export function setupOxyStore')) {
47
+ console.log('✅ setupOxyStore function exported');
48
+ } else {
49
+ console.log('❌ setupOxyStore function not found');
50
+ filesValid = false;
51
+ }
52
+ }
53
+
54
+ const indexFile = path.join(__dirname, '..', 'ui', 'index.ts');
55
+ if (fs.existsSync(indexFile)) {
56
+ const content = fs.readFileSync(indexFile, 'utf8');
57
+ const exportsFound = requiredExports.filter(exp => content.includes(exp));
58
+ console.log(`✅ Exports found in ui/index.ts: ${exportsFound.join(', ')}`);
59
+
60
+ if (exportsFound.length < requiredExports.length) {
61
+ const missing = requiredExports.filter(exp => !exportsFound.includes(exp));
62
+ console.log(`⚠️ Missing exports: ${missing.join(', ')}`);
63
+ }
64
+ }
65
+
66
+ // Check main index file
67
+ const mainIndexFile = path.join(__dirname, '..', 'index.ts');
68
+ if (fs.existsSync(mainIndexFile)) {
69
+ const content = fs.readFileSync(mainIndexFile, 'utf8');
70
+ if (content.includes('setupOxyStore')) {
71
+ console.log('✅ setupOxyStore exported from main index');
72
+ } else {
73
+ console.log('❌ setupOxyStore not exported from main index');
74
+ filesValid = false;
75
+ }
76
+ }
77
+
78
+ console.log('\n' + '='.repeat(50));
79
+ if (filesValid) {
80
+ console.log('🎉 All validations passed! New Redux architecture is properly implemented.');
81
+ console.log('\nKey features:');
82
+ console.log('- ✅ Framework-agnostic Redux integration');
83
+ console.log('- ✅ Tree-shakable with setupOxyStore.pick()');
84
+ console.log('- ✅ Individual slice exports');
85
+ console.log('- ✅ External store support');
86
+ console.log('- ✅ Backward compatibility');
87
+ console.log('- ✅ Comprehensive documentation');
88
+ } else {
89
+ console.log('❌ Some validations failed. Please check the missing files/exports.');
90
+ process.exit(1);
91
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Simple validation test for the new Redux architecture
3
+ * This test can be run to ensure the refactoring works correctly
4
+ */
5
+
6
+ import { configureStore } from '@reduxjs/toolkit';
7
+
8
+ // Test that setupOxyStore can be imported and used
9
+ try {
10
+ const { setupOxyStore } = require('../ui/store/setupOxyStore');
11
+
12
+ console.log('✅ setupOxyStore imported successfully');
13
+
14
+ // Test basic usage
15
+ const reducers = setupOxyStore();
16
+ console.log('✅ setupOxyStore() returns reducers:', Object.keys(reducers));
17
+
18
+ // Test tree-shaking
19
+ const authOnly = setupOxyStore.pick('auth');
20
+ console.log('✅ Tree-shaking works:', Object.keys(authOnly));
21
+
22
+ // Test with configureStore
23
+ const store = configureStore({
24
+ reducer: {
25
+ ...setupOxyStore(),
26
+ custom: (state = { test: true }) => state,
27
+ },
28
+ });
29
+
30
+ const state = store.getState();
31
+ console.log('✅ Store integration works:', Object.keys(state));
32
+
33
+ // Test individual exports
34
+ const { authSlice, followSlice } = require('../ui/store/slices');
35
+ console.log('✅ Individual slices exported:', authSlice.name, followSlice.name);
36
+
37
+ console.log('\n🎉 All tests passed! The new Redux architecture is working correctly.');
38
+
39
+ } catch (error) {
40
+ console.error('❌ Test failed:', error);
41
+ process.exit(1);
42
+ }
package/src/core/index.ts CHANGED
@@ -1676,72 +1676,6 @@ export class OxyServices {
1676
1676
  throw this.handleError(error);
1677
1677
  }
1678
1678
  }
1679
-
1680
- /**
1681
- * Health check endpoint to verify API connectivity
1682
- * @returns Health status and basic server info
1683
- */
1684
- async healthCheck(): Promise<{
1685
- status: string;
1686
- users?: number;
1687
- timestamp?: string;
1688
- [key: string]: any
1689
- }> {
1690
- try {
1691
- const res = await this.client.get('/');
1692
- return res.data;
1693
- } catch (error) {
1694
- throw this.handleError(error);
1695
- }
1696
- }
1697
-
1698
- /**
1699
- * Download file content using authenticated request
1700
- * @param fileId - The file ID to download
1701
- * @returns Response object for further processing
1702
- */
1703
- async downloadFileContent(fileId: string): Promise<Response> {
1704
- try {
1705
- const downloadUrl = this.getFileDownloadUrl(fileId);
1706
- const response = await fetch(downloadUrl);
1707
-
1708
- if (!response.ok) {
1709
- throw new Error(`Download failed: ${response.status} ${response.statusText}`);
1710
- }
1711
-
1712
- return response;
1713
- } catch (error) {
1714
- throw this.handleError(error);
1715
- }
1716
- }
1717
-
1718
- /**
1719
- * Get file content as text using authenticated request
1720
- * @param fileId - The file ID to get content for
1721
- * @returns File content as string
1722
- */
1723
- async getFileContentAsText(fileId: string): Promise<string> {
1724
- try {
1725
- const response = await this.downloadFileContent(fileId);
1726
- return await response.text();
1727
- } catch (error) {
1728
- throw this.handleError(error);
1729
- }
1730
- }
1731
-
1732
- /**
1733
- * Get file content as blob using authenticated request
1734
- * @param fileId - The file ID to get content for
1735
- * @returns File content as blob
1736
- */
1737
- async getFileContentAsBlob(fileId: string): Promise<Blob> {
1738
- try {
1739
- const response = await this.downloadFileContent(fileId);
1740
- return await response.blob();
1741
- } catch (error) {
1742
- throw this.handleError(error);
1743
- }
1744
- }
1745
1679
  }
1746
1680
 
1747
1681
  export default OxyServices;
package/src/index.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  OxyProvider,
19
19
  OxyContextProvider,
20
20
  useOxy,
21
+ useAuthFetch,
21
22
 
22
23
  // Components
23
24
  OxySignInButton,
@@ -39,9 +40,8 @@ import { OxyContextState, OxyContextProviderProps } from './ui/context/OxyContex
39
40
  import * as Models from './models/interfaces';
40
41
 
41
42
  // ------------- Core Exports -------------
42
- export default OxyCore; // Default export for backward compatibility
43
- export { OxyServices };
44
- export * from './core';
43
+ export { OxyCore, OxyServices };
44
+ export default OxyServices; // Default export for backward compatibility
45
45
 
46
46
  // ------------- Utility Exports -------------
47
47
  export { DeviceManager } from './utils';
@@ -57,6 +57,7 @@ export {
57
57
  OxyProvider,
58
58
  OxyContextProvider,
59
59
  useOxy,
60
+ useAuthFetch,
60
61
 
61
62
  // Components
62
63
  OxySignInButton,
@@ -68,10 +69,41 @@ export {
68
69
  useFollow,
69
70
  ProfileScreen,
70
71
  OxyRouter,
72
+
73
+ // Redux Store - NEW ARCHITECTURE
74
+ setupOxyStore,
75
+ oxyReducers,
76
+ // Individual slices
77
+ authSlice,
78
+ authActions,
79
+ authSelectors,
80
+ authReducer,
81
+ followSlice,
82
+ followActions,
83
+ followSelectors,
84
+ followThunks,
85
+ followReducer,
86
+ // Action creators
87
+ loginStart,
88
+ loginSuccess,
89
+ loginFailure,
90
+ logout,
91
+ setFollowingStatus,
92
+ clearFollowError,
93
+ resetFollowState,
94
+ fetchFollowStatus,
95
+ toggleFollowUser,
96
+ // Types
97
+ type AuthState,
98
+ type FollowState,
99
+ initialAuthState,
100
+ initialFollowState,
101
+
102
+ // Legacy exports (deprecated)
71
103
  store,
72
104
  type RootState,
73
105
  type AppDispatch,
74
- };
106
+ } from './ui';
75
107
 
76
108
  // ------------- Type Exports -------------
77
109
  export { OxyContextState, OxyContextProviderProps };
@@ -142,31 +142,17 @@ const FollowButton: React.FC<FollowButtonProps> = ({
142
142
  const dispatch = useDispatch();
143
143
  const { oxyServices, isAuthenticated } = useOxy();
144
144
 
145
- // Optimized single selector to prevent multiple re-renders with defensive checks
146
- const followState = useSelector((state: RootState) => {
147
- // Defensive check to handle cases where follow state might not be initialized yet
148
- if (!state.follow) {
149
- return {
150
- isFollowing: initiallyFollowing ?? false,
151
- isLoading: false,
152
- error: null
153
- };
154
- }
155
-
156
- return {
157
- isFollowing: state.follow.followingUsers?.[userId] ?? initiallyFollowing ?? false,
158
- isLoading: state.follow.loadingUsers?.[userId] ?? false,
159
- error: state.follow.errors?.[userId] ?? null
160
- };
161
- });
162
-
163
- // Whether the follow status has been loaded from the store with defensive check
164
- const isStatusKnown = useSelector((state: RootState) => {
165
- if (!state.follow?.followingUsers) {
166
- return false;
167
- }
168
- return Object.prototype.hasOwnProperty.call(state.follow.followingUsers, userId);
169
- });
145
+ // Optimized single selector to prevent multiple re-renders
146
+ const followState = useSelector((state: RootState) => ({
147
+ isFollowing: state.follow.followingUsers[userId] ?? initiallyFollowing ?? false,
148
+ isLoading: state.follow.loadingUsers[userId] ?? false,
149
+ error: state.follow.errors[userId]
150
+ }));
151
+
152
+ // Whether the follow status has been loaded from the store
153
+ const isStatusKnown = useSelector((state: RootState) =>
154
+ Object.prototype.hasOwnProperty.call(state.follow.followingUsers, userId)
155
+ );
170
156
 
171
157
  const { isFollowing, isLoading, error } = followState;
172
158
 
@@ -32,55 +32,70 @@ const OxyProvider: React.FC<OxyProviderProps> = (props) => {
32
32
  onAuthStateChange,
33
33
  storageKeyPrefix,
34
34
  showInternalToaster = true,
35
+ store: externalStore,
36
+ skipReduxProvider = false,
35
37
  ...bottomSheetProps
36
38
  } = props;
37
39
 
38
40
  // Create internal bottom sheet ref
39
41
  const internalBottomSheetRef = useRef<BottomSheetModalRef>(null);
40
42
 
41
- // If contextOnly is true, we just provide the context without the bottom sheet UI
42
- if (contextOnly) {
43
+ // Determine which store to use
44
+ const storeToUse = externalStore || store;
45
+
46
+ // Helper function to wrap content with Redux Provider if needed
47
+ const wrapWithReduxProvider = (content: React.ReactNode) => {
48
+ if (skipReduxProvider) {
49
+ // App manages Redux Provider externally
50
+ return content;
51
+ }
52
+
43
53
  return (
44
- <Provider store={store}>
45
- <OxyContextProvider
46
- oxyServices={oxyServices}
47
- storageKeyPrefix={storageKeyPrefix}
48
- onAuthStateChange={onAuthStateChange}
49
- >
50
- {children}
51
- </OxyContextProvider>
54
+ <Provider store={storeToUse}>
55
+ {content}
52
56
  </Provider>
53
57
  );
54
- }
58
+ };
55
59
 
56
- // Otherwise, provide both the context and the bottom sheet UI
57
- return (
58
- <Provider store={store}>
60
+ // If contextOnly is true, we just provide the context without the bottom sheet UI
61
+ if (contextOnly) {
62
+ return wrapWithReduxProvider(
59
63
  <OxyContextProvider
60
64
  oxyServices={oxyServices}
61
65
  storageKeyPrefix={storageKeyPrefix}
62
66
  onAuthStateChange={onAuthStateChange}
63
- bottomSheetRef={internalBottomSheetRef}
64
67
  >
65
- <FontLoader>
66
- <GestureHandlerRootView style={styles.gestureHandlerRoot}>
67
- <BottomSheetModalProvider>
68
- <StatusBar translucent backgroundColor="transparent" />
69
- <SafeAreaProvider>
70
- <OxyBottomSheet {...bottomSheetProps} bottomSheetRef={internalBottomSheetRef} oxyServices={oxyServices} />
71
- {children}
72
- </SafeAreaProvider>
73
- </BottomSheetModalProvider>
74
- {/* Global Toaster for app-wide notifications outside of Modal contexts - only show if internal toaster is disabled */}
75
- {!showInternalToaster && (
76
- <View style={styles.toasterContainer}>
77
- <Toaster position="top-center" swipeToDismissDirection="left" offset={15} />
78
- </View>
79
- )}
80
- </GestureHandlerRootView>
81
- </FontLoader>
68
+ {children}
82
69
  </OxyContextProvider>
83
- </Provider>
70
+ );
71
+ }
72
+
73
+ // Otherwise, provide both the context and the bottom sheet UI
74
+ return wrapWithReduxProvider(
75
+ <OxyContextProvider
76
+ oxyServices={oxyServices}
77
+ storageKeyPrefix={storageKeyPrefix}
78
+ onAuthStateChange={onAuthStateChange}
79
+ bottomSheetRef={internalBottomSheetRef}
80
+ >
81
+ <FontLoader>
82
+ <GestureHandlerRootView style={styles.gestureHandlerRoot}>
83
+ <BottomSheetModalProvider>
84
+ <StatusBar translucent backgroundColor="transparent" />
85
+ <SafeAreaProvider>
86
+ <OxyBottomSheet {...bottomSheetProps} bottomSheetRef={internalBottomSheetRef} oxyServices={oxyServices} />
87
+ {children}
88
+ </SafeAreaProvider>
89
+ </BottomSheetModalProvider>
90
+ {/* Global Toaster for app-wide notifications outside of Modal contexts - only show if internal toaster is disabled */}
91
+ {!showInternalToaster && (
92
+ <View style={styles.toasterContainer}>
93
+ <Toaster position="top-center" swipeToDismissDirection="left" offset={15} />
94
+ </View>
95
+ )}
96
+ </GestureHandlerRootView>
97
+ </FontLoader>
98
+ </OxyContextProvider>
84
99
  );
85
100
  };
86
101
 
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { TouchableOpacity, Text, View, StyleSheet, ViewStyle, TextStyle, StyleProp, Platform } from 'react-native';
3
3
  import { useOxy } from '../context/OxyContext';
4
4
  import OxyLogo from './OxyLogo';
5
- import { fontFamilies } from '../styles/fonts';
5
+ import { fontFamilies, shadows } from '../styles';
6
6
 
7
7
  export interface OxySignInButtonProps {
8
8
  /**
@@ -168,11 +168,7 @@ const styles = StyleSheet.create({
168
168
  backgroundColor: '#FFFFFF',
169
169
  borderWidth: 1,
170
170
  borderColor: '#DDDDDD',
171
- shadowColor: '#000000',
172
- shadowOffset: { width: 0, height: 2 },
173
- shadowOpacity: 0.1,
174
- shadowRadius: 4,
175
- elevation: 2,
171
+ ...shadows.button,
176
172
  },
177
173
  buttonOutline: {
178
174
  backgroundColor: 'transparent',
@@ -1 +1,2 @@
1
- export { useFollow } from './useFollow';
1
+ export { useOxyFollow, useFollow } from './useOxyFollow';
2
+ export { useAuthFetch } from './useAuthFetch';