Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use caching to load inbox and feed faster #2288 #2301

Merged
merged 22 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7b163e7
add caching of inbox items
andreymikhadyuk Nov 6, 2023
04881b8
install and configure redux-persist library
andreymikhadyuk Nov 6, 2023
ca1d308
remove timestamp methods usage
andreymikhadyuk Nov 6, 2023
df5ccab
add whitelist to redux persist
andreymikhadyuk Nov 6, 2023
d3fc3ab
add logic to save feed state by common id
andreymikhadyuk Nov 6, 2023
ec8b0c1
change state reconciler of redux-persist to auto-merge level 2
andreymikhadyuk Nov 6, 2023
6ca47d9
add logic to set cached feed state for active common
andreymikhadyuk Nov 6, 2023
a1d1590
reset global data on user change
andreymikhadyuk Nov 6, 2023
3d3f084
remove wrong feed items reset
andreymikhadyuk Nov 7, 2023
272d0ea
fix sidenav content projects fetch
andreymikhadyuk Nov 7, 2023
fb75117
deserialize feed item related data from cache
andreymikhadyuk Nov 7, 2023
905fb52
create inbox transform for dehydration of persisted data
andreymikhadyuk Nov 7, 2023
9e1c9da
move checkIsSynchronizedDate to utils folder
andreymikhadyuk Nov 7, 2023
2d798b6
cache only 30 first inbox items
andreymikhadyuk Nov 7, 2023
dc7922e
cache only first 30 feed items
andreymikhadyuk Nov 7, 2023
1637270
add updating of the existing caches inbox items
andreymikhadyuk Nov 7, 2023
0d249b1
fix middle inbox items fetch
andreymikhadyuk Nov 7, 2023
1161230
add unfollowed items removal
andreymikhadyuk Nov 7, 2023
67e8d5e
add subscription to common member log
andreymikhadyuk Nov 9, 2023
ab5ebdb
Merge branch 'dev' into feature/CW-2288-inbox-feed-caching
andreymikhadyuk Nov 9, 2023
57c2a54
revert subscription log
andreymikhadyuk Nov 9, 2023
aca420c
fix wrong useEffect placement
andreymikhadyuk Nov 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"react-virtualized": "^9.22.3",
"react-zoom-pan-pinch": "^3.2.0",
"redux": "^4.0.4",
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3",
"reselect": "^4.0.0",
"slate": "^0.94.1",
Expand Down
7 changes: 5 additions & 2 deletions src/pages/App/AppWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React, { FC } from "react";
import { Provider } from "react-redux";
import { store } from "@/shared/appConfig";
import { PersistGate } from "redux-persist/integration/react";
import { store, persistor } from "@/shared/appConfig";
import { NotificationProvider } from "./providers";

const AppWrapper: FC = ({ children }) => (
<Provider store={store}>
<NotificationProvider>{children}</NotificationProvider>
<PersistGate loading={null} persistor={persistor}>
<NotificationProvider>{children}</NotificationProvider>
</PersistGate>
</Provider>
);

Expand Down
20 changes: 18 additions & 2 deletions src/pages/Auth/store/saga.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import { getProvider } from "@/shared/utils/authProvider";
import { getFundingRequestNotification } from "@/shared/utils/notifications";
import {
cacheActions,
commonActions,
commonLayoutActions,
inboxActions,
multipleSpacesLayoutActions,
} from "@/store/states";
import {
Expand Down Expand Up @@ -301,6 +303,16 @@ const updateUserData = async (user: User): Promise<User> => {
});
};

const resetGlobalData = (fullReset: boolean) => {
if (fullReset) {
store.dispatch(multipleSpacesLayoutActions.resetMultipleSpacesLayout());
store.dispatch(commonLayoutActions.clearData());
}
store.dispatch(inboxActions.resetInbox());
store.dispatch(cacheActions.resetFeedStates());
store.dispatch(commonActions.resetCommon());
};

