@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
@@ -1,259 +1,33 @@
1
1
  "use strict";
2
2
 
3
- import { configureStore, createSlice, createAsyncThunk } from '@reduxjs/toolkit';
4
- const initialAuthState = {
5
- user: null,
6
- isAuthenticated: false,
7
- isLoading: false,
8
- error: null
9
- };
10
- const initialFollowState = {
11
- followingUsers: {},
12
- loadingUsers: {},
13
- fetchingUsers: {},
14
- errors: {}
15
- };
3
+ /**
4
+ * OxyHQ Services Redux Store
5
+ * Framework-agnostic, tree-shakable Redux integration
6
+ *
7
+ * This module exports individual slices, reducers, actions, selectors, and helpers
8
+ * for easy integration into any Redux store without internal dependencies.
9
+ */
16
10
 
17
- // Async thunk for fetching follow status from backend with deduplication
18
- export const fetchFollowStatus = createAsyncThunk('follow/fetchFollowStatus', async ({
19
- userId,
20
- oxyServices
21
- }, {
22
- rejectWithValue
23
- }) => {
24
- try {
25
- // Use the proper core service method
26
- const response = await oxyServices.getFollowStatus(userId);
27
- return {
28
- userId,
29
- isFollowing: response.isFollowing
30
- };
31
- } catch (error) {
32
- // Ignore authentication errors when user isn't signed in - don't update state
33
- if (error?.status === 401 || error?.message?.includes('Authentication')) {
34
- return rejectWithValue('Not authenticated');
35
- }
36
- // Log other failures and reject to not update state
37
- console.warn(`Failed to fetch follow status for user ${userId}:`, error);
38
- return rejectWithValue(error?.message || 'Failed to fetch follow status');
39
- }
40
- }, {
41
- // Prevent duplicate requests for the same user ID
42
- condition: ({
43
- userId
44
- }, {
45
- getState
46
- }) => {
47
- const state = getState();
48
- // Defensive check for follow state
49
- if (!state.follow?.fetchingUsers) {
50
- return true; // Allow request if state not initialized
51
- }
52
- const isAlreadyFetching = state.follow.fetchingUsers[userId];
53
- if (isAlreadyFetching) {
54
- console.log(`⚡ Deduplicating fetch request for user ${userId} - already in progress`);
55
- return false; // Cancel this request
56
- }
57
- return true; // Allow this request
58
- }
59
- });
11
+ // Export individual slices and their components
12
+ export * from './slices';
60
13
 
