Skip to content

Commit

Permalink
Merge pull request #2360 from daostack/feature/CW-2358-last-visited-c…
Browse files Browse the repository at this point in the history
…ommon

Remember last visited common and use it #2358
  • Loading branch information
andreymikhadyuk authored Nov 29, 2023
2 parents 63a8cef + bd9b723 commit 30edd7d
Show file tree
Hide file tree
Showing 22 changed files with 236 additions and 122 deletions.
55 changes: 25 additions & 30 deletions src/pages/commonFeed/CommonFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import {
} from "@/shared/constants";
import { useRoutesContext } from "@/shared/contexts";
import { useAuthorizedModal, useQueryParams } from "@/shared/hooks";
import { useCommonFeedItems, useUserCommonIds } from "@/shared/hooks/useCases";
import {
useCommonFeedItems,
useLastVisitedCommon,
useUserCommonIds,
} from "@/shared/hooks/useCases";
import { useCommonPinnedFeedItems } from "@/shared/hooks/useCases/useCommonPinnedFeedItems";
import { SidebarIcon } from "@/shared/icons";
import {
Expand Down Expand Up @@ -114,6 +118,7 @@ const CommonFeedComponent: FC<CommonFeedProps> = (props) => {
fetched: isCommonDataFetched,
fetchCommonData,
} = useCommonData(userId);
const { updateLastVisitedCommon } = useLastVisitedCommon(userId);
const parentCommonId = commonData?.common.directParent?.commonId;
const anotherCommonId =
userCommonIds[0] === commonId ? userCommonIds[1] : userCommonIds[0];
Expand Down Expand Up @@ -414,38 +419,28 @@ const CommonFeedComponent: FC<CommonFeedProps> = (props) => {
}, [rootCommonMember?.id]);

useEffect(() => {
return () => {
const updateLastVisited = () => {
const common = stateRef.current?.data?.common;
const rootCommon = stateRef.current?.data?.rootCommon;

dispatch(
commonLayoutActions.setLastCommonFromFeed({
id: commonId,
data: common
? {
name: common.name,
image: common.image,
isProject: checkIsProject(common),
memberCount: common.memberCount,
rootCommon: common.rootCommonId
? {
id: common.rootCommonId,
data: rootCommon
? {
name: rootCommon.name,
image: rootCommon.image,
isProject: false,
memberCount: rootCommon.memberCount,
}
: null,
}
: null,
}
: null,
}),
);
updateLastVisitedCommon({
id: commonId,
data: common
? {
name: common.name,
image: common.image,
isProject: checkIsProject(common),
memberCount: common.memberCount,
}
: null,
});
};
}, [commonId]);

updateLastVisited();

return () => {
updateLastVisited();
};
}, [updateLastVisitedCommon, commonId]);