function* socialLoginSaga({
payload,
}: ReturnType<typeof actions.socialLogin.request>) {
Expand Down Expand Up @@ -465,8 +477,6 @@ function* logOut() {
window.ReactNativeWebView.postMessage(WebviewActions.logout);
}

yield put(multipleSpacesLayoutActions.resetMultipleSpacesLayout());
yield put(commonLayoutActions.clearData());
history.push(ROUTE_PATHS.HOME);
yield true;
}
Expand Down Expand Up @@ -567,6 +577,12 @@ function* authSagas() {

firebase.auth().onAuthStateChanged(async (res) => {
try {
const { user: userInStore } = store.getState().auth;

if (userInStore?.uid !== res?.uid) {
resetGlobalData(!res);
}

store.dispatch(
actions.setAuthProvider(
getAuthProviderFromProviderData(res?.providerData),
Expand Down
13 changes: 12 additions & 1 deletion src/pages/commonFeed/CommonFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
getCommonPageAboutTabPath,
} from "@/shared/utils";
import {
cacheActions,
commonActions,
commonLayoutActions,
selectCommonAction,
Expand Down Expand Up @@ -162,7 +163,11 @@ const CommonFeedComponent: FC<CommonFeedProps> = (props) => {
hasMore: hasMoreCommonFeedItems,
fetch: fetchCommonFeedItems,
batchNumber,
} = useCommonFeedItems(commonId, commonFeedItemIdsForNotListening);
} = useCommonFeedItems(
commonId,
commonFeedItemIdsForNotListening,
sharedFeedItemId,
);

const {
isModalOpen: isCommonJoinModalOpen,
Expand Down Expand Up @@ -330,7 +335,13 @@ const CommonFeedComponent: FC<CommonFeedProps> = (props) => {
useEffect(() => {
fetchData();

const interval = setInterval(() => {
dispatch(cacheActions.copyFeedStateByCommonId(commonId));
}, 5000);

return () => {
clearInterval(interval);
dispatch(cacheActions.copyFeedStateByCommonId(commonId));
dispatch(commonActions.resetCommon());
};
}, [commonId]);
Expand Down
4 changes: 0 additions & 4 deletions src/pages/inbox/BaseInbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,6 @@ const InboxPage: FC<InboxPageProps> = (props) => {

useEffect(() => {
fetchData();

return () => {
dispatch(inboxActions.resetInbox());
};
}, [userId]);

useEffect(() => {
Expand Down
4 changes: 2 additions & 2 deletions src/shared/appConfig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import configureStore from "@/store";
import history from "./history";

const { store } = configureStore(history);
const { store, persistor } = configureStore(history);

export { history, store };
export { history, store, persistor };
3 changes: 2 additions & 1 deletion src/shared/hooks/useCases/useCommonFeedItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface Return
export const useCommonFeedItems = (
commonId: string,
idsForNotListening?: string[],
sharedFeedItemId?: string | null,
): Return => {
const dispatch = useDispatch();
const feedItems = useSelector(selectFeedItems);
Expand All @@ -20,6 +21,7 @@ export const useCommonFeedItems = (
dispatch(
commonActions.getFeedItems.request({
commonId,
sharedFeedItemId,
feedItemId,
limit: 15,
}),
Expand Down Expand Up @@ -67,7 +69,6 @@ export const useCommonFeedItems = (
dispatch(
commonActions.getFeedItems.cancel("Cancel feed items fetch on unmount"),
);
dispatch(commonActions.resetFeedItems());
};
}, []);

Expand Down
3 changes: 3 additions & 0 deletions src/shared/interfaces/SynchronizedDate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ export interface SynchronizedDate {
_seconds: number;
_nanoseconds: number;
}

export const checkIsSynchronizedDate = (date: any): date is SynchronizedDate =>
andreymikhadyuk marked this conversation as resolved.
Show resolved Hide resolved
Boolean(date && date._seconds);
43 changes: 43 additions & 0 deletions src/shared/interfaces/feedLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
CommonFeed,
FeedItemFollowWithMetadata,
} from "@/shared/models";
import { convertObjectDatesToFirestoreTimestamps } from "@/shared/utils";

export interface FeedLayoutRef {
setExpandedFeedItemId: (feedItemId: string | null) => void;
Expand Down Expand Up @@ -67,3 +68,45 @@ export type FeedLayoutItemChangeDataWithType = FeedLayoutItemChangeData &
commonId: string;
}
);

export const deserializeFeedItemFollowLayoutItem = <
T extends FeedItemFollowLayoutItem | FeedItemFollowLayoutItemWithFollowData,
>(
item: T,
): T => ({
...item,
feedItem: convertObjectDatesToFirestoreTimestamps<CommonFeed>(item.feedItem),
feedItemFollowWithMetadata: item.feedItemFollowWithMetadata && {
...convertObjectDatesToFirestoreTimestamps<FeedItemFollowWithMetadata>(
item.feedItemFollowWithMetadata,
["lastSeen", "lastActivity"],
),
feedItem: convertObjectDatesToFirestoreTimestamps<CommonFeed>(
item.feedItemFollowWithMetadata.feedItem,
),
},
});

export const deserializeChatChannelLayoutItem = (
item: ChatChannelLayoutItem,
): ChatChannelLayoutItem => ({
...item,
chatChannel: convertObjectDatesToFirestoreTimestamps<ChatChannel>(
item.chatChannel,
["lastMessage.createdAt"],
),
});

export const deserializeFeedLayoutItem = (
item: FeedLayoutItem,
): FeedLayoutItem =>
checkIsChatChannelLayoutItem(item)
? deserializeChatChannelLayoutItem(item)
: deserializeFeedItemFollowLayoutItem(item);

export const deserializeFeedLayoutItemWithFollowData = (
item: FeedLayoutItemWithFollowData,
): FeedLayoutItemWithFollowData =>
checkIsChatChannelLayoutItem(item)
? deserializeChatChannelLayoutItem(item)
: deserializeFeedItemFollowLayoutItem(item);
Original file line number Diff line number Diff line change
Expand Up @@ -104,22 +104,16 @@ export const useProjectsData = (): Return => {
}, [isAuthenticated]);

useEffect(() => {
if (areCommonsLoading) {
return;
}
if (!areCommonsFetched) {
dispatch(commonLayoutActions.getCommons.request(activeItemId));
}
}, [areCommonsLoading, areCommonsFetched]);
}, [areCommonsFetched]);

useEffect(() => {
if (areProjectsLoading || !currentCommonId) {
return;
}
if (!areProjectsFetched) {
if (currentCommonId && !areProjectsFetched) {
dispatch(commonLayoutActions.getProjects.request(currentCommonId));
}
}, [areProjectsLoading, areProjectsFetched, currentCommonId]);
}, [areProjectsFetched, currentCommonId]);

useEffect(() => {
if (
Expand Down
12 changes: 7 additions & 5 deletions src/shared/utils/convertDatesToFirestoreTimestamps.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import firebase from "firebase";
import { get, set } from "lodash";
import { SynchronizedDate } from "@/shared/interfaces";
import { checkIsSynchronizedDate, SynchronizedDate } from "@/shared/interfaces";
import { Timestamp } from "@/shared/models";

export const convertToTimestamp = (
date: SynchronizedDate,
): firebase.firestore.Timestamp =>
new firebase.firestore.Timestamp(date._seconds, date._nanoseconds);
date: SynchronizedDate | Timestamp,
): Timestamp =>
checkIsSynchronizedDate(date)
? new Timestamp(date._seconds, date._nanoseconds)
: new Timestamp(date.seconds, date.nanoseconds);

const convertDateInObject = (
data: Record<string, unknown>,
Expand Down
16 changes: 16 additions & 0 deletions src/store/states/cache/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
User,
} from "@/shared/models";
import { CacheActionType } from "./constants";
import { FeedState } from "./types";

export const getUserStateById = createAsyncAction(
CacheActionType.GET_USER_STATE_BY_ID,
Expand Down Expand Up @@ -131,6 +132,21 @@ export const updateProposalStateById = createStandardAction(
state: LoadingState<Proposal | null>;
}>();

export const copyFeedStateByCommonId = createStandardAction(
CacheActionType.COPY_FEED_STATE_BY_COMMON_ID,
)<string>();

export const updateFeedStateByCommonId = createStandardAction(
CacheActionType.UPDATE_FEED_STATE_BY_COMMON_ID,
)<{
commonId: string;
state: FeedState;
}>();

export const resetFeedStates = createStandardAction(
CacheActionType.RESET_FEED_STATES,
)();

export const getFeedItemUserMetadata = createAsyncAction(
CacheActionType.GET_FEED_ITEM_USER_METADATA,
CacheActionType.GET_FEED_ITEM_USER_METADATA_SUCCESS,
Expand Down
4 changes: 4 additions & 0 deletions src/store/states/cache/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export enum CacheActionType {

UPDATE_PROPOSAL_STATE_BY_ID = "@CACHE/UPDATE_PROPOSAL_STATE_BY_ID",

COPY_FEED_STATE_BY_COMMON_ID = "@CACHE/COPY_FEED_STATE_BY_COMMON_ID",
UPDATE_FEED_STATE_BY_COMMON_ID = "@CACHE/UPDATE_FEED_STATE_BY_COMMON_ID",
RESET_FEED_STATES = "@CACHE/RESET_FEED_STATES",

GET_FEED_ITEM_USER_METADATA = "@CACHE/GET_FEED_ITEM_USER_METADATA",
GET_FEED_ITEM_USER_METADATA_SUCCESS = "@CACHE/GET_FEED_ITEM_USER_METADATA_SUCCESS",
GET_FEED_ITEM_USER_METADATA_FAILURE = "@CACHE/GET_FEED_ITEM_USER_METADATA_FAILURE",
Expand Down
13 changes: 13 additions & 0 deletions src/store/states/cache/reducer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const initialState: CacheState = {
discussionStates: {},
discussionMessagesStates: {},
proposalStates: {},
feedByCommonIdStates: {},
feedItemUserMetadataStates: {},
chatChannelUserStatusStates: {},
};
Expand Down Expand Up @@ -97,6 +98,18 @@ export const reducer = createReducer<CacheState, Action>(initialState)
nextState.proposalStates[proposalId] = { ...state };
}),
)
.handleAction(actions.updateFeedStateByCommonId, (state, { payload }) =>
produce(state, (nextState) => {
const { commonId, state } = payload;

nextState.feedByCommonIdStates[commonId] = { ...state };
}),
)
.handleAction(actions.resetFeedStates, (state) =>
produce(state, (nextState) => {
nextState.feedByCommonIdStates = {};
}),
)
.handleAction(actions.updateFeedItemUserMetadata, (state, { payload }) =>
produce(state, (nextState) => {
const { commonId, userId, feedObjectId, state } = payload;
Expand Down
19 changes: 19 additions & 0 deletions src/store/states/cache/saga/copyFeedStateByCommonId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { put, select } from "redux-saga/effects";
import { selectCommonState, CommonState } from "../../common";
import * as actions from "../actions";

export function* copyFeedStateByCommonId({
payload: commonId,
}: ReturnType<typeof actions.copyFeedStateByCommonId>) {
const commonState = (yield select(selectCommonState)) as CommonState;
yield put(
actions.updateFeedStateByCommonId({
commonId,
state: {
feedItems: commonState.feedItems,
pinnedFeedItems: commonState.pinnedFeedItems,
sharedFeedItem: commonState.sharedFeedItem,
},
}),
);
}
3 changes: 3 additions & 0 deletions src/store/states/cache/saga/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { takeLatest } from "redux-saga/effects";
import { getFeedItemUserMetadataKey } from "@/shared/constants/getFeedItemUserMetadataKey";
import { takeLeadingByIdentifier } from "@/shared/utils/saga";
import * as actions from "../actions";
import { copyFeedStateByCommonId } from "./copyFeedStateByCommonId";
import { getDiscussionStateById } from "./getDiscussionStateById";
import { getFeedItemUserMetadataState } from "./getFeedItemUserMetadataState";
import { getGovernanceStateByCommonId } from "./getGovernanceStateByCommonId";
Expand Down Expand Up @@ -33,4 +35,5 @@ export function* mainSaga() {
({ payload: { payload } }) => getFeedItemUserMetadataKey(payload),
getFeedItemUserMetadataState,
);
yield takeLatest(actions.copyFeedStateByCommonId, copyFeedStateByCommonId);
}
4 changes: 4 additions & 0 deletions src/store/states/cache/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export const selectDiscussionMessagesStateByDiscussionId =
(discussionId: string) => (state: AppState) =>
state.cache.discussionMessagesStates[discussionId] || null;

export const selectFeedStateByCommonId =
(commonId: string) => (state: AppState) =>
state.cache.feedByCommonIdStates[commonId] || null;

export const selectFeedItemUserMetadata =
(info: { commonId: string; userId: string; feedObjectId: string }) =>
(state: AppState) =>
Expand Down
7 changes: 7 additions & 0 deletions src/store/states/cache/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import {
Proposal,
User,
} from "@/shared/models";
import { CommonState } from "../common";

export type FeedState = Pick<
CommonState,
"feedItems" | "pinnedFeedItems" | "sharedFeedItem"
>;

export interface CacheState {
userStates: Record<string, LoadingState<User | null>>;
Expand All @@ -18,6 +24,7 @@ export interface CacheState {
string,
LoadingState<DiscussionMessage[] | null>
>;
feedByCommonIdStates: Record<string, FeedState>;
// key: {commonId}_{userId}_{feedObjectId}
feedItemUserMetadataStates: Record<
string,
Expand Down
Loading
Loading