Skip to content

Commit

Permalink
Merge pull request #74 from Prography-9th-3team/feat/feed
Browse files Browse the repository at this point in the history
feat: feed 구현
  • Loading branch information
hoongding authored Jul 26, 2024
2 parents d141397 + 4d80c63 commit f7a7e4b
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 23 deletions.
4 changes: 4 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ const nextConfig = {
source: '/file/:path*',
destination: 'http://3.39.102.104/file',
},
{
source: '/recommend/:path*',
destination: 'http://3.39.102.104/recommend/:path*',
},
],
};

Expand Down
3 changes: 3 additions & 0 deletions src/apis/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ const apis = {
file: '/file',
thumbnail: (uuid: string) => `/file/thumb/original/${uuid}`,
},
recommend: {
recommend_bookmarks: '/recommend/book-mark/list',
},
};

export default apis;
2 changes: 1 addition & 1 deletion src/apis/bookmark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface IBookmarkParamDataType {
isFavorite?: boolean;
}

interface IBookmarkListResponseDataType {
export interface IBookmarkListResponseDataType {
pageInfo: {
pageNumber: number;
size: number;
Expand Down
42 changes: 42 additions & 0 deletions src/apis/recommend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-disable @typescript-eslint/no-explicit-any */

import useAuthStore from '@/stores/authStore';
import { InfiniteData, useInfiniteQuery } from '@tanstack/react-query';
import { fetchData } from '.';
import { default as apis } from './api';
import { IBookmarkListResponseDataType } from './bookmark';

export const useRecommendBookmarkList = () => {
const url = apis.recommend.recommend_bookmarks;
const authStore = useAuthStore();

return useInfiniteQuery<any, unknown, IBookmarkListResponseDataType, any>({
queryKey: [apis.bookmark.bookmark_list],
queryFn: async ({ pageParam }) => {
const res = await fetchData.get(url, {
params: { pageNumber: pageParam, size: 8 },
});

return res.data;
},
initialPageParam: 0,
getNextPageParam: (page: any) => {
const { lastPage, pageNumber } = page.result.pageInfo;

return !lastPage ? pageNumber + 1 : null;
},
select: (res: InfiniteData<{ result: IBookmarkListResponseDataType }>) => {
const content = res.pages.reduce((prev: any, cur: any) => {
return [...prev, ...cur.result.content];
}, []);

return {
content,
pageInfo: res.pages[0].result.pageInfo,
};
},
staleTime: 1000 * 60 * 10,
gcTime: 1000 * 60 * 10,
enabled: authStore.isLogin(),
});
};
5 changes: 4 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Feed from '@/components/Feed';
import Footer from '@/components/Footer';
import Sidebar from '@/components/Sidebar';
import ToastArea from '@/components/common/Toast/ToastArea';
Expand All @@ -8,7 +9,8 @@ import RouteGuard from './RouteGuard';

export const metadata: Metadata = {
title: '패킷',
description: 'Generated by create next app',
description:
'성장하는 사람들을 위한 올인원 툴, 패킷으로 쉽고 간편하게 나만의 인사이트를 관리하세요.',
icons: '/logo.svg',
};

Expand All @@ -29,6 +31,7 @@ export default function RootLayout({
<div className='flex-1'>{children}</div>
<Footer />
</div>
<Feed />
<ToastArea />
<div id='modal' className='styled-scroll'></div>
</Provider>
Expand Down
49 changes: 28 additions & 21 deletions src/components/BookmarkCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useBookmarkLike } from '@/apis/bookmark';
import { bookmarkValidateSiteName } from '@/constants/data';
import { isValidUrl } from '@/lib/url';
import { cn } from '@/lib/utils';
import useToastStore from '@/stores/toastStore';
import { MouseEvent, useState } from 'react';
Expand All @@ -18,6 +19,7 @@ export interface IBookmarkCard {
imageUUID?: string;
isFavorite: boolean;
onClick: () => void;
isRecommendCard?: boolean;
}

const BookmarkCard = ({
Expand All @@ -32,6 +34,7 @@ const BookmarkCard = ({
imageUUID,
isFavorite,
onClick,
isRecommendCard = false,
}: IBookmarkCard) => {
const { addToast } = useToastStore();

Expand Down Expand Up @@ -85,7 +88,9 @@ const BookmarkCard = ({
alt='썸네일'
width={650}
/>
) : representImageUrl && !bookmarkValidateSiteName.includes(siteName) ? (
) : representImageUrl &&
!bookmarkValidateSiteName.includes(siteName) &&
isValidUrl(representImageUrl) ? (
// url 썸네일 이미지
<img
className='aspect-[296/180] object-cover'
Expand Down Expand Up @@ -124,26 +129,28 @@ const BookmarkCard = ({
</picture>
<span className='body-md text-text truncate'>{bookmarkSiteName}</span>
</div>
<div
className={cn([
'hidden items-center gap-12 *:text-icon-minimal group-hover:flex',
isLike && 'flex',
])}
>
<button onClick={handleToggleLike}>
{isLike ? (
<Icon name='heart_fill' className='w-20 h-20 text-primary' />
) : (
<Icon name='heart' className='w-20 h-20' />
)}
</button>
<button onClick={handleCopyUrl}>
<Icon name='link_03' className='w-20 h-20' />
</button>
<button onClick={(e) => e.stopPropagation()}>
<Icon name='dotsVertical' className='w-20 h-20' />
</button>
</div>
{!isRecommendCard && (
<div
className={cn([
'hidden items-center gap-12 *:text-icon-minimal group-hover:flex',
isLike && 'flex',
])}
>
<button onClick={handleToggleLike}>
{isLike ? (
<Icon name='heart_fill' className='w-20 h-20 text-primary' />
) : (
<Icon name='heart' className='w-20 h-20' />
)}
</button>
<button onClick={handleCopyUrl}>
<Icon name='link_03' className='w-20 h-20' />
</button>
<button onClick={(e) => e.stopPropagation()}>
<Icon name='dotsVertical' className='w-20 h-20' />
</button>
</div>
)}
</div>
</div>
);
Expand Down
46 changes: 46 additions & 0 deletions src/components/Feed/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use client';

import { useRecommendBookmarkList } from '@/apis/recommend';
import { cn } from '@/lib/utils';
import { usePathname } from 'next/navigation';
import BookmarkCard from '../BookmarkCard';

const Feed = () => {
const pathName = usePathname();

const pathList = ['/login', '/onboarding', '/oauth2/redirect'];

const { data: bookmarkData } = useRecommendBookmarkList();

const handleOpenBlank = ({ url }: { url: string }) => {
window.open(url, '_blank');
};

return (
<>
{!pathList.includes(pathName) && (
<div
className={cn(
'overflow-scroll h-full w-[260px] right-0 flex px-12 pt-40 gap-[14px] flex-col bg-surface',
'border-l border-[#E9E9EA] styled-scroll',
)}
>
<h1 className='heading-lg-bd'>이런 사이트는 어때요?</h1>
<div className='flex flex-col gap-24'>
{bookmarkData?.content.map((item) => (
<BookmarkCard
key={item.bookMarkId}
{...item}
imageUUID={item.userInsertRepresentImage?.uuid}
onClick={() => handleOpenBlank({ url: item.url })}
isRecommendCard={true}
/>
))}
</div>
</div>
)}
</>
);
};

export default Feed;
8 changes: 8 additions & 0 deletions src/lib/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const isValidUrl = (url: string) => {
try {
new URL(url);
return true;
} catch (e) {
return false;
}
};

0 comments on commit f7a7e4b

Please sign in to comment.