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

FE mark as unread\read functionality #2017 #2050

Merged
merged 1 commit into from
Sep 11, 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 @@ -135,6 +135,7 @@ const DiscussionFeedCard = forwardRef<FeedItemRef, DiscussionFeedCardProps>(
commonMember,
feedItemFollow,
getNonAllowedItems,
feedItemUserMetadata,
},
{
report: onReportModalOpen,
Expand Down Expand Up @@ -324,6 +325,7 @@ const DiscussionFeedCard = forwardRef<FeedItemRef, DiscussionFeedCardProps>(
isLoading={isLoading}
menuItems={menuItems}
seenOnce={feedItemUserMetadata?.seenOnce}
seen={feedItemUserMetadata?.seen}
ownerId={item.userId}
discussionPredefinedType={discussion?.predefinedType}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Trash2Icon,
UnfollowIcon,
UnpinIcon,
Message3Icon,
} from "@/shared/icons";
import { ContextMenuItem as Item, UploadFile } from "@/shared/interfaces";
import { parseStringToTextEditorValue } from "@/shared/ui-kit";
Expand All @@ -31,7 +32,13 @@ export const useMenuItems = (
actions: Actions,
): Item[] => {
const dispatch = useDispatch();
const { discussion, commonId, feedItem, feedItemFollow } = options;
const {
discussion,
commonId,
feedItem,
feedItemFollow,
feedItemUserMetadata,
} = options;
const { report, share, remove } = actions;
const allowedMenuItems = getAllowedItems({ ...options, feedItemFollow });
const items: Item[] = [
Expand Down Expand Up @@ -59,6 +66,38 @@ export const useMenuItems = (
onClick: share,
icon: <Share3Icon />,
},
{
id: FeedItemMenuItem.MarkUnread,
text: "Mark as unread",
onClick: async () => {
if (!commonId || !feedItem) {
return;
}

await CommonFeedService.markCommonFeedItemAsUnseen(
commonId,
feedItem.id,
);
},
icon: <Message3Icon />,
},
{
id: FeedItemMenuItem.MarkRead,
text: "Mark as read",
onClick: async () => {
if (!commonId || !feedItem) {
return;
}

await CommonFeedService.markCommonFeedItemAsSeen({
commonId,
feedObjectId: feedItem.id,
lastSeenId: feedItemUserMetadata?.lastSeen?.id,
type: feedItemUserMetadata?.lastSeen?.type,
});
},
icon: <Message3Icon />,
},
{
id: FeedItemMenuItem.Report,
text: "Report",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CommonFeedType } from "@/shared/models";
import { notEmpty } from "@/shared/utils/notEmpty";
import { FeedItemMenuItem, FeedItemPinAction } from "../../FeedItem/constants";
import { GetAllowedItemsOptions } from "../../FeedItem/types";
import { checkIsEditItemAllowed } from "./checkIsEditItemAllowed";
Expand Down Expand Up @@ -27,6 +28,16 @@ const MENU_ITEM_TO_CHECK_FUNCTION_MAP: Record<
!options.feedItemFollow.isDisabled && options.feedItemFollow.isFollowing
);
},
[FeedItemMenuItem.MarkUnread]: ({ feedItemUserMetadata }) => {
const { count, seen } = feedItemUserMetadata || {};

return notEmpty(count) && notEmpty(seen) && count === 0 && seen;
},
[FeedItemMenuItem.MarkRead]: ({ feedItemUserMetadata }) => {
const { count, seen } = feedItemUserMetadata || {};

return Boolean(count) || !seen;
},
};

