diff --git a/src/bookmarks/ui/BookmarkUserInfo.tsx b/src/bookmarks/ui/BookmarkUserInfo.tsx
index 2daf1ecd..9e22a10d 100644
--- a/src/bookmarks/ui/BookmarkUserInfo.tsx
+++ b/src/bookmarks/ui/BookmarkUserInfo.tsx
@@ -13,6 +13,7 @@ interface BookmarkUserInfoProps {
isFollowing: boolean;
friendId: number;
memberId: number;
+ isBlocked: boolean;
};
}
@@ -43,12 +44,14 @@ const BookmarkUserInfo = ({
)}
{!isFriendPage?.isFollowing && (
)}
>
diff --git a/src/friend/api/friends.tsx b/src/friend/api/friends.tsx
index 7228a8b8..6e0b2771 100644
--- a/src/friend/api/friends.tsx
+++ b/src/friend/api/friends.tsx
@@ -20,6 +20,7 @@ export interface FollowingInfo {
memberId: number;
nickname: string;
emoji: string;
+ isBlocked: boolean;
}
interface GETFollowingListRequest {
@@ -81,6 +82,7 @@ interface FollowerInfo {
memberId: number;
nickname: string;
isFollowing: boolean;
+ isBlocked: boolean;
emoji: string;
}
@@ -392,6 +394,7 @@ export interface SearchList {
nickname: string;
emoji: string;
isFollowing: boolean;
+ isBlocked: boolean;
}
interface GETSearchListRequest {
@@ -431,8 +434,6 @@ export const GET_SEARCH_LIST_KEY = (params: GETSearchListQueryRequest) => [
'GET_SEARCH_LIST',
params.memberId,
params.keyword,
- params.cursorId,
- params.pageSize,
];
export const useGETSearchListQuery = (params: GETSearchListQueryRequest) => {
diff --git a/src/friend/ui/Friends.tsx b/src/friend/ui/Friends.tsx
index 95bc2cce..4a3bbda5 100644
--- a/src/friend/ui/Friends.tsx
+++ b/src/friend/ui/Friends.tsx
@@ -51,6 +51,7 @@ const Friends = () => {
name={info.nickname}
profileEmoji={info.emoji}
isFollowing={true}
+ isBlocked={info.isBlocked}
/>
))}
{selectedType === FriendType.Following && !followings.length && (
@@ -65,6 +66,7 @@ const Friends = () => {
name={info.nickname}
profileEmoji={info.emoji}
isFollowing={info.isFollowing}
+ isBlocked={info.isBlocked}
/>
))}
diff --git a/src/friend/ui/buttons/FollowButton.tsx b/src/friend/ui/buttons/FollowButton.tsx
index 31c782c8..e21f7c9c 100644
--- a/src/friend/ui/buttons/FollowButton.tsx
+++ b/src/friend/ui/buttons/FollowButton.tsx
@@ -6,18 +6,34 @@ import { theme } from '@/styles/theme';
import { type MouseEvent } from 'react';
import { usePOSTFollowUserQuery } from '@/friend/api/friends';
import useSearchStore from '@/store/search';
+import useToast from '@/common-ui/Toast/hooks/useToast';
interface FollowButtonProps {
memberId: number;
followerId: number;
+ isBlocked?: boolean;
}
-const FollowButton = ({ memberId, followerId }: FollowButtonProps) => {
+const FollowButton = ({
+ memberId,
+ followerId,
+ isBlocked = false,
+}: FollowButtonProps) => {
const { setSelectedMemberId } = useSearchStore();
const { mutate } = usePOSTFollowUserQuery({ memberId: followerId });
+ const { fireToast } = useToast();
+
//TODO: 하드 코딩 개선
const onClick = (e: MouseEvent) => {
e.stopPropagation();
+ if (isBlocked) {
+ fireToast({
+ message: '차단된 사용자는 팔로우 할 수 없어요',
+ mode: 'ERROR',
+ });
+ return;
+ }
+
setSelectedMemberId(memberId);
mutate({ memberId, followerId });
};
diff --git a/src/friend/ui/buttons/UnFollowButton.tsx b/src/friend/ui/buttons/UnFollowButton.tsx
index 5fbe3132..4a530daf 100644
--- a/src/friend/ui/buttons/UnFollowButton.tsx
+++ b/src/friend/ui/buttons/UnFollowButton.tsx
@@ -5,18 +5,32 @@ import { theme } from '@/styles/theme';
import { type MouseEvent } from 'react';
import { useDELETEUnFollowQuery } from '@/friend/api/friends';
import useSearchStore from '@/store/search';
+import useToast from '@/common-ui/Toast/hooks/useToast';
interface UnFollowButtonProps {
memberId: number;
followerId: number;
+ isBlocked?: boolean;
}
-const UnFollowButton = ({ memberId, followerId }: UnFollowButtonProps) => {
+const UnFollowButton = ({
+ memberId,
+ followerId,
+ isBlocked = false,
+}: UnFollowButtonProps) => {
const { setSelectedMemberId } = useSearchStore();
const { mutate } = useDELETEUnFollowQuery({ memberId: followerId });
- //TODO: 하드코딩 개선
+ const { fireToast } = useToast();
+
const onClick = (e: MouseEvent) => {
e.stopPropagation();
+ if (isBlocked) {
+ fireToast({
+ message: '차단된 사용자는 팔로우 할 수 없어요',
+ mode: 'ERROR',
+ });
+ return;
+ }
setSelectedMemberId(memberId);
mutate({ memberId, followerId });
};
diff --git a/src/friend/ui/friend/FriendFollowerItem.tsx b/src/friend/ui/friend/FriendFollowerItem.tsx
index 9d6d9270..7708fd93 100644
--- a/src/friend/ui/friend/FriendFollowerItem.tsx
+++ b/src/friend/ui/friend/FriendFollowerItem.tsx
@@ -8,6 +8,7 @@ type FriendFollowerProps = {
name: string;
profileEmoji: string;
isFollowing: boolean;
+ isBlocked: boolean;
};
const FriendFollowerItem = ({
id,
@@ -15,6 +16,7 @@ const FriendFollowerItem = ({
name,
profileEmoji,
isFollowing,
+ isBlocked,
}: FriendFollowerProps) => {
return (
+
) : (
-
+
)
}
/>
diff --git a/src/friend/ui/friend/FriendFollowingItem.tsx b/src/friend/ui/friend/FriendFollowingItem.tsx
index acbc02c5..9d20c66c 100644
--- a/src/friend/ui/friend/FriendFollowingItem.tsx
+++ b/src/friend/ui/friend/FriendFollowingItem.tsx
@@ -8,6 +8,7 @@ type FriendFollowingProps = {
name: string;
profileEmoji: string;
isFollowing: boolean;
+ isBlocked: boolean;
};
const FriendFollowingItem = ({
id,
@@ -15,6 +16,7 @@ const FriendFollowingItem = ({
name,
profileEmoji,
isFollowing,
+ isBlocked,
}: FriendFollowingProps) => {
return (
+
) : (
-
+
)
}
/>
diff --git a/src/friend/ui/friend/FriendList.tsx b/src/friend/ui/friend/FriendList.tsx
index a76d8413..8ac572a6 100644
--- a/src/friend/ui/friend/FriendList.tsx
+++ b/src/friend/ui/friend/FriendList.tsx
@@ -40,7 +40,8 @@ const FriendList = ({ keyword }: FriendListProps) => {
memberId={memberId}
name={info.nickname}
profileEmoji={info.emoji}
- isFollowing={Boolean(info.isFollowing)}
+ isFollowing={info.isFollowing}
+ isBlocked={info.isBlocked}
/>
))}
diff --git a/src/members/api/member.ts b/src/members/api/member.ts
index 32a326da..452de7b3 100644
--- a/src/members/api/member.ts
+++ b/src/members/api/member.ts
@@ -1,7 +1,11 @@
import { GET_USER_PROFILE } from '@/auth/api/profile';
import useToast from '@/common-ui/Toast/hooks/useToast';
import client from '@/common/service/client';
+import { GET_SEARCH_LIST_KEY, SearchList } from '@/friend/api/friends';
+import useFriendStore from '@/store/friend';
+import useSearchStore from '@/store/search';
import {
+ InfiniteData,
useInfiniteQuery,
useMutation,
useQuery,
@@ -328,18 +332,53 @@ interface POSTBlockMemberQueryParams {
memberId: number;
}
+type InfiniteSearchList =
+ | InfiniteData<{
+ contents: SearchList[];
+ hasNext: boolean;
+ }>
+ | undefined;
+
export const usePOSTBlockMemberQuery = ({
memberId,
}: POSTBlockMemberQueryParams) => {
const router = useNavigate();
const { fireToast } = useToast();
const queryClient = useQueryClient();
+ const { keyword, selectedMemberId } = useSearchStore();
+ console.log(keyword, memberId);
return useMutation(postBlockMemberAPI, {
onSuccess: () => {
fireToast({ message: '차단 되었습니다' });
router(-1);
queryClient.refetchQueries(GET_BLOCK_MEMBER_LIST_KEY({ memberId }));
queryClient.refetchQueries(GET_USER_PROFILE({ loginId: memberId }));
+ if (keyword && selectedMemberId) {
+ queryClient.setQueryData(
+ GET_SEARCH_LIST_KEY({ memberId, keyword }),
+ (searchList) => {
+ if (searchList) {
+ return {
+ ...searchList,
+ pages: searchList.pages.map((page) => ({
+ ...page,
+ contents: page.contents.map((content) => {
+ if (content.memberId === selectedMemberId) {
+ return {
+ ...content,
+ isFollowing: false,
+ isBlocked: true,
+ };
+ }
+ return content;
+ }),
+ })),
+ };
+ }
+ return searchList;
+ },
+ );
+ }
},
});
};
@@ -351,6 +390,7 @@ export interface MemberProfile {
nickname: string;
profileEmoji: string;
isFollowing: boolean;
+ isBlocked: boolean;
}
interface GETMemberProfileParams {
@@ -411,7 +451,6 @@ interface GetBlockMemberListParams {
pageSize?: number;
}
-// NOTE : Backend API가 수정되면 삭제
const GETBlockMemberList = {
API: async (params: GetBlockMemberListParams) => {
const { data } = await client({
@@ -477,9 +516,13 @@ export const useUnblockUserQuery = ({
}: DELETEBlockMemberQueryParams) => {
const queryClient = useQueryClient();
const { fireToast } = useToast();
+ const { friendId } = useFriendStore();
return useMutation(unblockUserAPI, {
onSuccess: () => {
queryClient.invalidateQueries(GET_BLOCK_MEMBER_LIST_KEY({ memberId }));
+ queryClient.refetchQueries(
+ GET_FRIEND_PROFILE({ memberId: friendId, loginId: memberId }),
+ );
fireToast({ message: '차단이 해제 되었습니다' });
},
});
diff --git a/src/pages/FriendBookmarkPage.tsx b/src/pages/FriendBookmarkPage.tsx
index 73d18074..ef5ab1df 100644
--- a/src/pages/FriendBookmarkPage.tsx
+++ b/src/pages/FriendBookmarkPage.tsx
@@ -13,18 +13,26 @@ import IconButton from '@/common/ui/IconButton';
import {
useGETFriendProfileQuery,
usePOSTBlockMemberQuery,
+ useUnblockUserQuery,
} from '@/members/api/member';
import useAuthStore from '@/store/auth';
import BookmarkListView from '@/bookmarks/ui/Main/BookmarkListView';
-import { Suspense } from 'react';
+import { Suspense, useEffect } from 'react';
import SkeletonWrapper from '@/common-ui/SkeletonWrapper';
import BookmarkSkeletonItem from '@/bookmarks/ui/Main/BookmarkSkeletonItem';
+import useFriendStore from '@/store/friend';
const FriendBookmarkPage = () => {
// FIRST RENDER
const { memberId } = useAuthStore();
const { id: friendId } = useParams<{ id: string }>();
+ const { setFriendId } = useFriendStore();
+
+ useEffect(() => {
+ setFriendId(Number(friendId));
+ }, [friendId]);
+
// SERVER
// 1. 친구 프로필 조회
const { data: profileInfo } = useGETFriendProfileQuery({
@@ -38,6 +46,10 @@ const FriendBookmarkPage = () => {
const onClick_차단하기 = () => {
postBlockMember({ blockeeId: Number(friendId), blockerId: memberId });
};
+ const { mutate: deleteUnBlockMember } = useUnblockUserQuery({ memberId });
+ const onClick_차단해제 = () => {
+ deleteUnBlockMember({ blockeeId: Number(friendId), blockerId: memberId });
+ };
// 2. 카테고리 선택
const { selectedCategoryId, categoryOptions, onChangeCategory } = useCategory(
@@ -59,21 +71,29 @@ const FriendBookmarkPage = () => {
as={ {}} name="more" size="s" />}
/>
-
- 차단하기
-
+ {!!profileInfo?.isBlocked && (
+
+ 차단해제
+
+ )}
+ {!profileInfo?.isBlocked && (
+
+ 차단하기
+
+ )}
}
/>
diff --git a/src/store/friend.ts b/src/store/friend.ts
index b85f9f1c..d40e8a18 100644
--- a/src/store/friend.ts
+++ b/src/store/friend.ts
@@ -8,6 +8,8 @@ export enum FriendType {
interface FriendStore {
selectedType: FriendType;
setSelectedType: (mode: FriendType) => void;
+ friendId: number;
+ setFriendId: (friendId: number) => void;
}
const useFriendStore = create((set) => ({
@@ -15,6 +17,10 @@ const useFriendStore = create((set) => ({
setSelectedType: (selectedType) => {
set({ selectedType });
},
+ friendId: 0,
+ setFriendId: (friendId) => {
+ set({ friendId });
+ },
}));
export default useFriendStore;
diff --git a/src/store/toast.ts b/src/store/toast.ts
index e6ad80ac..32a72bbb 100644
--- a/src/store/toast.ts
+++ b/src/store/toast.ts
@@ -9,7 +9,8 @@ export type ToastMessage =
| '앗! 유효하지 않은 주소에요'
| '신고 되었습니다'
| '이미 신고한 북마크에요'
- | '앗! 알림 설정 기준일은 1일 이상이어야 해요';
+ | '앗! 알림 설정 기준일은 1일 이상이어야 해요'
+ | '차단된 사용자는 팔로우 할 수 없어요';
export type ToastMode = 'SUCCESS' | 'DELETE' | 'ERROR';