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

Enable follow\unfollow space #2045 #2098

Merged
merged 1 commit into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ const DiscussionFeedCard = forwardRef<FeedItemRef, DiscussionFeedCardProps>(
fetchFeedItemUserMetadata,
} = useFeedItemUserMetadata();
const { data: common } = useCommon(isHome ? commonId : "");
const feedItemFollow = useFeedItemFollow(item.id, commonId);
const feedItemFollow = useFeedItemFollow(
{ feedItemId: item.id, commonId },
{ withSubscription: true },
);
const menuItems = useMenuItems(
{
commonId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,10 @@ const ProposalFeedCard = forwardRef<FeedItemRef, ProposalFeedCardProps>(
onOpen: onShareModalOpen,
onClose: onShareModalClose,
} = useModal(false);
const feedItemFollow = useFeedItemFollow(item.id, commonId);
const feedItemFollow = useFeedItemFollow(
{ feedItemId: item.id, commonId },
{ withSubscription: true },
);
const menuItems = useMenuItems(
{
commonId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ interface FollowFeedItemButtonProps {

const FollowFeedItemButton: FC<FollowFeedItemButtonProps> = (props) => {
const { feedItemId, commonId } = props;
const { isDisabled, isFollowing, onFollowToggle } = useFeedItemFollow(
const { isDisabled, isFollowing, onFollowToggle } = useFeedItemFollow({
feedItemId,
commonId,
);
});

return (
<ButtonIcon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@
overflow: hidden;
}

.commonMainInfoWrapper {
display: flex;
align-items: center;
column-gap: 8px;
}

.commonName {
margin: 0;
font-family: PoppinsSans, sans-serif;
Expand Down
28 changes: 17 additions & 11 deletions src/pages/commonFeed/components/HeaderContent/HeaderContent.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { FC } from "react";
import { NavLink } from "react-router-dom";
import classNames from "classnames";
import { InviteFriendsButton } from "@/pages/common/components";
import { useRoutesContext } from "@/shared/contexts";
import { useCommonFollow } from "@/shared/hooks/useCases";
import { useIsTabletView } from "@/shared/hooks/viewport";
import { RightArrowThinIcon } from "@/shared/icons";
import { RightArrowThinIcon, StarIcon } from "@/shared/icons";
import {
CirclesPermissions,
Common,
Expand All @@ -13,7 +13,7 @@ import {
} from "@/shared/models";
import { CommonAvatar, TopNavigationOpenSidenavButton } from "@/shared/ui-kit";
import { checkIsProject, getPluralEnding } from "@/shared/utils";
import { NewStreamButton, ShareButton } from "./components";
import { ActionsButton, NewStreamButton } from "./components";
import styles from "./HeaderContent.module.scss";

interface HeaderContentProps {
Expand All @@ -29,7 +29,11 @@ const HeaderContent: FC<HeaderContentProps> = (props) => {
props;
const { getCommonPageAboutTabPath } = useRoutesContext();
const isMobileVersion = useIsTabletView();
const commonFollow = useCommonFollow(common.id, commonMember);
const isProject = checkIsProject(common);
const showFollowIcon = commonFollow.isFollowInProgress
? !commonMember?.isFollowing
: commonMember?.isFollowing;

return (
<div className={classNames(styles.container, className)}>
Expand All @@ -52,7 +56,10 @@ const HeaderContent: FC<HeaderContentProps> = (props) => {
/>

<div className={styles.commonInfoWrapper}>
<h1 className={styles.commonName}>{common.name}</h1>
<div className={styles.commonMainInfoWrapper}>
<h1 className={styles.commonName}>{common.name}</h1>
{showFollowIcon && <StarIcon stroke="currentColor" />}
</div>
<p className={styles.commonMembersAmount}>
{commonMembersAmount} member{getPluralEnding(commonMembersAmount)}
</p>
Expand All @@ -66,13 +73,12 @@ const HeaderContent: FC<HeaderContentProps> = (props) => {
governance={governance}
isMobileVersion={isMobileVersion}
/>
{!isMobileVersion && (
<InviteFriendsButton
isMobileVersion={isMobileVersion}
common={common}
TriggerComponent={ShareButton}
/>
)}
<ActionsButton
common={common}
commonMember={commonMember}
commonFollow={commonFollow}
isMobileVersion={isMobileVersion}
/>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { FC } from "react";
import { ShareModal } from "@/shared/components";
import { useModal } from "@/shared/hooks";
import { CommonFollowState } from "@/shared/hooks/useCases/useCommonFollow";
import { CirclesPermissions, Common, CommonMember } from "@/shared/models";
import { DesktopMenu, MenuButton } from "@/shared/ui-kit";
import { StaticLinkType, generateStaticShareLink } from "@/shared/utils";
import { useMenuItems } from "./hooks";

interface ActionsButtonProps {
common: Common;
commonMember: (CommonMember & CirclesPermissions) | null;
commonFollow: CommonFollowState;
isMobileVersion: boolean;
}

const ActionsButton: FC<ActionsButtonProps> = (props) => {
const { common, commonMember, commonFollow, isMobileVersion } = props;
const {
isShowing: isShareModalOpen,
onOpen: onShareModalOpen,
onClose: onShareModalClose,
} = useModal(false);
const items = useMenuItems(
{
common,
commonMember,
isMobileVersion,
isFollowInProgress: commonFollow.isFollowInProgress,
},
{
share: onShareModalOpen,
onFollowToggle: commonFollow.onFollowToggle,
},
);
const shareLink = generateStaticShareLink(StaticLinkType.Common, common);

return (
<>
{items.length > 0 && (
<DesktopMenu triggerEl={<MenuButton />} items={items} />
)}
<ShareModal
sourceUrl={shareLink}
isShowing={isShareModalOpen}
onClose={onShareModalClose}
/>
</>
);
};

export default ActionsButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./useMenuItems";
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from "react";
import { CommonFollowState } from "@/shared/hooks/useCases";
import { FollowIcon, Share3Icon, UnfollowIcon } from "@/shared/icons";
import { MenuItem as Item } from "@/shared/interfaces";
import { CommonFeedMenuItem } from "../../../../../constants";
import {
Options as GetAllowedItemsOptions,
getAllowedItems,
} from "../../../../../utils";

interface Actions {
share: () => void;
onFollowToggle: CommonFollowState["onFollowToggle"];
}

export const useMenuItems = (
options: GetAllowedItemsOptions,
actions: Actions,
): Item[] => {
const { common } = options;
const { share, onFollowToggle } = actions;

const items: Item[] = [
{
id: CommonFeedMenuItem.Share,
text: "Share",
onClick: share,
icon: <Share3Icon />,
},
{
id: CommonFeedMenuItem.Follow,
text: `Follow ${common.name}`,
onClick: () => onFollowToggle(),
icon: <FollowIcon />,
},
{
id: CommonFeedMenuItem.Mute,
text: `Unfollow ${common.name}`,
onClick: () => onFollowToggle(),
icon: <UnfollowIcon />,
},
];

return getAllowedItems(items, options);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as ActionsButton } from "./ActionsButton";
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./NewStreamButton";
export * from "./ShareButton";
export * from "./ActionsButton";
5 changes: 5 additions & 0 deletions src/pages/commonFeed/constants/commonFeedMenuItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum CommonFeedMenuItem {
Share = "share",
Follow = "follow",
Mute = "mute",
}
3 changes: 2 additions & 1 deletion src/pages/commonFeed/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const MIN_CHAT_WIDTH = 384;
export * from "./commonFeedMenuItem";
export * from "./minChatWidth";
1 change: 1 addition & 0 deletions src/pages/commonFeed/constants/minChatWidth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const MIN_CHAT_WIDTH = 384;
24 changes: 24 additions & 0 deletions src/pages/commonFeed/utils/getAllowedItems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { MenuItem as Item } from "@/shared/interfaces";
import { CirclesPermissions, Common, CommonMember } from "@/shared/models";
import { CommonFeedMenuItem } from "../constants";

export interface Options {
common: Common;
commonMember: (CommonMember & CirclesPermissions) | null;
isFollowInProgress: boolean;
isMobileVersion: boolean;
}

const MENU_ITEM_TO_CHECK_FUNCTION_MAP: Record<
CommonFeedMenuItem,
(options: Options) => boolean
> = {
[CommonFeedMenuItem.Share]: ({ isMobileVersion }) => !isMobileVersion,
[CommonFeedMenuItem.Follow]: ({ commonMember, isFollowInProgress }) =>
!isFollowInProgress && Boolean(commonMember && !commonMember.isFollowing),
[CommonFeedMenuItem.Mute]: ({ commonMember, isFollowInProgress }) =>
!isFollowInProgress && Boolean(commonMember?.isFollowing),
};

export const getAllowedItems = (items: Item[], options: Options): Item[] =>
items.filter(({ id }) => MENU_ITEM_TO_CHECK_FUNCTION_MAP[id](options));
1 change: 1 addition & 0 deletions src/pages/commonFeed/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./generateSplitViewMaxSizeGetter";
export * from "./getLastMessage";
export * from "./getAllowedItems";
13 changes: 11 additions & 2 deletions src/services/Common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { commonMembersSubCollection } from "@/pages/OldCommon/store/api";
import { store } from "@/shared/appConfig";
import {
ApiEndpoint,
DocChange,
GovernanceActions,
ProposalsTypes,
} from "@/shared/constants";
Expand Down Expand Up @@ -337,8 +338,8 @@ class CommonService {

if (docChange) {
callback(docChange.doc.data(), {
isAdded: docChange.type === "added",
isRemoved: docChange.type === "removed",
isAdded: docChange.type === DocChange.Added,
isRemoved: docChange.type === DocChange.Removed,
});
}
});
Expand Down Expand Up @@ -381,6 +382,14 @@ class CommonService {
args: { circleId, commonId, userId },
});
};

public followCommon = async (commonId: string): Promise<void> => {
await Api.post(ApiEndpoint.FollowCommon, { commonId });
};

public muteCommon = async (commonId: string): Promise<void> => {
await Api.post(ApiEndpoint.MuteCommon, { commonId });
};
}

export default new CommonService();
32 changes: 32 additions & 0 deletions src/services/FeedItemFollows.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ApiEndpoint } from "@/shared/constants";
import { DocChange } from "@/shared/constants/docChange";
import { UnsubscribeFunction } from "@/shared/interfaces";
import { FollowFeedItemPayload } from "@/shared/interfaces/api";
import {
Expand Down Expand Up @@ -36,6 +37,37 @@ class FeedItemFollowsService {
return snapshot.docs[0]?.data() || null;
};

public subscribeToUserFeedItemFollowData = (
userId: string,
feedItemId: string,
callback: (
userFeedItemFollowData: FeedItemFollow | null,
statuses: {
isAdded: boolean;
isRemoved: boolean;
isModified: boolean;
},
) => void,
): UnsubscribeFunction => {
const query = this.getFeedItemFollowsSubCollection(userId).where(
"feedItemId",
"==",
feedItemId,
);

return query.onSnapshot((snapshot) => {
const docChange = snapshot.docChanges()[0];

if (docChange) {
callback(docChange.doc.data(), {
isAdded: docChange.type === DocChange.Added,
isRemoved: docChange.type === DocChange.Removed,
isModified: docChange.type === DocChange.Modified,
});
}
});
};

public getUserFeedItemFollowDataWithMetadata = async (
userId: string,
feedItemId: string,
Expand Down
5 changes: 5 additions & 0 deletions src/shared/constants/docChange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum DocChange {
Added = "added",
Removed = "removed",
Modified = "modified",
}
2 changes: 2 additions & 0 deletions src/shared/constants/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export const ApiEndpoint = {
CreateReport: "/moderation/report",
HideContent: "/moderation/hide",
ShowContent: "/moderation/show",
FollowCommon: "/commons/follow",
MuteCommon: "/commons/mute",
LeaveCommon: "/commons/leave",
CreateSubscription: "/commons/immediate-contribution",
UpdateSubscription: "/subscriptions/update",
Expand Down
1 change: 1 addition & 0 deletions src/shared/constants/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ export * from "./viewportBreakpoint";
export * from "./currencyTypes";
export * from "./systemDiscussionMessage";
export * from "./theme";
export * from "./docChange";
1 change: 1 addition & 0 deletions src/shared/hooks/useCases/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ export { useDiscussionMessagesById } from "./useDiscussionMessagesById";
export { useUserPendingJoin } from "./useUserPendingJoin";
export { useCommonMemberWithUserInfo } from "./useCommonMemberWithUserInfo";
export { useEligibleVoters } from "./useEligibleVoters";
export * from "./useCommonFollow";
Loading
Loading