diff --git a/src/services/User.ts b/src/services/User.ts index 4e30a21f4b..18c7664f31 100644 --- a/src/services/User.ts +++ b/src/services/User.ts @@ -15,7 +15,6 @@ import { convertObjectDatesToFirestoreTimestamps, convertToTimestamp, firestoreDataConverter, - transformFirebaseDataList, } from "@/shared/utils"; import firebase from "@/shared/utils/firebase"; import * as cacheActions from "@/store/states/cache/actions"; @@ -51,31 +50,56 @@ class UserService { }; }; - public getUserById = async (userId: string): Promise => { - const userSnapshot = await this.getUsersCollection() + public getUserById = async ( + userId: string, + cached = false, + ): Promise => { + const snapshot = await this.getUsersCollection() .where("uid", "==", userId) - .get(); + .get({ source: cached ? "cache" : "default" }); + const users = snapshot.docs.map((doc) => doc.data()); + const user = users[0] || null; + + if (cached && !user) { + return this.getUserById(userId); + } - return transformFirebaseDataList(userSnapshot)[0] || null; + return user; }; public getCachedUserById = async (userId: string): Promise => { - const userState = store.getState().cache.userStates[userId]; + try { + const userState = store.getState().cache.userStates[userId]; - if (userState?.fetched) { - return userState.data; - } - if (userState?.loading) { - return await waitForUserToBeLoaded(userId); - } + if (userState?.fetched) { + return userState.data; + } + if (userState?.loading) { + return await waitForUserToBeLoaded(userId); + } - store.dispatch( - cacheActions.getUserStateById.request({ - payload: { userId }, - }), - ); + store.dispatch( + cacheActions.getUserStateById.request({ + payload: { userId }, + }), + ); + + return await waitForUserToBeLoaded(userId); + } catch (err) { + const user = await this.getUserById(userId, true); + store.dispatch( + cacheActions.updateUserStateById({ + userId, + state: { + loading: false, + fetched: true, + data: user, + }, + }), + ); - return await waitForUserToBeLoaded(userId); + return user; + } }; public getCachedUsersById = async (userIds: string[]): Promise => diff --git a/src/store/states/cache/index.ts b/src/store/states/cache/index.ts index 2a0fca605d..ea30e2f27e 100644 --- a/src/store/states/cache/index.ts +++ b/src/store/states/cache/index.ts @@ -1,5 +1,5 @@ export * as cacheActions from "./actions"; -export { reducer as cacheReducer } from "./reducer"; +export { reducer as cacheReducer, INITIAL_CACHE_STATE } from "./reducer"; export { mainSaga as cacheSaga } from "./saga"; export * from "./selectors"; export * from "./types"; diff --git a/src/store/states/cache/reducer.tsx b/src/store/states/cache/reducer.tsx index d30e54de54..50874f2638 100644 --- a/src/store/states/cache/reducer.tsx +++ b/src/store/states/cache/reducer.tsx @@ -8,7 +8,7 @@ import { CacheState } from "./types"; type Action = ActionType; -const initialState: CacheState = { +export const INITIAL_CACHE_STATE: CacheState = { userStates: {}, governanceByCommonIdStates: {}, discussionStates: {}, @@ -19,7 +19,7 @@ const initialState: CacheState = { chatChannelUserStatusStates: {}, }; -export const reducer = createReducer(initialState) +export const reducer = createReducer(INITIAL_CACHE_STATE) .handleAction(actions.updateUserStateById, (state, { payload }) => produce(state, (nextState) => { const { userId, state } = payload; @@ -115,8 +115,7 @@ export const reducer = createReducer(initialState) const uniq = unionBy( payload.state?.data ?? [], - state.discussionMessagesStates[discussionId]?.data ?? - [], + state.discussionMessagesStates[discussionId]?.data ?? [], "id", ).sort( (a, b) => @@ -136,8 +135,7 @@ export const reducer = createReducer(initialState) const { discussionId, discussionMessage } = payload; const updatedDiscussionMessages = [ - ...(state.discussionMessagesStates[discussionId] - ?.data ?? []), + ...(state.discussionMessagesStates[discussionId]?.data ?? []), discussionMessage, ]; diff --git a/src/store/transforms.ts b/src/store/transforms.ts index 0bde9e2597..b8622cbe89 100644 --- a/src/store/transforms.ts +++ b/src/store/transforms.ts @@ -1,9 +1,12 @@ import { createTransform } from "redux-persist"; -import { deserializeFeedLayoutItemWithFollowData } from "@/shared/interfaces"; +import { + deserializeFeedLayoutItemWithFollowData, + LoadingState, +} from "@/shared/interfaces"; import { convertObjectDatesToFirestoreTimestamps } from "@/shared/utils"; import { MultipleSpacesLayoutState } from "@/store/states"; import { getFeedLayoutItemDateForSorting } from "@/store/states/inbox/utils"; -import { CacheState } from "./states/cache"; +import { CacheState, INITIAL_CACHE_STATE } from "./states/cache"; import { InboxItems, InboxState, @@ -11,6 +14,20 @@ import { INITIAL_INBOX_STATE, } from "./states/inbox"; +const clearNonFinishedStates = ( + states: Record>, +): Record> => + Object.entries(states).reduce((acc, [key, value]) => { + if (value.loading || !value.fetched) { + return acc; + } + + return { + ...acc, + [key]: value, + }; + }, {}); + export const inboxTransform = createTransform( (inboundState: InboxState) => { if (inboundState.items.unread) { @@ -65,11 +82,12 @@ export const inboxTransform = createTransform( ); export const cacheTransform = createTransform( - (inboundState: CacheState) => inboundState, - (outboundState: CacheState) => ({ - ...outboundState, - discussionMessagesStates: {}, + (inboundState: CacheState) => ({ + ...INITIAL_CACHE_STATE, + userStates: clearNonFinishedStates(inboundState.userStates), + feedByCommonIdStates: inboundState.feedByCommonIdStates, }), + (outboundState: CacheState) => outboundState, { whitelist: ["cache"] }, );