diff --git a/apps/client/src/pages/jobPins/JobPins.tsx b/apps/client/src/pages/jobPins/JobPins.tsx index 7434705..4bb7e49 100644 --- a/apps/client/src/pages/jobPins/JobPins.tsx +++ b/apps/client/src/pages/jobPins/JobPins.tsx @@ -1,42 +1,73 @@ -import { Card } from '@pinback/design-system/ui'; +import { useGetJobPinsArticles } from '@pages/jobPins/apis/queries'; import Footer from '@pages/myBookmark/components/footer/Footer'; - -const MOCK_JOB_PINS = Array.from({ length: 30 }, (_, index) => ({ - id: index + 1, - title: '텍스트텍스트텍스트텍스트텍스트텍스트텍스트', - content: '서브텍스트입니다서브텍스트입니다서브텍스트입니다서브텍스트입니다', - category: '카테고리명', - categoryColor: 'COLOR7' as const, - variant: 'save' as const, - nickname: index % 3 === 0 ? '구글닉네임명' : '', -})); +import { Card } from '@pinback/design-system/ui'; +import { useInfiniteScroll } from '@shared/hooks/useInfiniteScroll'; +import { useRef } from 'react'; const JobPins = () => { + const scrollContainerRef = useRef(null); + + const { data, isPending, fetchNextPage, hasNextPage } = + useGetJobPinsArticles(); + + const observerRef = useInfiniteScroll({ + fetchNextPage, + hasNextPage, + root: scrollContainerRef, + }); + + const articlesToDisplay = + data?.pages.flatMap((page) => page.articles ?? []) ?? []; + + const job = data?.pages?.[0]?.job ?? null; + + if (isPending) { + return
Loading...
; + } + return (

관심 직무 핀

-

기획자

+ {job &&

{job}

}

같은 직무의 사람들이 저장한 아티클을 살펴봐요. 선택한 직무를 기준으로 최신 핀이 업데이트 돼요!

-
- {MOCK_JOB_PINS.map((pin) => ( - - ))} -
+ {job === null ? ( +

+ 기존 사용자 직무 선택 API로 직무 정보를 변경해주세요. +

+ ) : articlesToDisplay.length > 0 ? ( +
+ {articlesToDisplay.map((article) => ( + window.open(article.url, '_blank')} + /> + ))} + +
+
+ ) : ( + // TODO: 아티클 없는경우 UI 수정 +

+ 아직 공유된 아티클이 없어요. +

+ )}
diff --git a/apps/client/src/pages/jobPins/apis/axios.ts b/apps/client/src/pages/jobPins/apis/axios.ts new file mode 100644 index 0000000..0d7218e --- /dev/null +++ b/apps/client/src/pages/jobPins/apis/axios.ts @@ -0,0 +1,22 @@ +import apiRequest from '@shared/apis/setting/axiosInstance'; +import { JobPinsResponse } from '@pages/jobPins/types/api'; + +interface ApiResponse { + code: string; + message: string; + data: T; +} + +export const getJobPinsArticles = async ( + page: number, + size: number +): Promise => { + const { data } = await apiRequest.get('/api/v3/articles/shared/job', { + params: { + page, + size, + }, + }); + + return (data as ApiResponse).data; +}; diff --git a/apps/client/src/pages/jobPins/apis/queries.ts b/apps/client/src/pages/jobPins/apis/queries.ts new file mode 100644 index 0000000..c279c1d --- /dev/null +++ b/apps/client/src/pages/jobPins/apis/queries.ts @@ -0,0 +1,18 @@ +import { useInfiniteQuery } from '@tanstack/react-query'; +import { JobPinsResponse } from '@pages/jobPins/types/api'; +import { getJobPinsArticles } from './axios'; + +export const useGetJobPinsArticles = () => { + return useInfiniteQuery({ + queryKey: ['jobPinsArticles'], + queryFn: ({ pageParam = 0 }) => getJobPinsArticles(pageParam as number, 20), + initialPageParam: 0, + getNextPageParam: (lastPage, allPages) => { + if (lastPage.articles.length === 0) { + return undefined; + } + + return allPages.length; + }, + }); +}; diff --git a/apps/client/src/pages/jobPins/types/api.ts b/apps/client/src/pages/jobPins/types/api.ts new file mode 100644 index 0000000..42b9942 --- /dev/null +++ b/apps/client/src/pages/jobPins/types/api.ts @@ -0,0 +1,20 @@ +interface JobPinCategory { + categoryId: number; + categoryName: string; + categoryColor: string; +} + +interface JobPinArticle { + articleId: number; + url: string; + title: string; + thumbnailUrl: string; + memo: string; + ownerName: string; + category: JobPinCategory; +} + +export interface JobPinsResponse { + job: string | null; + articles: JobPinArticle[]; +}