Skip to content

Commit

Permalink
피드 아이템 컴포넌트 확장(좋아요 버튼 합성, onClick props 추가) (#616)
Browse files Browse the repository at this point in the history
also add LikeButton component and compose on FeedPanel
  • Loading branch information
eunsukimme authored Dec 9, 2023
1 parent 0df28e7 commit 7787b9f
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 80 deletions.
6 changes: 3 additions & 3 deletions src/api/post/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ export const useInfinitePosts = (take: number, meetingId: number) => {
return { data, hasNextPage, fetchNextPage, isFetchingNextPage, isLoading };
};

export const useMutationUpdateLike = (take: number, meetingId: number, postId: number) => {
export const useMutationUpdateLike = (take: number, meetingId: number) => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: () => postLike(String(postId)),
onMutate: async () => {
mutationFn: (postId: number) => postLike(String(postId)),
onMutate: async postId => {
await queryClient.cancelQueries(['getPosts', take, meetingId]);

type Post = paths['/post/v1']['get']['responses']['200']['content']['application/json']['data'];
Expand Down
42 changes: 42 additions & 0 deletions src/components/button/LikeButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import LikeActiveIcon from '@assets/svg/like_active.svg';
import LikeDefaultIcon from '@assets/svg/like_default.svg';
import { LIKE_MAX_COUNT } from '@constants/feed';
import { styled } from 'stitches.config';

interface LikeButtonProps {
isLiked: boolean;
likeCount: number;
onClickLike: (e: React.MouseEvent<HTMLButtonElement>) => void;
}

export default function LikeButton({ isLiked, likeCount, onClickLike }: LikeButtonProps) {
const formattedLikeCount = likeCount > LIKE_MAX_COUNT ? `${LIKE_MAX_COUNT}+` : likeCount;

return (
<SLikeButton like={isLiked} onClick={onClickLike}>
{isLiked ? <LikeActiveIcon /> : <LikeDefaultIcon />}
{formattedLikeCount}
</SLikeButton>
);
}

const SLikeButton = styled('button', {
display: 'flex',
alignItems: 'center',
fontStyle: 'H5',

variants: {
like: {
true: {
color: '$red',
},
false: {
color: '$gray10',
},
},
},

'& > svg': {
mr: '$6',
},
});
75 changes: 11 additions & 64 deletions src/components/page/meetingDetail/Feed/FeedItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,10 @@ import { styled } from 'stitches.config';
// import MoreIcon from '@assets/svg/more.svg';
import { ampli } from '@/ampli';
import { useQueryGetMeeting } from '@api/meeting/hooks';
import { useMutationUpdateLike } from '@api/post/hooks';
import { UserResponse } from '@api/user';
import LikeActiveIcon from '@assets/svg/like_active.svg';
import LikeDefaultIcon from '@assets/svg/like_default.svg';
import ProfileDefaultIcon from '@assets/svg/profile_default.svg?rect';
import Avatar from '@components/avatar/Avatar';
import {
AVATAR_MAX_LENGTH,
CARD_CONTENT_MAX_LENGTH,
CARD_TITLE_MAX_LENGTH,
LIKE_MAX_COUNT,
TAKE_COUNT,
} from '@constants/feed';
import { AVATAR_MAX_LENGTH, CARD_CONTENT_MAX_LENGTH, CARD_TITLE_MAX_LENGTH } from '@constants/feed';
import { THUMBNAIL_IMAGE_INDEX } from '@constants/index';
import { useDisplay } from '@hooks/useDisplay';
import { playgroundLink } from '@sopt-makers/playground-common';
Expand All @@ -40,40 +31,20 @@ interface PostProps {
interface FeedItemProps {
post: PostProps;
HeaderSection?: React.ReactNode;
LikeButton?: React.ReactNode;
meetingId?: number;
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
}

const FeedItem = ({ post, HeaderSection }: FeedItemProps) => {
const { id, user, title, contents, images, updatedDate, commenterThumbnails, commentCount, likeCount, isLiked } =
post;
const formattedLikeCount = likeCount > LIKE_MAX_COUNT ? `${LIKE_MAX_COUNT}+` : likeCount;
const FeedItem = ({ post, HeaderSection, LikeButton, meetingId: _meetingId, onClick }: FeedItemProps) => {
const { user, title, contents, images, updatedDate, commenterThumbnails, commentCount } = post;
const router = useRouter();
const meetingId = router.query.id as string;
const { data: meeting } = useQueryGetMeeting({ params: { id: meetingId } });
const { mutate } = useMutationUpdateLike(TAKE_COUNT, Number(meetingId), id);
const { isMobile } = useDisplay();
// NOTE: 게시글 상세페이지에선 router.query.id 가 post의 id 이기 때문에 meetingId를 주입받아야 한다.
const meetingId = _meetingId ?? Number(router.query.id as string);
const { data: meeting } = useQueryGetMeeting({ params: { id: String(meetingId) } });

const handleLikeClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
mutate();
ampli.clickFeedlistLike({ crew_status: meeting?.approved, location: router.pathname });
};
return (
<SFeedItem
onClick={() =>
ampli.clickFeedCard({
feed_id: id,
feed_upload: updatedDate,
feed_title: title,
feed_image_total: images ? images.length : 0,
feed_comment_total: commentCount,
feed_like_total: likeCount,
group_id: Number(meetingId),
crew_status: meeting?.approved,
platform_type: isMobile ? 'MO' : 'PC',
location: router.pathname,
})
}
>
<SFeedItem onClick={onClick}>
{HeaderSection}
<STop>
<Flex align="center">
Expand Down Expand Up @@ -129,10 +100,7 @@ const FeedItem = ({ post, HeaderSection }: FeedItemProps) => {
</SCommentWrapper>
</Flex>

<SLikeButton like={isLiked} onClick={handleLikeClick}>
{isLiked ? <LikeActiveIcon /> : <LikeDefaultIcon />}
{formattedLikeCount}
</SLikeButton>
{LikeButton}
</SBottom>
</SFeedItem>
);
Expand Down Expand Up @@ -281,27 +249,6 @@ const SCommentCount = styled('span', {
fontStyle: 'H5',
});

const SLikeButton = styled('button', {
display: 'flex',
alignItems: 'center',
fontStyle: 'H5',

variants: {
like: {
true: {
color: '$red',
},
false: {
color: '$gray10',
},
},
},

'& > svg': {
mr: '$6',
},
});

const SOverlay = styled('div', {
position: 'absolute',
background: '$gray950',
Expand Down
56 changes: 43 additions & 13 deletions src/components/page/meetingDetail/Feed/FeedPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ampli } from '@/ampli';
import { useInfinitePosts } from '@api/post/hooks';
import { useInfinitePosts, useMutationUpdateLike } from '@api/post/hooks';
import { useQueryMyProfile } from '@api/user/hooks';
import FeedCreateModal from '@components/feed/Modal/FeedCreateModal';
import { POST_MAX_COUNT, TAKE_COUNT } from '@constants/feed';
Expand All @@ -14,6 +14,8 @@ import { styled } from 'stitches.config';
import EmptyView from './EmptyView';
import FeedItem from './FeedItem';
import MobileFeedListSkeleton from './Skeleton/MobileFeedListSkeleton';
import LikeButton from '@components/button/LikeButton';
import { useQueryGetMeeting } from '@api/meeting/hooks';

interface FeedPanelProps {
isMember: boolean;
Expand All @@ -24,7 +26,7 @@ const FeedPanel = ({ isMember }: FeedPanelProps) => {
const meetingId = router.query.id as string;
const feedCreateOverlay = useOverlay();

const { isTablet } = useDisplay();
const { isMobile, isTablet } = useDisplay();
const { data: me } = useQueryMyProfile();
const {
data: postsData,
Expand All @@ -34,6 +36,8 @@ const FeedPanel = ({ isMember }: FeedPanelProps) => {
isLoading,
} = useInfinitePosts(TAKE_COUNT, Number(meetingId));
useScrollRestorationAfterLoading(isLoading);
const { data: meeting } = useQueryGetMeeting({ params: { id: meetingId } });
const { mutate: mutateLike } = useMutationUpdateLike(TAKE_COUNT, Number(meetingId));

const isEmpty = !postsData?.pages[0];
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
Expand All @@ -56,17 +60,43 @@ const FeedPanel = ({ isMember }: FeedPanelProps) => {
});
};

const renderedPosts = postsData?.pages.map(post => (
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion

<Link href={`/post?id=${post!.id}`} key={post!.id}>
<a>
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
{/* @ts-ignore */}
<FeedItem post={post} />
</a>
</Link>
));
const handleLikeClick = (postId: number) => (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
mutateLike(postId);
ampli.clickFeedlistLike({ crew_status: meeting?.approved, location: router.pathname });
};

const renderedPosts = postsData?.pages.map(post => {
if (!post) return;
return (
<Link href={`/post?id=${post.id}`} key={post.id}>
<a>
<FeedItem
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
/* @ts-ignore */
post={post}
LikeButton={
<LikeButton isLiked={post.isLiked} likeCount={post.likeCount} onClickLike={handleLikeClick(post.id)} />
}
onClick={() =>
ampli.clickFeedCard({
feed_id: post.id,
feed_upload: post.updatedDate,
feed_title: post.title,
feed_image_total: post.images ? post.images.length : 0,
feed_comment_total: post.commentCount,
feed_like_total: post.likeCount,
group_id: Number(meetingId),
crew_status: meeting?.approved,
platform_type: isMobile ? 'MO' : 'PC',
location: router.pathname,
})
}
/>
</a>
</Link>
);
});

return (
<>
Expand Down

0 comments on commit 7787b9f

Please sign in to comment.