61
- // Async thunk for following/unfollowing users using core services
62
- export const toggleFollowUser = createAsyncThunk('follow/toggleFollowUser', async ({
63
- userId,
64
- oxyServices,
65
- isCurrentlyFollowing
66
- }, {
67
- rejectWithValue,
68
- dispatch
69
- }) => {
70
- try {
71
- let response;
72
- let newFollowState;
73
- if (isCurrentlyFollowing) {
74
- // Use the core service to unfollow user
75
- response = await oxyServices.unfollowUser(userId);
76
- newFollowState = false;
77
- } else {
78
- // Use the core service to follow user
79
- response = await oxyServices.followUser(userId);
80
- newFollowState = true;
81
- }
14
+ // Export setup helper for easy integration
15
+ export { setupOxyStore, oxyReducers } from './setupOxyStore';
82
16
 
83
- // Check if the response indicates success (different APIs might return different formats)
84
- const isSuccess = response.success !== false && response.action !== 'error';
85
- if (isSuccess) {
86
- return {
87
- userId,
88
- isFollowing: newFollowState,
89
- message: response.message || `Successfully ${newFollowState ? 'followed' : 'unfollowed'} user`
90
- };
91
- } else {
92
- return rejectWithValue(response.message || `Failed to ${newFollowState ? 'follow' : 'unfollow'} user`);
93
- }
94
- } catch (error) {
95
- // Enhanced error handling with state mismatch detection
96
- let errorMessage = 'Network error occurred';
97
- if (error?.message) {
98
- errorMessage = error.message;
99
- } else if (error?.response?.data?.message) {
100
- errorMessage = error.response.data.message;
101
- } else if (error?.data?.message) {
102
- errorMessage = error.data.message;
103
- }
17
+ // Export types for external store integration
104
18
 
105
- // Handle state mismatch errors by syncing with backend
106
- if (errorMessage.includes('Not following this user') && isCurrentlyFollowing) {
107
- console.warn(`State mismatch detected for user ${userId}: Frontend thinks following, backend says not following. Syncing state...`);
108
- // Auto-sync with backend state
109
- try {
110
- const actualStatus = await oxyServices.getFollowStatus(userId);
111
- dispatch({
112
- type: 'follow/setFollowingStatus',
113
- payload: {
114
- userId,
115
- isFollowing: actualStatus.isFollowing
116
- }
117
- });
118
- return rejectWithValue('State synced with backend. Please try again.');
119
- } catch (syncError) {
120
- console.error('Failed to sync state with backend:', syncError);
121
- }
122
- } else if (errorMessage.includes('Already following this user') && !isCurrentlyFollowing) {
123
- console.warn(`State mismatch detected for user ${userId}: Frontend thinks not following, backend says following. Syncing state...`);
124
- // Auto-sync with backend state
125
- try {
126
- const actualStatus = await oxyServices.getFollowStatus(userId);
127
- dispatch({
128
- type: 'follow/setFollowingStatus',
129
- payload: {
130
- userId,
131
- isFollowing: actualStatus.isFollowing
132
- }
133
- });
134
- return rejectWithValue('State synced with backend. Please try again.');
135
- } catch (syncError) {
136
- console.error('Failed to sync state with backend:', syncError);
137
- }
138
- }
139
- return rejectWithValue(errorMessage);
140
- }
141
- });
142
- const authSlice = createSlice({
143
- name: 'auth',
144
- initialState: initialAuthState,
145
- reducers: {
146
- loginStart(state) {
147
- state.isLoading = true;
148
- state.error = null;
149
- },
150
- loginSuccess(state, action) {
151
- state.isLoading = false;
152
- state.isAuthenticated = true;
153
- state.user = action.payload;
154
- },
155
- loginFailure(state, action) {
156
- state.isLoading = false;
157
- state.error = action.payload;
158
- },
159
- logout(state) {
160
- state.user = null;
161
- state.isAuthenticated = false;
162
- }
163
- }
164
- });
165
- const followSlice = createSlice({
166
- name: 'follow',
167
- initialState: initialFollowState,
168
- reducers: {
169
- setFollowingStatus(state, action) {
170
- const {
171
- userId,
172
- isFollowing
173
- } = action.payload;
174
- state.followingUsers[userId] = isFollowing;
175
- state.errors[userId] = null;
176
- },
177
- clearFollowError(state, action) {
178
- const userId = action.payload;
179
- state.errors[userId] = null;
180
- },
181
- resetFollowState(state) {
182
- state.followingUsers = {};
183
- state.loadingUsers = {};
184
- state.fetchingUsers = {};
185
- state.errors = {};
186
- }
187
- },
188
- extraReducers: builder => {
189
- builder
190
- // Handle fetchFollowStatus
191
- .addCase(fetchFollowStatus.pending, (state, action) => {
192
- const {
193
- userId
194
- } = action.meta.arg;
195
- state.fetchingUsers[userId] = true;
196
- state.errors[userId] = null;
197
- }).addCase(fetchFollowStatus.fulfilled, (state, action) => {
198
- const {
199
- userId,
200
- isFollowing
201
- } = action.payload;
202
- state.followingUsers[userId] = isFollowing;
203
- state.fetchingUsers[userId] = false;
204
- state.errors[userId] = null;
205
- }).addCase(fetchFollowStatus.rejected, (state, action) => {
206
- const {
207
- userId
208
- } = action.meta.arg;
209
- state.fetchingUsers[userId] = false;
210
- // Don't update follow state on fetch errors - preserve existing/initial state
211
- if (action.payload !== 'Not authenticated') {
212
- console.warn(`Failed to fetch follow status for user ${userId}:`, action.payload);
213
- }
214
- })
215
- // Handle toggleFollowUser
216
- .addCase(toggleFollowUser.pending, (state, action) => {
217
- const {
218
- userId
219
- } = action.meta.arg;
220
- state.loadingUsers[userId] = true;
221
- state.errors[userId] = null;
222
- }).addCase(toggleFollowUser.fulfilled, (state, action) => {
223
- const {
224
- userId,
225
- isFollowing
226
- } = action.payload;
227
- state.followingUsers[userId] = isFollowing;
228
- state.loadingUsers[userId] = false;
229
- state.errors[userId] = null;
230
- }).addCase(toggleFollowUser.rejected, (state, action) => {
231
- const {
232
- userId
233
- } = action.meta.arg;
234
- state.loadingUsers[userId] = false;
235
- state.errors[userId] = action.error.message || 'Failed to update follow status';
236
- });
237
- }
238
- });
239
- export const {
240
- loginStart,
241
- loginSuccess,
242
- loginFailure,
243
- logout
244
- } = authSlice.actions;
245
- export const {
246
- setFollowingStatus,
247
- clearFollowError,
248
- resetFollowState
249
- } = followSlice.actions;
19
+ // For backward compatibility: create a legacy store instance
20
+ // This will be deprecated in favor of setupOxyStore()
21
+ import { configureStore } from '@reduxjs/toolkit';
22
+ import { setupOxyStore } from './setupOxyStore';
250
23
 
