Skip to content
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
7 changes: 5 additions & 2 deletions apps/client/src/pages/myBookmark/MyBookmark.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ const MyBookmark = () => {
const handleDeleteArticle = (id: number) => {
deleteArticle(id, {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['bookmarkReadArticles'] });
queryClient.invalidateQueries({ queryKey: ['bookmarkUnreadArticles'] });
queryClient.invalidateQueries({ queryKey: ['bookmarkArticles'] });
queryClient.invalidateQueries({ queryKey: ['bookmarkArticlesCount'] });
queryClient.invalidateQueries({
queryKey: ['categoryBookmarkArticlesCount'],
});
queryClient.invalidateQueries({
queryKey: ['categoryBookmarkArticles'],
});
Expand Down
54 changes: 34 additions & 20 deletions apps/client/src/pages/myBookmark/apis/axios.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,48 @@
import {
BookmarkArticlesCountResponse,
BookmarkArticlesResponse,
CategoryBookmarkArticleResponse,
} from '@pages/myBookmark/types/api';
import apiRequest from '@shared/apis/setting/axiosInstance';

export const getBookmarkArticles = async (page: number, size: number) => {
export const getBookmarkArticles = async (
readStatus: boolean | null,
page: number,
size: number
): Promise<BookmarkArticlesResponse> => {
const readStatusQuery =
readStatus === null ? '' : `&read-status=${readStatus}`;
const { data } = await apiRequest.get(
`/api/v1/articles?page=${page}&size=${size}`
`/api/v3/articles?page=${page}&size=${size}${readStatusQuery}`
);
return data.data;
};

export const getBookmarkUnreadArticles = async (page: number, size: number) => {
const { data } = await apiRequest.get(
`/api/v1/articles/unread?page=${page}&size=${size}`
);
return data.data;
};
export const getBookmarkArticlesCount =
async (): Promise<BookmarkArticlesCountResponse> => {
const { data } = await apiRequest.get(`/api/v3/articles/count`);
return data.data;
};

export const getCategoryBookmarkArticles = async (
categoryId: string | null,
readStatus: boolean | null,
page: number,
size: number
) => {
if (readStatus === null) {
const { data } = await apiRequest.get(
`/api/v1/articles/category?categoryId=${categoryId}&page=${page}&size=${size}`
);
return data.data;
} else {
const { data } = await apiRequest.get(
`/api/v1/articles/category?categoryId=${categoryId}&read-status=${readStatus}&page=${page}&size=${size}`
);
return data.data;
}
): Promise<CategoryBookmarkArticleResponse> => {
const readStatusQuery =
readStatus === null ? '' : `&read-status=${readStatus}`;
const { data } = await apiRequest.get(
`/api/v3/articles/category?category-id=${categoryId}&page=${page}&size=${size}${readStatusQuery}`
);
return data.data;
};

export const getCategoryBookmarkArticlesCount = async (
categoryId: string
): Promise<BookmarkArticlesCountResponse> => {
const { data } = await apiRequest.get(
`/api/v3/articles/category/count?category-id=${categoryId}`
);
return data.data;
};
56 changes: 41 additions & 15 deletions apps/client/src/pages/myBookmark/apis/queries.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
import { useSuspenseInfiniteQuery } from '@tanstack/react-query';
import {
useQuery,
useSuspenseInfiniteQuery,
useSuspenseQuery,
} from '@tanstack/react-query';
import {
getBookmarkArticles,
getBookmarkUnreadArticles,
getBookmarkArticlesCount,
getCategoryBookmarkArticles,
getCategoryBookmarkArticlesCount,
} from './axios';
import {
CategoryBookmarkArticleResponse,
} from '../types/api';

export const useGetBookmarkArticles = () => {
export const useGetBookmarkArticles = (readStatus: boolean | null) => {
return useSuspenseInfiniteQuery({
queryKey: ['bookmarkReadArticles'],
queryFn: ({ pageParam = 0 }) => getBookmarkArticles(pageParam, 20),
queryKey: ['bookmarkArticles', readStatus],
queryFn: ({ pageParam = 0 }) =>
getBookmarkArticles(readStatus, Number(pageParam), 20),
initialPageParam: 0,
getNextPageParam: (lastPage, allPages) =>
lastPage.articles.length === 0 ? undefined : allPages.length,
});
};

export const useGetBookmarkUnreadArticles = () => {
return useSuspenseInfiniteQuery({
queryKey: ['bookmarkUnreadArticles'],
queryFn: ({ pageParam = 0 }) => getBookmarkUnreadArticles(pageParam, 20),
initialPageParam: 0,
getNextPageParam: (lastPage, allPages) =>
lastPage.articles.length === 0 ? undefined : allPages.length,
export const useGetBookmarkArticlesCount = () => {
return useSuspenseQuery({
queryKey: ['bookmarkArticlesCount'],
queryFn: getBookmarkArticlesCount,
});
};

Expand All @@ -31,10 +37,20 @@ export const useGetCategoryBookmarkArticles = (
) => {
return useSuspenseInfiniteQuery({
queryKey: ['categoryBookmarkArticles', readStatus, categoryId],

queryFn: ({ pageParam = 0 }) => {
if (!categoryId) return null;
return getCategoryBookmarkArticles(categoryId, readStatus, pageParam, 20);
if (!categoryId)
return Promise.resolve<CategoryBookmarkArticleResponse>({
totalArticleCount: 0,
unreadArticleCount: 0,
categoryName: '',
articles: [],
});
return getCategoryBookmarkArticles(
categoryId,
readStatus,
Number(pageParam),
20
);
},

initialPageParam: 0,
Expand All @@ -44,3 +60,13 @@ export const useGetCategoryBookmarkArticles = (
},
});
};

export const useGetCategoryBookmarkArticlesCount = (
categoryId: string | null
) => {
return useQuery({
queryKey: ['categoryBookmarkArticlesCount', categoryId],
queryFn: () => getCategoryBookmarkArticlesCount(categoryId!),
enabled: !!categoryId,
});
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
import {
useGetBookmarkArticles,
useGetBookmarkUnreadArticles,
useGetCategoryBookmarkArticles,
} from '@pages/myBookmark/apis/queries';

import { useInfiniteScroll } from '@shared/hooks/useInfiniteScroll';
import FetchCard from '@pages/myBookmark/components/fetchCard/FetchCard';
import { useMyBookmarkContentData } from '@pages/myBookmark/hooks/useMyBookmarkContentData';
import NoArticles from '@pages/myBookmark/components/NoArticles/NoArticles';
import NoUnreadArticles from '@pages/myBookmark/components/noUnreadArticles/NoUnreadArticles';
import { MutableRefObject } from 'react';
import { Badge } from '@pinback/design-system/ui';
import { Badge, Card } from '@pinback/design-system/ui';

interface MyBookmarkContentProps {
activeBadge: 'all' | 'notRead';
Expand All @@ -33,67 +26,22 @@ const MyBookmarkContent = ({
scrollContainerRef,
}: MyBookmarkContentProps) => {
const {
data: articlesData,
fetchNextPage: fetchNextArticles,
hasNextPage: hasNextArticles,
} = useGetBookmarkArticles();

const {
data: unreadArticlesData,
fetchNextPage: fetchNextUnreadArticles,
hasNextPage: hasNextUnreadArticles,
} = useGetBookmarkUnreadArticles();

const {
data: categoryArticlesData,
fetchNextPage: fetchNextCategoryArticles,
hasNextPage: hasNextCategoryArticles,
} = useGetCategoryBookmarkArticles(
view,
list,
counts,
pagination,
} = useMyBookmarkContentData({
activeBadge,
category,
categoryId,
activeBadge === 'notRead' ? false : null
);

const categoryList =
categoryId && categoryArticlesData?.pages
? categoryArticlesData.pages.flatMap((page) => page.articles)
: [];

const articlesToDisplay = category
? categoryList
: activeBadge === 'all'
? (articlesData?.pages.flatMap((page) => page.articles) ?? [])
: (unreadArticlesData?.pages.flatMap((page) => page.articles) ?? []);

const totalArticle = category
? categoryArticlesData?.pages?.[0]?.totalArticle
: articlesData?.pages?.[0]?.totalArticle;

const totalUnread = category
? categoryArticlesData?.pages?.[0]?.totalUnreadArticle
: articlesData?.pages?.[0]?.totalUnreadArticle;

const hasNextPage = category
? hasNextCategoryArticles
: activeBadge === 'all'
? hasNextArticles
: hasNextUnreadArticles;

const fetchNextPage = category
? fetchNextCategoryArticles
: activeBadge === 'all'
? fetchNextArticles
: fetchNextUnreadArticles;

const observerRef = useInfiniteScroll({
fetchNextPage,
hasNextPage,
root: scrollContainerRef,
scrollContainerRef,
});
const totalCount = counts.total ?? 0;

/** Empty 상태 컴포넌트 */
const EmptyStateComponent = () => {
if (articlesToDisplay.length === 0) {
if (articlesData?.pages?.[0]?.totalArticle === 0) return <NoArticles />;
if (list.articles.length === 0) {
if (totalCount === 0) return <NoArticles />;
return <NoUnreadArticles />;
}
return null;
Expand All @@ -104,36 +52,51 @@ const MyBookmarkContent = ({
<div className="mt-[3rem] flex gap-[2.4rem]">
<Badge
text="전체보기"
countNum={totalArticle ?? 0}
countNum={counts.total ?? 0}
onClick={() => onBadgeChange('all')}
isActive={activeBadge === 'all'}
/>
<Badge
text="안 읽음"
countNum={totalUnread ?? 0}
countNum={counts.unread ?? 0}
onClick={() => onBadgeChange('notRead')}
isActive={activeBadge === 'notRead'}
/>
</div>

{articlesToDisplay.length > 0 ? (
{list.articles.length > 0 ? (
<div
ref={scrollContainerRef}
className="scrollbar-hide mt-[2.6rem] flex h-screen flex-wrap content-start gap-[1.6rem] overflow-y-auto scroll-smooth"
>
{articlesToDisplay.map((article) => (
<FetchCard
{list.articles.map((article) => (
<Card
key={article.articleId}
article={article}
type="bookmark"
title={article.title || '제목 없음'}
imageUrl={article.thumbnailUrl || undefined}
content={article.memo ?? undefined}
category={
view.isCategoryView
? view.categoryName
: article.category?.categoryName
}
categoryColor={
view.isCategoryView ? undefined : article.category?.categoryColor
}
date={new Date(article.createdAt).toLocaleDateString('ko-KR')}
onClick={() => {
window.open(article.url, '_blank');
updateToReadStatus(article.articleId, {
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['bookmarkReadArticles'],
queryKey: ['bookmarkArticles'],
});
queryClient.invalidateQueries({
queryKey: ['bookmarkArticlesCount'],
});
queryClient.invalidateQueries({
queryKey: ['bookmarkUnreadArticles'],
queryKey: ['categoryBookmarkArticlesCount'],
});
queryClient.invalidateQueries({
queryKey: ['categoryBookmarkArticles'],
Expand All @@ -152,7 +115,10 @@ const MyBookmarkContent = ({
/>
))}

<div ref={observerRef} style={{ height: '1px', width: '100%' }} />
<div
ref={pagination.sentinelRef}
style={{ height: '1px', width: '100%' }}
/>
</div>
) : (
<EmptyStateComponent />
Expand Down
Loading
Loading