if (!isDataFetched) {
const headerEl = renderLoadingHeader ? (
Expand Down
13 changes: 8 additions & 5 deletions src/pages/commonFeed/CommonFeedPage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { FC, useEffect, useMemo } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useParams } from "react-router-dom";
import { selectUser } from "@/pages/Auth/store/selectors";
import { InboxItemType } from "@/shared/constants";
import { MainRoutesProvider } from "@/shared/contexts";
import { useLastVisitedCommon } from "@/shared/hooks/useCases";
import { MultipleSpacesLayoutPageContent } from "@/shared/layouts";
import {
multipleSpacesLayoutActions,
selectCommonLayoutLastCommonFromFeed,
selectMultipleSpacesLayoutMainWidth,
} from "@/store/states";
import BaseCommonFeedPage, {
Expand Down Expand Up @@ -59,7 +60,9 @@ const CommonFeedPage: FC = () => {
const { id: commonId } = useParams<CommonFeedPageRouterParams>();
const dispatch = useDispatch();
const layoutMainWidth = useSelector(selectMultipleSpacesLayoutMainWidth);
const lastCommonFromFeed = useSelector(selectCommonLayoutLastCommonFromFeed);
const user = useSelector(selectUser());
const userId = user?.uid;
const { lastVisitedCommon } = useLastVisitedCommon(userId);
const onActiveItemDataChange = useActiveItemDataChange();
const feedLayoutSettings = useMemo<FeedLayoutSettings>(
() => ({
Expand All @@ -68,13 +71,13 @@ const CommonFeedPage: FC = () => {
}),
[layoutMainWidth],
);
const lastCommonFromFeedData = lastCommonFromFeed?.data;
const lastCommonFromFeedData = lastVisitedCommon?.data;

const renderLoadingHeader = lastCommonFromFeedData
? () => (
<HeaderContentWrapper className={styles.headerContentWrapper}>
<HeaderCommonContent
commonId={lastCommonFromFeed.id}
commonId={lastVisitedCommon.id}
commonName={lastCommonFromFeedData.name}
commonImage={lastCommonFromFeedData.image}
isProject={lastCommonFromFeedData.isProject}
Expand All @@ -95,7 +98,7 @@ const CommonFeedPage: FC = () => {

useEffect(() => {
return () => {
dispatch(multipleSpacesLayoutActions.moveBreadcrumbsToPrevious());
dispatch(multipleSpacesLayoutActions.clearBreadcrumbs());
};
}, []);

Expand Down
59 changes: 59 additions & 0 deletions src/services/UserActivity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { UnsubscribeFunction } from "@/shared/interfaces";
import { Collection, UserActivity } from "@/shared/models";
import { firestoreDataConverter } from "@/shared/utils";
import firebase, { isFirestoreCacheError } from "@/shared/utils/firebase";

const userActivityConverter = firestoreDataConverter<UserActivity>();

class UserActivityService {
private getUsersActivityCollection = () =>
firebase
.firestore()
.collection(Collection.UsersActivity)
.withConverter(userActivityConverter);

public getUserActivity = async (
userId: string,
cached = false,
): Promise<UserActivity | null> => {
try {
const snapshot = await this.getUsersActivityCollection()
.doc(userId)
.get({ source: cached ? "cache" : "default" });

return snapshot?.data() || null;
} catch (error) {
if (cached && isFirestoreCacheError(error)) {
return this.getUserActivity(userId);
} else {
throw error;
}
}
};

public updateUserActivity = async (
userId: string,
data: Partial<UserActivity>,
): Promise<void> => {
await this.getUsersActivityCollection()
.doc(userId)
.set(data, { merge: true });
};

public subscribeToUserActivity = (
userId: string,
callback: (userActivity: UserActivity) => void,
): UnsubscribeFunction => {
const query = this.getUsersActivityCollection().doc(userId);

return query.onSnapshot((snapshot) => {
const userActivity = snapshot.data();

if (userActivity) {
callback(userActivity);
}
});
};
}

export default new UserActivityService();
1 change: 1 addition & 0 deletions src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ export { default as PayMeService } from "./PayMeService";
export { default as ProjectService } from "./Project";
export { default as ProposalService } from "./Proposal";
export { default as UserService } from "./User";
export { default as UserActivityService } from "./UserActivity";
export { default as DiscussionMessageService } from "./DiscussionMessage";
export { default as NotionService } from "./Notion";
1 change: 1 addition & 0 deletions src/shared/hooks/useCases/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export { useProposalById } from "./useProposalById";
export { useRootCommonMembershipIntro } from "./useRootCommonMembershipIntro";
export { useSubCommons } from "./useSubCommons";
export { useSupportersData } from "./useSupportersData";
export { useLastVisitedCommon } from "./useLastVisitedCommon";
export { useUserById } from "./useUserById";
export { default as useUserCards } from "./useUserCards";
export { useUserCommonIds } from "./useUserCommonIds";
Expand Down
68 changes: 68 additions & 0 deletions src/shared/hooks/useCases/useLastVisitedCommon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { useCallback, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Logger, UserActivityService } from "@/services";
import {
commonLayoutActions,
CommonLayoutState,
selectCommonLayoutLastCommonFromFeed,
} from "@/store/states";

interface Return {
lastVisitedCommon: CommonLayoutState["lastCommonFromFeed"];
updateLastVisitedCommon: (
data: CommonLayoutState["lastCommonFromFeed"],
) => void;
}

export const useLastVisitedCommon = (userId?: string): Return => {
const dispatch = useDispatch();
const lastVisitedCommon = useSelector(selectCommonLayoutLastCommonFromFeed);

const updateLastVisitedCommon = useCallback<
Return["updateLastVisitedCommon"]
>(
async (data) => {
dispatch(commonLayoutActions.setLastCommonFromFeed(data));

if (!userId || !data?.id) {
return;
}

try {
await UserActivityService.updateUserActivity(userId, {
lastVisitedCommon: data.id,
});
} catch (error) {
Logger.error(error);
}
},
[userId],
);

useEffect(() => {
if (!userId) {
return;
}

const unsubscribe = UserActivityService.subscribeToUserActivity(
userId,
(updatedUserActivity) => {
if (updatedUserActivity.lastVisitedCommon) {
dispatch(
commonLayoutActions.setLastCommonFromFeed({
id: updatedUserActivity.lastVisitedCommon,
data: null,
}),
);
}
},
);

return unsubscribe;
}, [userId]);

return {
lastVisitedCommon,
updateLastVisitedCommon,
};
};
4 changes: 2 additions & 2 deletions src/shared/icons/auth/apple.icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const AppleIcon: FC = () => {
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M22.515 11.262a5.04 5.04 0 0 1-2.011.372c-.133-.002-.183-.037-.19-.177-.109-1.318.244-2.524.88-3.66 1.086-1.94 2.738-3.137 4.885-3.664.183-.046.372-.07.572-.096.088-.012.178-.023.27-.037l.012.252c.006.122.011.238.014.353.046 2.38-1.492 5.49-4.432 6.657zm11.128 17.271.102-.296c-2.599-1.293-4.184-3.285-4.381-6.23-.196-2.944 1.148-5.118 3.509-6.764a3.764 3.764 0 0 0-.062-.091l-.01-.013c-.935-1.313-2.175-2.215-3.698-2.725a8.245 8.245 0 0 0-3.312-.415c-.756.06-1.482.272-2.195.532-.695.258-1.39.522-2.082.787-.626.24-1.249.24-1.874.004-.68-.254-1.357-.51-2.033-.77-1.285-.494-2.596-.624-3.944-.306-2.24.524-3.943 1.796-5.15 3.737-.962 1.545-1.38 3.26-1.487 5.06-.09 1.5.058 2.982.367 4.45.717 3.417 2.201 6.466 4.413 9.164.467.568.967 1.104 1.561 1.544.48.355.996.63 1.586.74.676.127 1.34.04 1.98-.174.385-.13.762-.284 1.138-.439.163-.067.327-.134.491-.199 1.503-.594 3.023-.667 4.551-.112.305.111.604.24.903.367.163.07.326.14.49.206.64.26 1.305.387 1.998.364.923-.032 1.72-.386 2.413-.973.35-.295.69-.613.981-.965 1.51-1.805 2.754-3.775 3.573-5.994.061-.163.117-.328.172-.489z"
fill={color}
/>
Expand Down
16 changes: 8 additions & 8 deletions src/shared/icons/auth/google.icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,26 @@ const GoogleIcon: FC = () => {
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M34.89 21.597c0-1.082-.097-2.122-.277-3.12H20.25v5.9h8.207c-.353 1.905-1.428 3.52-3.043 4.602v3.826h4.929c2.883-2.654 4.547-6.564 4.547-11.208z"
fill="#4285F4"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M20.25 36.5c4.117 0 7.57-1.366 10.093-3.695l-4.929-3.826c-1.365.915-3.112 1.456-5.164 1.456-3.972 0-7.334-2.683-8.533-6.287H6.622v3.95C9.132 33.084 14.29 36.5 20.25 36.5z"
fill="#34A853"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M11.717 24.148a9.167 9.167 0 0 1-.478-2.898c0-1.005.173-1.983.478-2.898v-3.95H6.622A15.244 15.244 0 0 0 5 21.25c0 2.46.59 4.79 1.622 6.849l5.095-3.951z"
fill="#FBBC05"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M20.25 12.065c2.239 0 4.25.77 5.83 2.28l4.374-4.373C27.813 7.512 24.36 6 20.25 6 14.289 6 9.131 9.417 6.622 14.401l5.095 3.951c1.2-3.604 4.561-6.287 8.533-6.287z"
fill="#EA4335"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import { useHistory } from "react-router-dom";
import classNames from "classnames";
import {
authentificated,
selectUser,
selectUserStreamsWithNotificationsAmount,
} from "@/pages/Auth/store/selectors";
import { Tab, Tabs } from "@/shared/components";
import { useRoutesContext } from "@/shared/contexts";
import { useModal } from "@/shared/hooks";
import { useUserCommonIds } from "@/shared/hooks/useCases";
import {
useLastVisitedCommon,
useUserCommonIds,
} from "@/shared/hooks/useCases";
import { Avatar2Icon, Blocks2Icon, InboxIcon } from "@/shared/icons";
import { CreateCommonPrompt } from "@/shared/layouts/MultipleSpacesLayout/components/Header/components/Navigation/components";
import { selectCommonLayoutLastCommonFromFeed } from "@/store/states";
import { LayoutTab } from "../../constants";
import { getActiveLayoutTab, getLayoutTabName } from "./utils";
import styles from "./LayoutTabs.module.scss";
Expand All @@ -34,14 +37,14 @@ const LayoutTabs: FC<LayoutTabsProps> = (props) => {
const history = useHistory();
const { getCommonPagePath, getInboxPagePath, getProfilePagePath } =
useRoutesContext();
const lastCommonIdFromFeed = useSelector(
selectCommonLayoutLastCommonFromFeed,
);
const isAuthenticated = useSelector(authentificated());
const userStreamsWithNotificationsAmount = useSelector(
selectUserStreamsWithNotificationsAmount(),
);
const user = useSelector(selectUser());
const userId = user?.uid;
const { data: userCommonIds } = useUserCommonIds();
const { lastVisitedCommon } = useLastVisitedCommon(userId);
const {
isShowing: isCreateCommonPromptOpen,
onOpen: onCreateCommonPromptOpen,
Expand Down Expand Up @@ -81,7 +84,7 @@ const LayoutTabs: FC<LayoutTabsProps> = (props) => {
} as CSSProperties;

const handleSpacesClick = () => {
const commonForRedirectId = lastCommonIdFromFeed?.id || userCommonIds[0];
const commonForRedirectId = lastVisitedCommon?.id || userCommonIds[0];

if (commonForRedirectId) {
history.push(getCommonPagePath(commonForRedirectId));
Expand Down
Loading

0 comments on commit 30edd7d

Please sign in to comment.