251
- // Selectors for follow state
252
- export const selectIsUserBeingFetched = (state, userId) => state.follow?.fetchingUsers?.[userId] ?? false;
24
+ /**
25
+ * @deprecated Use setupOxyStore() instead to integrate with your app's store
26
+ * This internal store will be removed in a future version
27
+ */
253
28
  export const store = configureStore({
254
- reducer: {
255
- auth: authSlice.reducer,
256
- follow: followSlice.reducer
257
- }
29
+ reducer: setupOxyStore()
258
30
  });
31
+ // Legacy selector (deprecated)
32
+ export const selectIsUserBeingFetched = (state, userId) => state.follow.fetchingUsers[userId] ?? false;
259
33
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["configureStore","createSlice","createAsyncThunk","initialAuthState","user","isAuthenticated","isLoading","error","initialFollowState","followingUsers","loadingUsers","fetchingUsers","errors","fetchFollowStatus","userId","oxyServices","rejectWithValue","response","getFollowStatus","isFollowing","status","message","includes","console","warn","condition","getState","state","follow","isAlreadyFetching","log","toggleFollowUser","isCurrentlyFollowing","dispatch","newFollowState","unfollowUser","followUser","isSuccess","success","action","errorMessage","data","actualStatus","type","payload","syncError","authSlice","name","initialState","reducers","loginStart","loginSuccess","loginFailure","logout","followSlice","setFollowingStatus","clearFollowError","resetFollowState","extraReducers","builder","addCase","pending","meta","arg","fulfilled","rejected","actions","selectIsUserBeingFetched","store","reducer","auth"],"sourceRoot":"../../../../src","sources":["ui/store/index.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["setupOxyStore","oxyReducers","configureStore","store","reducer","selectIsUserBeingFetched","state","userId","follow","fetchingUsers"],"sourceRoot":"../../../../src","sources":["ui/store/index.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc,UAAU;;AAExB;AACA,SAASA,aAAa,EAAEC,WAAW,QAAQ,iBAAiB;;AAE5D;;AAGA;AACA;AACA,SAASC,cAAc,QAAQ,kBAAkB;AACjD,SAASF,aAAa,QAAQ,iBAAiB;;AAE/C;AACA;AACA;AACA;AACA,OAAO,MAAMG,KAAK,GAAGD,cAAc,CAAC;EAClCE,OAAO,EAAEJ,aAAa,CAAC;AACzB,CAAC,CAAC;AAKF;AACA,OAAO,MAAMK,wBAAwB,GAAGA,CAACC,KAAgB,EAAEC,MAAc,KACvED,KAAK,CAACE,MAAM,CAACC,aAAa,CAACF,MAAM,CAAC,IAAI,KAAK","ignoreList":[]}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ import { authReducer } from './slices/authSlice';
4
+ import { followReducer } from './slices/followSlice';
5
+
6
+ /**
7
+ * Setup helper for Oxy Store
8
+ * Returns all Oxy reducers ready to be spread into a host app's Redux store
9
+ *
10
+ * Usage:
11
+ * ```ts
12
+ * const store = configureStore({
13
+ * reducer: {
14
+ * ...setupOxyStore(),
15
+ * appSpecificReducer,
16
+ * },
17
+ * });
18
+ * ```
19
+ */
20
+ export function setupOxyStore() {
21
+ return {
22
+ auth: authReducer,
23
+ follow: followReducer
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Tree-shakable version where you can pick specific reducers
29
+ *
30
+ * Usage:
31
+ * ```ts
32
+ * const store = configureStore({
33
+ * reducer: {
34
+ * ...setupOxyStore.pick('auth'), // Only include auth
35
+ * // or
36
+ * ...setupOxyStore.pick('auth', 'follow'), // Include both
37
+ * appSpecificReducer,
38
+ * },
39
+ * });
40
+ * ```
41
+ */
42
+ setupOxyStore.pick = function (...keys) {
43
+ const allReducers = setupOxyStore();
44
+ const pickedReducers = {};
45
+ for (const key of keys) {
46
+ if (key in allReducers) {
47
+ // Use bracket notation with explicit typing
48
+ pickedReducers[key] = allReducers[key];
49
+ }
50
+ }
51
+ return pickedReducers;
52
+ };
53
+
54
+ // Export individual reducers for maximum flexibility
55
+ export const oxyReducers = {
56
+ auth: authReducer,
57
+ follow: followReducer
58
+ };
59
+ //# sourceMappingURL=setupOxyStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["authReducer","followReducer","setupOxyStore","auth","follow","pick","keys","allReducers","pickedReducers","key","oxyReducers"],"sourceRoot":"../../../../src","sources":["ui/store/setupOxyStore.ts"],"mappings":";;AAAA,SAASA,WAAW,QAAQ,oBAAoB;AAChD,SAASC,aAAa,QAAQ,sBAAsB;;AAEpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,aAAaA,CAAA,EAAG;EAC9B,OAAO;IACLC,IAAI,EAAEH,WAAW;IACjBI,MAAM,EAAEH;EACV,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAC,aAAa,CAACG,IAAI,GAAG,UAAS,GAAGC,IAA8B,EAAE;EAC/D,MAAMC,WAAW,GAAGL,aAAa,CAAC,CAAC;EACnC,MAAMM,cAAc,GAAG,CAAC,CAA8C;EAEtE,KAAK,MAAMC,GAAG,IAAIH,IAAI,EAAE;IACtB,IAAIG,GAAG,IAAIF,WAAW,EAAE;MACtB;MACCC,cAAc,CAAyBC,GAAG,CAAC,GAAGF,WAAW,CAACE,GAAG,CAAC;IACjE;EACF;EAEA,OAAOD,cAAc;AACvB,CAAC;;AAED;AACA,OAAO,MAAME,WAAW,GAAG;EACzBP,IAAI,EAAEH,WAAW;EACjBI,MAAM,EAAEH;AACV,CAAC","ignoreList":[]}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ import { createSlice } from '@reduxjs/toolkit';
4
+ import { initialAuthState } from './types';
5
+ export const authSlice = createSlice({
6
+ name: 'auth',
7
+ initialState: initialAuthState,
8
+ reducers: {
9
+ loginStart(state) {
10
+ state.isLoading = true;
11
+ state.error = null;
12
+ },
13
+ loginSuccess(state, action) {
14
+ state.isLoading = false;
15
+ state.isAuthenticated = true;
16
+ state.user = action.payload;
17
+ },
18
+ loginFailure(state, action) {
19
+ state.isLoading = false;
20
+ state.error = action.payload;
21
+ },
22
+ logout(state) {
23
+ state.user = null;
24
+ state.isAuthenticated = false;
25
+ }
26
+ }
27
+ });
28
+
29
+ // Export actions
30
+ export const authActions = authSlice.actions;
31
+ export const {
32
+ loginStart,
33
+ loginSuccess,
34
+ loginFailure,
35
+ logout
36
+ } = authSlice.actions;
37
+
38
+ // Export selectors
39
+ export const authSelectors = {
40
+ selectUser: state => state.auth.user,
41
+ selectIsAuthenticated: state => state.auth.isAuthenticated,
42
+ selectIsLoading: state => state.auth.isLoading,
43
+ selectError: state => state.auth.error
44
+ };
45
+
46
+ // Export reducer
47
+ export const authReducer = authSlice.reducer;
48
+ //# sourceMappingURL=authSlice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["createSlice","initialAuthState","authSlice","name","initialState","reducers","loginStart","state","isLoading","error","loginSuccess","action","isAuthenticated","user","payload","loginFailure","logout","authActions","actions","authSelectors","selectUser","auth","selectIsAuthenticated","selectIsLoading","selectError","authReducer","reducer"],"sourceRoot":"../../../../../src","sources":["ui/store/slices/authSlice.ts"],"mappings":";;AAAA,SAASA,WAAW,QAAuB,kBAAkB;AAG7D,SAASC,gBAAgB,QAAQ,SAAS;AAE1C,OAAO,MAAMC,SAAS,GAAGF,WAAW,CAAC;EACnCG,IAAI,EAAE,MAAM;EACZC,YAAY,EAAEH,gBAAgB;EAC9BI,QAAQ,EAAE;IACRC,UAAUA,CAACC,KAAgB,EAAE;MAC3BA,KAAK,CAACC,SAAS,GAAG,IAAI;MACtBD,KAAK,CAACE,KAAK,GAAG,IAAI;IACpB,CAAC;IACDC,YAAYA,CAACH,KAAgB,EAAEI,MAA2B,EAAE;MAC1DJ,KAAK,CAACC,SAAS,GAAG,KAAK;MACvBD,KAAK,CAACK,eAAe,GAAG,IAAI;MAC5BL,KAAK,CAACM,IAAI,GAAGF,MAAM,CAACG,OAAO;IAC7B,CAAC;IACDC,YAAYA,CAACR,KAAgB,EAAEI,MAA6B,EAAE;MAC5DJ,KAAK,CAACC,SAAS,GAAG,KAAK;MACvBD,KAAK,CAACE,KAAK,GAAGE,MAAM,CAACG,OAAO;IAC9B,CAAC;IACDE,MAAMA,CAACT,KAAgB,EAAE;MACvBA,KAAK,CAACM,IAAI,GAAG,IAAI;MACjBN,KAAK,CAACK,eAAe,GAAG,KAAK;IAC/B;EACF;AACF,CAAC,CAAC;;AAEF;AACA,OAAO,MAAMK,WAAW,GAAGf,SAAS,CAACgB,OAAO;AAC5C,OAAO,MAAM;EAAEZ,UAAU;EAAEI,YAAY;EAAEK,YAAY;EAAEC;AAAO,CAAC,GAAGd,SAAS,CAACgB,OAAO;;AAEnF;AACA,OAAO,MAAMC,aAAa,GAAG;EAC3BC,UAAU,EAAGb,KAA0B,IAAKA,KAAK,CAACc,IAAI,CAACR,IAAI;EAC3DS,qBAAqB,EAAGf,KAA0B,IAAKA,KAAK,CAACc,IAAI,CAACT,eAAe;EACjFW,eAAe,EAAGhB,KAA0B,IAAKA,KAAK,CAACc,IAAI,CAACb,SAAS;EACrEgB,WAAW,EAAGjB,KAA0B,IAAKA,KAAK,CAACc,IAAI,CAACZ;AAC1D,CAAC;;AAED;AACA,OAAO,MAAMgB,WAAW,GAAGvB,SAAS,CAACwB,OAAO","ignoreList":[]}
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+
3
+ import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
4
+ import { initialFollowState } from './types';
5
+
6
+ // Define thunk state interface for dependency injection
7
+
8
+ // Async thunk for fetching follow status from backend with deduplication
9
+ export const fetchFollowStatus = createAsyncThunk('follow/fetchFollowStatus', async ({
10
+ userId,
11
+ oxyServices
12
+ }, {
13
+ rejectWithValue
14
+ }) => {
15
+ try {
16
+ // Use the proper core service method
17
+ const response = await oxyServices.getFollowStatus(userId);
18
+ return {
19
+ userId,
20
+ isFollowing: response.isFollowing
21
+ };
22
+ } catch (error) {
23
+ // Ignore authentication errors when user isn't signed in - don't update state
24
+ if (error?.status === 401 || error?.message?.includes('Authentication')) {
25
+ return rejectWithValue('Not authenticated');
26
+ }
27
+ // Log other failures and reject to not update state
28
+ console.warn(`Failed to fetch follow status for user ${userId}:`, error);
29
+ return rejectWithValue(error?.message || 'Failed to fetch follow status');
30
+ }
31
+ }, {
32
+ // Prevent duplicate requests for the same user ID
33
+ condition: ({
34
+ userId
35
+ }, {
36
+ getState
37
+ }) => {
38
+ const state = getState();
39
+ const isAlreadyFetching = state.follow.fetchingUsers[userId];
40
+ if (isAlreadyFetching) {
41
+ console.log(`⚡ Deduplicating fetch request for user ${userId} - already in progress`);
42
+ return false; // Cancel this request
43
+ }
44
+ return true; // Allow this request
45
+ }
46
+ });
47
+
48
+ // Async thunk for following/unfollowing users using core services
49
+ export const toggleFollowUser = createAsyncThunk('follow/toggleFollowUser', async ({
50
+ userId,
51
+ oxyServices,
52
+ isCurrentlyFollowing
53
+ }, {
54
+ rejectWithValue,
55
+ dispatch
56
+ }) => {
57
+ try {
58
+ let response;
59
+ let newFollowState;
60
+ if (isCurrentlyFollowing) {
61
+ // Use the core service to unfollow user
62
+ response = await oxyServices.unfollowUser(userId);
63
+ newFollowState = false;
64
+ } else {
65
+ // Use the core service to follow user
66
+ response = await oxyServices.followUser(userId);
67
+ newFollowState = true;
68
+ }
69
+
70
+ // Check if the response indicates success (different APIs might return different formats)
71
+ const isSuccess = response.success !== false && response.action !== 'error';
72
+ if (isSuccess) {
73
+ return {
74
+ userId,
75
+ isFollowing: newFollowState,
76
+ message: response.message || `Successfully ${newFollowState ? 'followed' : 'unfollowed'} user`
77
+ };
78
+ } else {
79
+ return rejectWithValue(response.message || `Failed to ${newFollowState ? 'follow' : 'unfollow'} user`);
80
+ }
81
+ } catch (error) {
82
+ // Enhanced error handling with state mismatch detection
83
+ let errorMessage = 'Network error occurred';
84
+ if (error?.message) {
85
+ errorMessage = error.message;
86
+ } else if (error?.response?.data?.message) {
87
+ errorMessage = error.response.data.message;
88
+ } else if (error?.data?.message) {
89
+ errorMessage = error.data.message;
90
+ }
91
+
92
+ // Handle state mismatch errors by syncing with backend
93
+ if (errorMessage.includes('Not following this user') && isCurrentlyFollowing) {
94
+ console.warn(`State mismatch detected for user ${userId}: Frontend thinks following, backend says not following. Syncing state...`);
95
+ // Auto-sync with backend state
96
+ try {
97
+ const actualStatus = await oxyServices.getFollowStatus(userId);
98
+ dispatch({
99
+ type: 'follow/setFollowingStatus',
100
+ payload: {
101
+ userId,
102
+ isFollowing: actualStatus.isFollowing
103
+ }
104
+ });
105
+ return rejectWithValue('State synced with backend. Please try again.');
106
+ } catch (syncError) {
107
+ console.error('Failed to sync state with backend:', syncError);
108
+ }
109
+ } else if (errorMessage.includes('Already following this user') && !isCurrentlyFollowing) {
110
+ console.warn(`State mismatch detected for user ${userId}: Frontend thinks not following, backend says following. Syncing state...`);
111
+ // Auto-sync with backend state
112
+ try {
113
+ const actualStatus = await oxyServices.getFollowStatus(userId);
114
+ dispatch({
115
+ type: 'follow/setFollowingStatus',
116
+ payload: {
117
+ userId,
118
+ isFollowing: actualStatus.isFollowing
119
+ }
120
+ });
121
+ return rejectWithValue('State synced with backend. Please try again.');
122
+ } catch (syncError) {
123
+ console.error('Failed to sync state with backend:', syncError);
124
+ }
125
+ }
126
+ return rejectWithValue(errorMessage);
127
+ }
128
+ });
129
+ export const followSlice = createSlice({
130
+ name: 'follow',
131
+ initialState: initialFollowState,
132
+ reducers: {
133
+ setFollowingStatus(state, action) {
134
+ const {
135
+ userId,
136
+ isFollowing
137
+ } = action.payload;
138
+ state.followingUsers[userId] = isFollowing;
139
+ state.errors[userId] = null;
140
+ },
141
+ clearFollowError(state, action) {
142
+ const userId = action.payload;
143
+ state.errors[userId] = null;
144
+ },
145
+ resetFollowState(state) {
146
+ state.followingUsers = {};
147
+ state.loadingUsers = {};
148
+ state.fetchingUsers = {};
149
+ state.errors = {};
150
+ }
151
+ },
152
+ extraReducers: builder => {
153
+ builder
154
+ // Handle fetchFollowStatus
155
+ .addCase(fetchFollowStatus.pending, (state, action) => {
156
+ const {
157
+ userId
158
+ } = action.meta.arg;
159
+ state.fetchingUsers[userId] = true;
160
+ state.errors[userId] = null;
161
+ }).addCase(fetchFollowStatus.fulfilled, (state, action) => {
162
+ const {
163
+ userId,
164
+ isFollowing
165
+ } = action.payload;
166
+ state.followingUsers[userId] = isFollowing;
167
+ state.fetchingUsers[userId] = false;
168
+ state.errors[userId] = null;
169
+ }).addCase(fetchFollowStatus.rejected, (state, action) => {
170
+ const {
171
+ userId
172
+ } = action.meta.arg;
173
+ state.fetchingUsers[userId] = false;
174
+ // Don't update follow state on fetch errors - preserve existing/initial state
175
+ if (action.payload !== 'Not authenticated') {
176
+ console.warn(`Failed to fetch follow status for user ${userId}:`, action.payload);
177
+ }
178
+ })
179
+ // Handle toggleFollowUser
180
+ .addCase(toggleFollowUser.pending, (state, action) => {
181
+ const {
182
+ userId
183
+ } = action.meta.arg;
184
+ state.loadingUsers[userId] = true;
185
+ state.errors[userId] = null;
186
+ }).addCase(toggleFollowUser.fulfilled, (state, action) => {
187
+ const {
188
+ userId,
189
+ isFollowing
190
+ } = action.payload;
191
+ state.followingUsers[userId] = isFollowing;
192
+ state.loadingUsers[userId] = false;
193
+ state.errors[userId] = null;
194
+ }).addCase(toggleFollowUser.rejected, (state, action) => {
195
+ const {
196
+ userId
197
+ } = action.meta.arg;
198
+ state.loadingUsers[userId] = false;
199
+ state.errors[userId] = action.error.message || 'Failed to update follow status';
200
+ });
201
+ }
202
+ });
203
+
204
+ // Export actions
205
+ export const followActions = followSlice.actions;
206
+ export const {
207
+ setFollowingStatus,
208
+ clearFollowError,
209
+ resetFollowState
210
+ } = followSlice.actions;
211
+
212
+ // Export thunks
213
+ export const followThunks = {
214
+ fetchFollowStatus,
215
+ toggleFollowUser
216
+ };
217
+
218
+ // Export selectors
219
+ export const followSelectors = {
220
+ selectFollowingUsers: state => state.follow.followingUsers,
221
+ selectLoadingUsers: state => state.follow.loadingUsers,
222
+ selectFetchingUsers: state => state.follow.fetchingUsers,
223
+ selectFollowErrors: state => state.follow.errors,
224
+ selectIsUserFollowed: (state, userId) => state.follow.followingUsers[userId] ?? false,
225
+ selectIsUserLoading: (state, userId) => state.follow.loadingUsers[userId] ?? false,
226
+ selectIsUserBeingFetched: (state, userId) => state.follow.fetchingUsers[userId] ?? false,
227
+ selectUserError: (state, userId) => state.follow.errors[userId] ?? null
228
+ };
229
+
230
+ // Export reducer
231
+ export const followReducer = followSlice.reducer;
232
+ //# sourceMappingURL=followSlice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["createSlice","createAsyncThunk","initialFollowState","fetchFollowStatus","userId","oxyServices","rejectWithValue","response","getFollowStatus","isFollowing","error","status","message","includes","console","warn","condition","getState","state","isAlreadyFetching","follow","fetchingUsers","log","toggleFollowUser","isCurrentlyFollowing","dispatch","newFollowState","unfollowUser","followUser","isSuccess","success","action","errorMessage","data","actualStatus","type","payload","syncError","followSlice","name","initialState","reducers","setFollowingStatus","followingUsers","errors","clearFollowError","resetFollowState","loadingUsers","extraReducers","builder","addCase","pending","meta","arg","fulfilled","rejected","followActions","actions","followThunks","followSelectors","selectFollowingUsers","selectLoadingUsers","selectFetchingUsers","selectFollowErrors","selectIsUserFollowed","selectIsUserLoading","selectIsUserBeingFetched","selectUserError","followReducer","reducer"],"sourceRoot":"../../../../../src","sources":["ui/store/slices/followSlice.ts"],"mappings":"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","ignoreList":[]}