Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
db27133
feat: support ad post
sshanzel Jun 23, 2025
9ebc493
feat: context to avoid prop drilling
sshanzel Jun 23, 2025
2d5561d
feat: boosted label on card
sshanzel Jun 23, 2025
25441c6
feat: ads modal dashboard integration
sshanzel Jun 23, 2025
4bd2ddb
feat: post boost mutations modal
sshanzel Jun 23, 2025
e314ab8
fix: min max default value and max edge case
sshanzel Jun 24, 2025
378b8a0
feat: boosted list view
sshanzel Jun 24, 2025
d1909dd
refactor: import state
sshanzel Jun 24, 2025
786c6e3
fix: weird svg bug
sshanzel Jun 24, 2025
eca98d4
feat: boost post modal actions
sshanzel Jun 24, 2025
d289873
Merge branch 'MI-888' into MI-888-ad
sshanzel Jun 24, 2025
9738ee7
fix: success modal ui
sshanzel Jun 24, 2025
20a239b
fix: dependency issue and campaign id
sshanzel Jun 25, 2025
c8ac16c
fix: options menu management
sshanzel Jun 25, 2025
cb24346
fix: missing engagements property
sshanzel Jun 25, 2025
68a4807
fix: usage of ref
sshanzel Jun 25, 2025
b813165
feat: common hook for when transaction errors
sshanzel Jun 25, 2025
6efe2dd
Merge branch 'MI-888' into MI-888-ad
sshanzel Jun 27, 2025
e5ba7cf
chore: delete unused file
sshanzel Jun 27, 2025
968ccb9
refactor: upper level context wrapiing
sshanzel Jun 27, 2025
8140f12
Merge branch 'MI-888' into MI-888-ad
sshanzel Jun 27, 2025
26f5c71
refactor: usage of context util
sshanzel Jun 27, 2025
5f65bbb
refactor: fetch campaign modals
sshanzel Jun 27, 2025
f3c0422
chore: remove dummy
sshanzel Jun 27, 2025
720efbd
revert: createContextProvider to createContext
sshanzel Jun 30, 2025
3885bbb
refactor: unnecessary check
sshanzel Jun 30, 2025
c980dc8
fix: estimated reach query
sshanzel Jun 30, 2025
b1e9987
Merge branch 'MI-888' into MI-888-ad
sshanzel Jul 1, 2025
1949281
fix: icons
sshanzel Jul 1, 2025
c401160
fix: status and queries
sshanzel Jul 1, 2025
e30be3b
refactor: feed context to use partial post for future proofing
sshanzel Jul 1, 2025
409ebed
fix: status mapping
sshanzel Jul 1, 2025
4ca0f6c
fix: build
sshanzel Jul 1, 2025
790de2e
fix: canceling a post boost
sshanzel Jul 1, 2025
b5ae7ef
fix: canceled process flow
sshanzel Jul 1, 2025
77181b0
fix: copy
sshanzel Jul 1, 2025
2386974
fix: stale state management
sshanzel Jul 1, 2025
1ff2b10
fix: button flicker
sshanzel Jul 1, 2025
e9b1d95
fix: loading state
sshanzel Jul 1, 2025
d575953
fix: test
sshanzel Jul 1, 2025
c975da2
Revert "fix: test"
sshanzel Jul 1, 2025
fb5631e
fix: tests
sshanzel Jul 2, 2025
975342e
fix: pr comments
sshanzel Jul 2, 2025
54849ab
refactor: unused property
sshanzel Jul 2, 2025
803cac7
refactor: better naming
sshanzel Jul 2, 2025
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
60 changes: 34 additions & 26 deletions packages/shared/src/components/Feed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ import { useFeedContentPreferenceMutationSubscription } from './feeds/useFeedCon
import { useFeedBookmarkPost } from '../hooks/bookmark/useFeedBookmarkPost';
import type { AdActions } from '../lib/ads';
import usePlusEntry from '../hooks/usePlusEntry';
import { FeedItemType } from './cards/common/common';
import { FeedCardContext } from '../features/posts/FeedCardContext';

