From 3f8c63347368683a052b957472ed1f183abc4555 Mon Sep 17 00:00:00 2001 From: BangDori Date: Thu, 16 May 2024 23:53:50 +0900 Subject: [PATCH 01/15] =?UTF-8?q?feat:=20=ED=94=BC=EB=93=9C=20=EC=88=A8?= =?UTF-8?q?=EA=B8=B0=EA=B8=B0=20API=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mocks/consts/hidden.ts | 17 +++++++++++++++++ src/app/mocks/handler/feed.ts | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/app/mocks/consts/hidden.ts diff --git a/src/app/mocks/consts/hidden.ts b/src/app/mocks/consts/hidden.ts new file mode 100644 index 0000000..6f32313 --- /dev/null +++ b/src/app/mocks/consts/hidden.ts @@ -0,0 +1,17 @@ +import { feeds } from './feed'; + +interface Hiddens { + [feedId: keyof typeof feeds]: boolean; +} + +export const hiddens: Hiddens = { + 1: false, + 2: false, + 3: false, + 4: false, + 5: false, + 6: false, + 7: false, + 8: false, + 9: false, +}; diff --git a/src/app/mocks/handler/feed.ts b/src/app/mocks/handler/feed.ts index ae0e24d..d83c459 100644 --- a/src/app/mocks/handler/feed.ts +++ b/src/app/mocks/handler/feed.ts @@ -5,6 +5,7 @@ import { reports } from '../consts/report'; import { users } from '../consts/user'; import { likes } from '../consts/like'; import { comments } from '../consts/comment'; +import { hiddens } from '../consts/hidden'; import { getCurrentDate } from '../dir/date'; import { createHttpSuccessResponse, @@ -187,4 +188,22 @@ export const feedHandlers = [ return createHttpSuccessResponse({}); }), + + // 7️⃣ 피드 숨기기 + http.put('/feeds/:feed_id/hides', ({ params }) => { + const { feed_id } = params; + + if (isNaN(Number(feed_id))) { + return createHttpErrorResponse('4220'); + } + + const formattedFeedId = Number(feed_id); + + if (!feeds[formattedFeedId]) { + return createHttpErrorResponse('4040'); + } + + hiddens[formattedFeedId] = true; + return createHttpSuccessResponse({ isHidden: true }); + }), ]; From 36eab27a8dcf895bb86ba830d4752f5b6938d2ef Mon Sep 17 00:00:00 2001 From: BangDori Date: Fri, 17 May 2024 00:01:07 +0900 Subject: [PATCH 02/15] =?UTF-8?q?feat:=20hidden=20=EB=AA=A8=ED=82=B9=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mocks/consts/feed.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/mocks/consts/feed.ts b/src/app/mocks/consts/feed.ts index 52ca7be..06430b1 100644 --- a/src/app/mocks/consts/feed.ts +++ b/src/app/mocks/consts/feed.ts @@ -4,6 +4,7 @@ import { comments } from './comment'; import { likes } from './like'; import { users } from './user'; import { reports } from './report'; +import { hiddens } from './hidden'; interface Feeds { [feedId: number]: Feed; @@ -273,6 +274,7 @@ export const feeds: Feeds = { for (let i = 10; i < 100; i++) { reports[i] = false; + hiddens[i] = false; comments[i] = []; likes[i] = { totalCount: i, isLiked: false }; feeds[i] = { From bd3054bbaf598807da6d641f7a8729ae2ccc3b40 Mon Sep 17 00:00:00 2001 From: BangDori Date: Fri, 17 May 2024 00:01:36 +0900 Subject: [PATCH 03/15] =?UTF-8?q?feat:=20=EC=8B=A0=EA=B3=A0=20=ED=98=B9?= =?UTF-8?q?=EC=9D=80=20=EC=88=A8=EA=B9=80=20=EC=B2=98=EB=A6=AC=EB=90=9C=20?= =?UTF-8?q?=ED=94=BC=EB=93=9C=20=EC=A0=9C=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mocks/handler/feed.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/mocks/handler/feed.ts b/src/app/mocks/handler/feed.ts index d83c459..ed2aaa4 100644 --- a/src/app/mocks/handler/feed.ts +++ b/src/app/mocks/handler/feed.ts @@ -40,7 +40,7 @@ export const feedHandlers = [ const feedsData = Object.values(feeds) .slice((formattedPage - 1) * pageCount, formattedPage * pageCount) - .filter((feed) => !reports[feed.id]); + .filter((feed) => !reports[feed.id] && !hiddens[feed.id]); const totalFeeds = Object.values(feeds).length; const endOfPageRange = formattedPage * pageCount; @@ -182,8 +182,9 @@ export const feedHandlers = [ return createHttpErrorResponse('4003'); } + reports[formattedFeedId] = true; if (isBlind) { - reports[formattedFeedId] = true; + hiddens[formattedFeedId] = true; } return createHttpSuccessResponse({}); From 3ebdf41815dbcdecfbe47e89c1a4693e12294966 Mon Sep 17 00:00:00 2001 From: BangDori Date: Fri, 17 May 2024 00:03:26 +0900 Subject: [PATCH 04/15] =?UTF-8?q?feat:=20=EC=88=A8=EA=B9=80=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=EB=90=9C=20=ED=94=BC=EB=93=9C=20key=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/widgets/feed-main-list/ui/FeedMainList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/feed-main-list/ui/FeedMainList.tsx b/src/widgets/feed-main-list/ui/FeedMainList.tsx index 92b693a..c5db820 100644 --- a/src/widgets/feed-main-list/ui/FeedMainList.tsx +++ b/src/widgets/feed-main-list/ui/FeedMainList.tsx @@ -35,7 +35,7 @@ export const FeedMainList = () => { {feeds?.pages.map((pageData) => { return pageData.data.feeds.map((feed) => hiddenFeedId === feed.id ? ( - + ) : ( ), From 99bc7ec1fa2738e4c100b7170feda87a4f1e5684 Mon Sep 17 00:00:00 2001 From: BangDori Date: Fri, 17 May 2024 00:07:06 +0900 Subject: [PATCH 05/15] =?UTF-8?q?feat:=20=ED=94=BC=EB=93=9C=20=EC=88=A8?= =?UTF-8?q?=EA=B8=B0=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/feed-hides/index.ts | 1 + src/features/feed-hides/ui/HideButton.tsx | 4 ++++ src/features/feed-hides/ui/index.ts | 1 + src/widgets/feed-kebab/ui/KebabMenu.tsx | 4 +++- 4 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 src/features/feed-hides/index.ts create mode 100644 src/features/feed-hides/ui/HideButton.tsx create mode 100644 src/features/feed-hides/ui/index.ts diff --git a/src/features/feed-hides/index.ts b/src/features/feed-hides/index.ts new file mode 100644 index 0000000..2eaf413 --- /dev/null +++ b/src/features/feed-hides/index.ts @@ -0,0 +1 @@ +export { HideButton } from './ui'; diff --git a/src/features/feed-hides/ui/HideButton.tsx b/src/features/feed-hides/ui/HideButton.tsx new file mode 100644 index 0000000..5845e3d --- /dev/null +++ b/src/features/feed-hides/ui/HideButton.tsx @@ -0,0 +1,4 @@ +export const HideButton: React.FC<{ feedId: number }> = ({ feedId }) => { + feedId; + return ; +}; diff --git a/src/features/feed-hides/ui/index.ts b/src/features/feed-hides/ui/index.ts new file mode 100644 index 0000000..b00c66b --- /dev/null +++ b/src/features/feed-hides/ui/index.ts @@ -0,0 +1 @@ +export { HideButton } from './HideButton'; diff --git a/src/widgets/feed-kebab/ui/KebabMenu.tsx b/src/widgets/feed-kebab/ui/KebabMenu.tsx index 0f058e6..2a72cba 100644 --- a/src/widgets/feed-kebab/ui/KebabMenu.tsx +++ b/src/widgets/feed-kebab/ui/KebabMenu.tsx @@ -1,5 +1,7 @@ +import { HideButton } from '@/features/feed-hides'; import { FeedReportsForm } from '@/features/feed-reports'; import { useToggle } from '@/shared/hooks'; + import './KebabMenu.scss'; interface KebabMenuProps { @@ -15,7 +17,7 @@ export const KebabMenu: React.FC = ({ feedId, onClose }) => { <>
  • - +
  • ; +import { useHides } from '../api'; + +interface HideButtonProps { + feedId: number; + onClose: () => void; +} + +export const HideButton: React.FC = ({ feedId, onClose }) => { + const { hideFeedAsync, isPending } = useHides(feedId); + + const handleClickHideBtn = async () => { + await hideFeedAsync(); + onClose(); + }; + + return ( + + ); }; diff --git a/src/widgets/feed-kebab/ui/KebabMenu.tsx b/src/widgets/feed-kebab/ui/KebabMenu.tsx index 2a72cba..ed68172 100644 --- a/src/widgets/feed-kebab/ui/KebabMenu.tsx +++ b/src/widgets/feed-kebab/ui/KebabMenu.tsx @@ -17,7 +17,7 @@ export const KebabMenu: React.FC = ({ feedId, onClose }) => { <>
    • - +
    • + ); From a2a238c7557b4723415868feb0145b82448e8935 Mon Sep 17 00:00:00 2001 From: BangDori Date: Fri, 17 May 2024 02:19:38 +0900 Subject: [PATCH 13/15] =?UTF-8?q?feat:=20=ED=94=BC=EB=93=9C=20=EC=88=A8?= =?UTF-8?q?=EA=B8=B0=EA=B8=B0=20API=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mocks/browser.ts | 2 ++ src/app/mocks/handler/feed.ts | 18 -------------- src/app/mocks/handler/hide.ts | 46 +++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 src/app/mocks/handler/hide.ts diff --git a/src/app/mocks/browser.ts b/src/app/mocks/browser.ts index d0d6e01..414d0ed 100644 --- a/src/app/mocks/browser.ts +++ b/src/app/mocks/browser.ts @@ -7,11 +7,13 @@ import { followHandler } from './handler/follow'; import { searchHandler } from './handler/search'; import { userHandler } from './handler/user'; import { bookmarkHandlers } from './handler/bookmark'; +import { feedHidesHandlers } from './handler/hide'; // 브라우저에서 실행하기 위한 mocking worker 초기화 export const worker = setupWorker( ...commentHandlers, ...feedHandlers, + ...feedHidesHandlers, ...bookmarkHandlers, ...likeHandlers, ...followHandler, diff --git a/src/app/mocks/handler/feed.ts b/src/app/mocks/handler/feed.ts index ed2aaa4..d583e85 100644 --- a/src/app/mocks/handler/feed.ts +++ b/src/app/mocks/handler/feed.ts @@ -189,22 +189,4 @@ export const feedHandlers = [ return createHttpSuccessResponse({}); }), - - // 7️⃣ 피드 숨기기 - http.put('/feeds/:feed_id/hides', ({ params }) => { - const { feed_id } = params; - - if (isNaN(Number(feed_id))) { - return createHttpErrorResponse('4220'); - } - - const formattedFeedId = Number(feed_id); - - if (!feeds[formattedFeedId]) { - return createHttpErrorResponse('4040'); - } - - hiddens[formattedFeedId] = true; - return createHttpSuccessResponse({ isHidden: true }); - }), ]; diff --git a/src/app/mocks/handler/hide.ts b/src/app/mocks/handler/hide.ts new file mode 100644 index 0000000..fa1995d --- /dev/null +++ b/src/app/mocks/handler/hide.ts @@ -0,0 +1,46 @@ +import { http } from 'msw'; + +import { feeds } from '../consts/feed'; +import { hiddens } from '../consts/hidden'; +import { + createHttpErrorResponse, + createHttpSuccessResponse, +} from '../dir/response'; + +export const feedHidesHandlers = [ + // 1️⃣ 피드 숨기기 + http.put('/feeds/:feed_id/hides', ({ params }) => { + const { feed_id } = params; + + if (isNaN(Number(feed_id))) { + return createHttpErrorResponse('4220'); + } + + const formattedFeedId = Number(feed_id); + + if (!feeds[formattedFeedId]) { + return createHttpErrorResponse('4040'); + } + + hiddens[formattedFeedId] = true; + return createHttpSuccessResponse({ isHidden: true }); + }), + + // 2️⃣ 피드 숨기기 취소 + http.delete('/feeds/:feed_id/hides', ({ params }) => { + const { feed_id } = params; + + if (isNaN(Number(feed_id))) { + return createHttpErrorResponse('4220'); + } + + const formattedFeedId = Number(feed_id); + + if (!feeds[formattedFeedId]) { + return createHttpErrorResponse('4040'); + } + + hiddens[formattedFeedId] = false; + return createHttpSuccessResponse({ isHidden: false }); + }), +]; From 35d7b4dafc924db1d09aa2f96587c34022fe0a03 Mon Sep 17 00:00:00 2001 From: BangDori Date: Fri, 17 May 2024 02:25:25 +0900 Subject: [PATCH 14/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EB=AC=BC=20?= =?UTF-8?q?=EC=88=A8=EA=B8=B0=EA=B8=B0=20=EC=B7=A8=EC=86=8C=20API=20?= =?UTF-8?q?=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/feed-hides/api/index.ts | 1 + src/features/feed-hides/api/useHideCancle.tsx | 19 +++++++++++++++++++ src/features/feed-hides/index.ts | 2 +- .../feed-hides}/ui/HiddenFeed.scss | 0 .../feed-hides}/ui/HiddenFeed.tsx | 11 ++++++----- src/features/feed-hides/ui/index.ts | 1 + .../feed-main-list/ui/FeedMainList.tsx | 2 +- 7 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 src/features/feed-hides/api/useHideCancle.tsx rename src/{widgets/feed-main-list => features/feed-hides}/ui/HiddenFeed.scss (100%) rename src/{widgets/feed-main-list => features/feed-hides}/ui/HiddenFeed.tsx (65%) diff --git a/src/features/feed-hides/api/index.ts b/src/features/feed-hides/api/index.ts index ed33b10..4711d0e 100644 --- a/src/features/feed-hides/api/index.ts +++ b/src/features/feed-hides/api/index.ts @@ -1 +1,2 @@ export { useHides } from './useHides'; +export { useHideCancel } from './useHideCancle'; diff --git a/src/features/feed-hides/api/useHideCancle.tsx b/src/features/feed-hides/api/useHideCancle.tsx new file mode 100644 index 0000000..7587a6a --- /dev/null +++ b/src/features/feed-hides/api/useHideCancle.tsx @@ -0,0 +1,19 @@ +import { useMutation } from '@tanstack/react-query'; + +import { cancleHiddenFeed } from '@/entitites/feed'; +import { axiosInstance } from '@/shared/axios'; + +async function requestHideCancelFeed(feedId: number) { + const { data } = await axiosInstance.delete(`/feeds/${feedId}/hides`); + + return data; +} + +export const useHideCancel = (feedId: number) => { + const { mutateAsync: hideCancelFeed, isPending } = useMutation({ + mutationFn: () => requestHideCancelFeed(feedId), + onSuccess: () => cancleHiddenFeed(feedId), + }); + + return { hideCancelFeed, isPending }; +}; diff --git a/src/features/feed-hides/index.ts b/src/features/feed-hides/index.ts index 2eaf413..5ecdd1f 100644 --- a/src/features/feed-hides/index.ts +++ b/src/features/feed-hides/index.ts @@ -1 +1 @@ -export { HideButton } from './ui'; +export * from './ui'; diff --git a/src/widgets/feed-main-list/ui/HiddenFeed.scss b/src/features/feed-hides/ui/HiddenFeed.scss similarity index 100% rename from src/widgets/feed-main-list/ui/HiddenFeed.scss rename to src/features/feed-hides/ui/HiddenFeed.scss diff --git a/src/widgets/feed-main-list/ui/HiddenFeed.tsx b/src/features/feed-hides/ui/HiddenFeed.tsx similarity index 65% rename from src/widgets/feed-main-list/ui/HiddenFeed.tsx rename to src/features/feed-hides/ui/HiddenFeed.tsx index d6e454d..94cb120 100644 --- a/src/widgets/feed-main-list/ui/HiddenFeed.tsx +++ b/src/features/feed-hides/ui/HiddenFeed.tsx @@ -1,14 +1,16 @@ -import { cancleHiddenFeed } from '@/entitites/feed'; import { Icon } from '@/shared/ui'; import './HiddenFeed.scss'; +import { useHideCancel } from '../api'; interface HiddenFeedProps { feedId: number; message: string; } -const HiddenFeed: React.FC = ({ feedId, message }) => { +export const HiddenFeed: React.FC = ({ feedId, message }) => { + const { hideCancelFeed, isPending } = useHideCancel(feedId); + return (
      @@ -16,7 +18,8 @@ const HiddenFeed: React.FC = ({ feedId, message }) => {

      {message}

      @@ -24,5 +27,3 @@ const HiddenFeed: React.FC = ({ feedId, message }) => {
      ); }; - -export default HiddenFeed; diff --git a/src/features/feed-hides/ui/index.ts b/src/features/feed-hides/ui/index.ts index b00c66b..f579823 100644 --- a/src/features/feed-hides/ui/index.ts +++ b/src/features/feed-hides/ui/index.ts @@ -1 +1,2 @@ export { HideButton } from './HideButton'; +export { HiddenFeed } from './HiddenFeed'; diff --git a/src/widgets/feed-main-list/ui/FeedMainList.tsx b/src/widgets/feed-main-list/ui/FeedMainList.tsx index c1e6012..d9f75f1 100644 --- a/src/widgets/feed-main-list/ui/FeedMainList.tsx +++ b/src/widgets/feed-main-list/ui/FeedMainList.tsx @@ -1,10 +1,10 @@ import { useHiddenFeedStore } from '@/entitites/feed'; +import { HiddenFeed } from '@/features/feed-hides'; import { NetworkError, Observer } from '@/shared/ui'; import { useInfinityFeeds } from '../api'; import { Feed } from './Feed'; -import HiddenFeed from './HiddenFeed'; import { SkeletonFeedMainList } from './SkeletonFeedMainList'; import './FeedMainList.scss'; From 8e9be2b2226e14150ee8935ea3292a4a3e90f3d0 Mon Sep 17 00:00:00 2001 From: BangDori Date: Fri, 17 May 2024 02:30:03 +0900 Subject: [PATCH 15/15] =?UTF-8?q?style:=20cancleHiddenFeed=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entitites/feed/hide-store.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/entitites/feed/hide-store.ts b/src/entitites/feed/hide-store.ts index 2c7aed0..c6cc393 100644 --- a/src/entitites/feed/hide-store.ts +++ b/src/entitites/feed/hide-store.ts @@ -31,6 +31,10 @@ export function addHiddenFeed(feedId: number) { ); } +/** + * 숨김 피드 목록에서 피드를 제거합니다. + * @param feedId 피드 아이디 + */ export function cancleHiddenFeed(feedId: number) { useHiddenFeedStore.setState( ({ hiddenFeeds: prevHiddenFeeds }) => ({