export const getAllowedItems = (
Expand All @@ -38,6 +49,8 @@ export const getAllowedItems = (
FeedItemMenuItem.Pin,
FeedItemMenuItem.Unpin,
FeedItemMenuItem.Share,
FeedItemMenuItem.MarkUnread,
FeedItemMenuItem.MarkRead,
FeedItemMenuItem.Report,
FeedItemMenuItem.Edit,
FeedItemMenuItem.Remove,
Expand Down
3 changes: 3 additions & 0 deletions src/pages/common/components/FeedCard/FeedCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type FeedCardProps = PropsWithChildren<{
type?: CommonFeedType;
menuItems?: ContextMenuItem[];
seenOnce?: boolean;
seen?: boolean;
ownerId?: string;
discussionPredefinedType?: PredefinedTypes;
hasFiles?: boolean;
Expand Down Expand Up @@ -77,6 +78,7 @@ export const FeedCard = forwardRef<FeedCardRef, FeedCardProps>((props, ref) => {
type,
menuItems,
seenOnce,
seen,
ownerId,
discussionPredefinedType,
hasImages,
Expand Down Expand Up @@ -197,6 +199,7 @@ export const FeedCard = forwardRef<FeedCardRef, FeedCardProps>((props, ref) => {
isFollowing,
type,
seenOnce,
seen,
ownerId,
discussionPredefinedType,
hasFiles,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@
margin-left: 0.75rem;
color: $c-gray-800;
}

.unseen {
width: 1.4375rem;
border-radius: 50%;
background-color: $c-pink-primary;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import classNames from "classnames";
import { selectUser } from "@/pages/Auth/store/selectors";
import { PinIcon, StarIcon } from "@/shared/icons";
import { CommonFeedType } from "@/shared/models";
import { notEmpty } from "@/shared/utils/notEmpty";
import styles from "./FeedCardTags.module.scss";

interface FeedCardTagsProps {
unreadMessages?: number;
type?: CommonFeedType;
seenOnce?: boolean;
seen?: boolean;
ownerId?: string;
isActive: boolean;
isPinned?: boolean;
Expand All @@ -21,6 +23,7 @@ export const FeedCardTags: FC<FeedCardTagsProps> = (props) => {
unreadMessages,
type,
seenOnce,
seen,
ownerId,
isActive,
isPinned,
Expand Down Expand Up @@ -69,6 +72,9 @@ export const FeedCardTags: FC<FeedCardTagsProps> = (props) => {
{unreadMessages}
</div>
)}
{!unreadMessages && notEmpty(seen) && !seen && (
<div className={classNames(styles.tag, styles.unseen)}></div>
)}
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { FC, MouseEventHandler, useRef, useState } from "react";
import classNames from "classnames";
import { useLongPress } from "use-long-press";
import { PredefinedTypes } from "@/shared/models";
import {
checkIsTextEditorValueEmpty,
ContextMenu,
Expand Down Expand Up @@ -29,6 +28,7 @@ export const FeedItemBaseContent: FC<FeedItemBaseContentProps> = (props) => {
type,
menuItems,
seenOnce,
seen,
ownerId,
renderLeftContent,
isPinned,
Expand Down Expand Up @@ -149,6 +149,7 @@ export const FeedItemBaseContent: FC<FeedItemBaseContentProps> = (props) => {
unreadMessages={unreadMessages}
type={type}
seenOnce={seenOnce}
seen={seen}
ownerId={ownerId}
isActive={isActive}
isPinned={isPinned}
Expand Down
12 changes: 11 additions & 1 deletion src/pages/common/components/FeedItem/FeedItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { DiscussionFeedCard } from "../DiscussionFeedCard";
import { ProposalFeedCard } from "../ProposalFeedCard";
import { ProjectFeedItem } from "./components";
import { useFeedItemContext } from "./context";
import { useFeedItemCounters } from "./hooks";
import { FeedItemRef } from "./types";

interface FeedItemProps {
Expand Down Expand Up @@ -67,6 +68,8 @@ const FeedItem = forwardRef<FeedItemRef, FeedItemProps>((props, ref) => {
const { onFeedItemUpdate, getLastMessage, getNonAllowedItems, onUserSelect } =
useFeedItemContext();
useFeedItemSubscription(item.id, commonId, onFeedItemUpdate);
const { projectUnreadStreamsCount, projectUnreadMessages } =
useFeedItemCounters(item.id, commonId);

if (
shouldCheckItemVisibility &&
Expand Down Expand Up @@ -115,7 +118,14 @@ const FeedItem = forwardRef<FeedItemRef, FeedItemProps>((props, ref) => {
}

if (item.data.type === CommonFeedType.Project) {
return <ProjectFeedItem item={item} isMobileVersion={isMobileVersion} />;
return (
<ProjectFeedItem
item={item}
isMobileVersion={isMobileVersion}
unreadStreamsCount={projectUnreadStreamsCount}
unreadMessages={projectUnreadMessages}
/>
);
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,21 @@ import { OpenIcon } from "@/shared/icons";
import { CommonFeed } from "@/shared/models";
import { CommonAvatar, parseStringToTextEditorValue } from "@/shared/ui-kit";
import { checkIsProject } from "@/shared/utils";
import { useFeedItemCounters } from "../../hooks";
import styles from "./ProjectFeedItem.module.scss";

interface ProjectFeedItemProps {
item: CommonFeed;
isMobileVersion: boolean;
unreadStreamsCount?: number;
unreadMessages?: number;
}

export const ProjectFeedItem: FC<ProjectFeedItemProps> = (props) => {
const { item, isMobileVersion } = props;
const { item, isMobileVersion, unreadStreamsCount, unreadMessages } = props;
const history = useHistory();
const { getCommonPagePath } = useRoutesContext();
const { renderFeedItemBaseContent } = useFeedItemContext();
const { data: common, fetched: isCommonFetched, fetchCommon } = useCommon();
const { unreadStreamsCount, unreadMessages } = useFeedItemCounters(
item.id,
common?.directParent?.commonId,
);
const commonId = item.data.id;
const lastMessage = parseStringToTextEditorValue(
Number.isInteger(unreadStreamsCount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ export enum FeedItemMenuItem {
Remove = "remove",
Follow = "follow",
Unfollow = "unfollow",
MarkUnread = "markUnread",
MarkRead = "markRead",
}
1 change: 1 addition & 0 deletions src/pages/common/components/FeedItem/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface FeedItemBaseContentProps {
menuItems?: ContextMenuItem[];
type?: CommonFeedType;
seenOnce?: boolean;
seen?: boolean;
ownerId?: string;
commonName?: string;
renderImage?: (className?: string) => ReactNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { useCommonMember } from "@/pages/OldCommon/hooks";
import { useGovernanceByCommonId } from "@/shared/hooks/useCases";

interface Return {
unreadStreamsCount?: number;
unreadMessages?: number;
projectUnreadStreamsCount?: number;
projectUnreadMessages?: number;
}

export const useFeedItemCounters = (
Expand All @@ -28,7 +28,7 @@ export const useFeedItemCounters = (
}, [fetchGovernance, commonId]);

return {
unreadStreamsCount: streamsUnreadCountByProjectStream?.[feedItemId],
unreadMessages: unreadCountByProjectStream?.[feedItemId],
projectUnreadStreamsCount: streamsUnreadCountByProjectStream?.[feedItemId],
projectUnreadMessages: unreadCountByProjectStream?.[feedItemId],
};
};
2 changes: 2 additions & 0 deletions src/pages/common/components/FeedItem/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Discussion,
Proposal,
CommonFeedType,
CommonFeedObjectUserUnique,
} from "@/shared/models";
import { FeedItemMenuItem } from "./constants";

Expand All @@ -25,6 +26,7 @@ export interface GetAllowedItemsOptions {
commonMember?: CommonMember | null;
feedItemFollow: FeedItemFollowState;
getNonAllowedItems?: GetNonAllowedItemsOptions;
feedItemUserMetadata: CommonFeedObjectUserUnique | null;
}

export type MenuItemOptions = Omit<GetAllowedItemsOptions, "feedItemFollow">;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ const ProposalFeedCard = forwardRef<FeedItemRef, ProposalFeedCardProps>(
commonMember,
feedItemFollow,
getNonAllowedItems,
feedItemUserMetadata,
},
{
report: () => {},
Expand Down Expand Up @@ -426,6 +427,7 @@ const ProposalFeedCard = forwardRef<FeedItemRef, ProposalFeedCardProps>(
isLoading={isLoading}
type={item.data.type}
seenOnce={feedItemUserMetadata?.seenOnce}
seen={feedItemUserMetadata?.seen}
menuItems={menuItems}
ownerId={item.userId}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const FeedItemBaseContent: FC<FeedItemBaseContentProps> = (props) => {
type,
menuItems,
seenOnce,
seen,
ownerId,
commonName,
renderImage,
Expand Down Expand Up @@ -155,6 +156,7 @@ export const FeedItemBaseContent: FC<FeedItemBaseContentProps> = (props) => {
unreadMessages={unreadMessages}
type={type}
seenOnce={seenOnce}
seen={seen}
ownerId={ownerId}
isActive={isActive}
isPinned={false}
Expand Down
10 changes: 10 additions & 0 deletions src/services/CommonFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,16 @@ class CommonFeedService {
return convertObjectDatesToFirestoreTimestamps(data);
};

public markCommonFeedItemAsUnseen = (
commonId: string,
feedObjectId: string,
) => {
return Api.post(ApiEndpoint.MarkFeedObjectUnseenForUser, {
commonId,
feedObjectId,
});
};

public subscribeToCommonFeedItem = (
commonId: string,
feedItemId: string,
Expand Down
1 change: 1 addition & 0 deletions src/shared/constants/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const ApiEndpoint = {
UpdateCommon: "/commons/update",
CreateSubCommon: "/commons/subcommon/create",
MarkFeedObjectSeenForUser: "/commons/mark-feed-object-seen-for-user",
MarkFeedObjectUnseenForUser: "/commons/mark-feed-object-unseen-for-user",
AcceptRules: "/commons/accept-rules",
GetCommonFeedItems: "/commons/:commonId/feed-items",
GetCommonPinnedFeedItems: "/commons/:commonId/pinned-feed-items",
Expand Down
1 change: 1 addition & 0 deletions src/shared/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export { default as UploadIcon } from "./upload.icon";
export { default as WalletIcon } from "./wallet.icon";
export { default as MessageIcon } from "./message.icon";
export { default as Message2Icon } from "./message2.icon";
export { default as Message3Icon } from "./message3.icon";
export { default as Trash2Icon } from "./trash2.icon";
export { UnfollowIcon } from "./unfollow.icon";
export { UnpinIcon } from "./unpin.icon";
Expand Down
Loading
Loading