const FeedErrorScreen = dynamic(
() => import(/* webpackChunkName: "feedErrorScreen" */ './FeedErrorScreen'),
Expand Down Expand Up @@ -432,33 +434,39 @@ export default function Feed<T>({
) : (
<>
{items.map((item, index) => (
<FeedItemComponent
item={item}
index={index}
row={calculateRow(index, virtualizedNumCards)}
column={calculateColumn(index, virtualizedNumCards)}
columns={virtualizedNumCards}
<FeedCardContext.Provider
key={getFeedItemKey(item, index)}
openNewTab={openNewTab}
postMenuIndex={postMenuIndex}
showCommentPopupId={showCommentPopupId}
setShowCommentPopupId={setShowCommentPopupId}
isSendingComment={isSendingComment}
comment={comment}
user={user}
feedName={feedName}
ranking={ranking}
toggleBookmark={toggleBookmark}
toggleUpvote={toggleUpvote}
toggleDownvote={toggleDownvote}
onPostClick={onPostCardClick}
onShare={onShareClick}
onMenuClick={onMenuClick}
onCopyLinkClick={onCopyLinkClickLogged}
onCommentClick={onCommentClick}
onAdAction={onAdAction}
onReadArticleClick={onReadArticleClick}
/>
value={{
isBoostedAdPost: item.type === FeedItemType.Ad && !!item.post,
}}
>
<FeedItemComponent
item={item}
index={index}
row={calculateRow(index, virtualizedNumCards)}
column={calculateColumn(index, virtualizedNumCards)}
columns={virtualizedNumCards}
openNewTab={openNewTab}
postMenuIndex={postMenuIndex}
showCommentPopupId={showCommentPopupId}
setShowCommentPopupId={setShowCommentPopupId}
isSendingComment={isSendingComment}
comment={comment}
user={user}
feedName={feedName}
ranking={ranking}
toggleBookmark={toggleBookmark}
toggleUpvote={toggleUpvote}
toggleDownvote={toggleDownvote}
onPostClick={onPostCardClick}
onShare={onShareClick}
onMenuClick={onMenuClick}
onCopyLinkClick={onCopyLinkClickLogged}
onCommentClick={onCommentClick}
onAdAction={onAdAction}
onReadArticleClick={onReadArticleClick}
/>
</FeedCardContext.Provider>
))}
{!isFetching && !isInitialLoading && !isHorizontal && (
<InfiniteScrollScreenOffset ref={infiniteScrollRef} />
Expand Down
162 changes: 83 additions & 79 deletions packages/shared/src/components/FeedItemComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,86 +197,90 @@ export default function FeedItemComponent({
postType: (item as PostItem).post?.type,
});

switch (item.type) {
case FeedItemType.Post: {
if (
!!item.post.pinnedAt &&
item.post.source?.currentMember?.flags?.collapsePinnedPosts
) {
return null;
}

return (
<PostTag
enableSourceHeader={
feedName !== 'squad' && item.post.source?.type === 'squad'
}
ref={inViewRef}
post={{
...item.post,
}}
data-testid="postItem"
onUpvoteClick={(post, origin = Origin.Feed) => {
toggleUpvote({
payload: post,
origin,
opts: {
columns,
column,
row,
},
});
}}
onDownvoteClick={(post, origin = Origin.Feed) => {
toggleDownvote({
payload: post,
origin,
opts: {
columns,
column,
row,
},
});
}}
onPostClick={(post) => onPostClick(post, index, row, column)}
onPostAuxClick={(post) => onPostClick(post, index, row, column, true)}
onReadArticleClick={() =>
onReadArticleClick(item.post, index, row, column)
}
onShare={(post) => onShare(post, row, column)}
onBookmarkClick={(post, origin = Origin.Feed) => {
toggleBookmark({
post,
origin,
opts: {
columns,
column,
row,
},
});
}}
openNewTab={openNewTab}
enableMenu={!!user}
onMenuClick={(event) => onMenuClick(event, index, row, column)}
onCopyLinkClick={(event, post) =>
onCopyLinkClick(event, post, index, row, column)
}
menuOpened={postMenuIndex === index}
onCommentClick={(post) => onCommentClick(post, index, row, column)}
eagerLoadImage={row === 0 && column === 0}
>
{showCommentPopupId === item.post.id && (
<CommentPopup
onClose={() => setShowCommentPopupId(null)}
onSubmit={(content) =>
comment({ post: item.post, content, row, column, columns })
}
loading={isSendingComment}
/>
)}
</PostTag>
);
if (
item.type === FeedItemType.Post ||
(item.type === FeedItemType.Ad && item.post)
) {
if (
!!item.post.pinnedAt &&
item.post.source?.currentMember?.flags?.collapsePinnedPosts
) {
return null;
}

return (
<PostTag
enableSourceHeader={
feedName !== 'squad' && item.post.source?.type === 'squad'
}
ref={inViewRef}
post={{
...item.post,
}}
data-testid="postItem"
onUpvoteClick={(post, origin = Origin.Feed) => {
toggleUpvote({
payload: post,
origin,
opts: {
columns,
column,
row,
},
});
}}
onDownvoteClick={(post, origin = Origin.Feed) => {
toggleDownvote({
payload: post,
origin,
opts: {
columns,
column,
row,
},
});
}}
onPostClick={(post) => onPostClick(post, index, row, column)}
onPostAuxClick={(post) => onPostClick(post, index, row, column, true)}
onReadArticleClick={() =>
onReadArticleClick(item.post, index, row, column)
}
onShare={(post) => onShare(post, row, column)}
onBookmarkClick={(post, origin = Origin.Feed) => {
toggleBookmark({
post,
origin,
opts: {
columns,
column,
row,
},
});
}}
openNewTab={openNewTab}
enableMenu={!!user}
onMenuClick={(event) => onMenuClick(event, index, row, column)}
onCopyLinkClick={(event, post) =>
onCopyLinkClick(event, post, index, row, column)
}
menuOpened={postMenuIndex === index}
onCommentClick={(post) => onCommentClick(post, index, row, column)}
eagerLoadImage={row === 0 && column === 0}
>
{showCommentPopupId === item.post.id && (
<CommentPopup
onClose={() => setShowCommentPopupId(null)}
onSubmit={(content) =>
comment({ post: item.post, content, row, column, columns })
}
loading={isSendingComment}
/>
)}
</PostTag>
);
}

switch (item.type) {
case FeedItemType.Ad:
return (
<AdTag
Expand Down
4 changes: 4 additions & 0 deletions packages/shared/src/components/cards/common/PostMetadata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Separator } from './common';
import type { Post } from '../../../graphql/posts';
import { formatReadTime, TruncateText, DateFormat } from '../../utilities';
import { largeNumberFormat } from '../../../lib';
import { useFeedCardContext } from '../../../features/posts/FeedCardContext';

interface PostMetadataProps
extends Pick<Post, 'createdAt' | 'readTime' | 'numUpvotes'> {
Expand All @@ -28,6 +29,7 @@ export default function PostMetadata({
}: PostMetadataProps): ReactElement {
const timeActionContent = isVideoType ? 'watch' : 'read';
const showReadTime = isVideoType ? Number.isInteger(readTime) : !!readTime;
const { isBoostedAdPost } = useFeedCardContext();

return (
<div
Expand All @@ -36,6 +38,8 @@ export default function PostMetadata({
className,
)}
>
{isBoostedAdPost && <strong>Boosted</strong>}
{isBoostedAdPost && <Separator />}
{!!description && (
<TruncateText title={description}>{description}</TruncateText>
)}
Expand Down
10 changes: 7 additions & 3 deletions packages/shared/src/components/icons/Before/filled.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion packages/shared/src/components/icons/Before/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import React from 'react';
import type { IconProps } from '../../Icon';
import Icon from '../../Icon';
import FilledIcon from './filled.svg';
import OutlinedIcon from './outlined.svg';

export const BeforeIcon = (props: IconProps): ReactElement => (
<Icon {...props} IconPrimary={FilledIcon} IconSecondary={FilledIcon} />
<Icon {...props} IconPrimary={OutlinedIcon} IconSecondary={FilledIcon} />
);
Loading