diff --git a/.eslintrc.js b/.eslintrc.js index cb854af6..a373fb94 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,6 +30,8 @@ module.exports = { 'react/jsx-props-no-spreading': 'off', 'no-use-before-define': 'off', '@typescript-eslint/no-use-before-define': ['off'], + "react/require-default-props": 'off', + "react/self-closing-comp": 'off', }, settings: { react: { diff --git a/public/icon/plus-icon.svg b/public/icon/plus-icon.svg new file mode 100644 index 00000000..5cedfa23 --- /dev/null +++ b/public/icon/plus-icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/apis/getRecentEpigrams.ts b/src/apis/getRecentEpigrams.ts index 341ebef8..a2fb9f52 100644 --- a/src/apis/getRecentEpigrams.ts +++ b/src/apis/getRecentEpigrams.ts @@ -1,10 +1,10 @@ import type { GetRecentEpigramsResponseType } from '@/schema/recentEpigram'; import httpClient from './index'; -const getRecentEpigrams = async (): Promise => { +const getRecentEpigrams = async (limit: number): Promise => { const response = await httpClient.get('/epigrams', { params: { - limit: 3, + limit, }, }); return response.data; diff --git a/src/components/Emotion/card/EmotionIconCard.tsx b/src/components/Emotion/EmotionCard.tsx similarity index 93% rename from src/components/Emotion/card/EmotionIconCard.tsx rename to src/components/Emotion/EmotionCard.tsx index a230deec..1896f7cd 100644 --- a/src/components/Emotion/card/EmotionIconCard.tsx +++ b/src/components/Emotion/EmotionCard.tsx @@ -1,3 +1,9 @@ +/* + 1개의 감정 아이콘 카드를 랜더링 합니다. + 아이콘의 타입, 상태, 크기, 클릭 이벤트를 관리합니다. + 아이콘 타입과 상태에 따라 아이콘의 모양과 스타일을 조정합니다. + */ + import React from 'react'; import cn from '@/lib/utils'; import Image from 'next/image'; @@ -104,11 +110,4 @@ function EmotionIconCard({ iconType = '감동', state = 'Default', size = 'sm', ); } -EmotionIconCard.displayName = 'EmotionIconCard'; - -// 기본 props 설정 -EmotionIconCard.defaultProps = { - onClick: () => {}, -}; - export default EmotionIconCard; diff --git a/src/components/Emotion/card/EmotionSelector.tsx b/src/components/Emotion/EmotionSelector.tsx similarity index 84% rename from src/components/Emotion/card/EmotionSelector.tsx rename to src/components/Emotion/EmotionSelector.tsx index 29b3f104..5a73639e 100644 --- a/src/components/Emotion/card/EmotionSelector.tsx +++ b/src/components/Emotion/EmotionSelector.tsx @@ -1,5 +1,10 @@ +/* + 여러 개의 EmotionIconCard를 관리합니다. + 사용자 인터페이스에 필요한 상호 작용 로직을 포함합니다. + */ + import React, { useState } from 'react'; -import InteractiveEmotionIconCard from '@/components/Emotion/card/InteractiveEmotionIconCard'; +import EmotionIconCard from '@/components/Emotion/EmotionCard'; import useMediaQuery from '@/hooks/useMediaQuery'; import { EmotionType, EmotionState } from '@/types/EmotionTypes'; @@ -52,7 +57,7 @@ function EmotionSelector() { return (
{(['감동', '기쁨', '고민', '슬픔', '분노'] as const).map((iconType) => ( - handleCardClick(iconType)} /> + handleCardClick(iconType)} /> ))}
); diff --git a/src/components/Emotion/card/InteractiveEmotionIconCard.tsx b/src/components/Emotion/card/InteractiveEmotionIconCard.tsx deleted file mode 100644 index f8448315..00000000 --- a/src/components/Emotion/card/InteractiveEmotionIconCard.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import EmotionIconCard from '@/components/Emotion/card/EmotionIconCard'; -import { InteractiveEmotionIconCardProps } from '@/types/EmotionTypes'; - -// InteractiveEmotionIconCard 컴포넌트 함수 선언 -function InteractiveEmotionIconCard(props: InteractiveEmotionIconCardProps) { - return ; -} - -InteractiveEmotionIconCard.displayName = 'InteractiveEmotionIconCard'; - -export default InteractiveEmotionIconCard; diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 5c893fed..d342347f 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { useRouter } from 'next/router'; import Image from 'next/image'; -import { HeaderProps } from '../../types/Header'; import { useToast } from '../ui/use-toast'; import LOGO_ICON from '../../../public/epigram-icon.png'; import ARROW_LEFT_ICON from '../../../public/icon/arrow-left-icon.svg'; @@ -9,15 +8,28 @@ import PROFILE_ICON from '../../../public/icon/profile-icon.svg'; import SEARCH_ICON from '../../../public/icon/search-icon.svg'; import SHARE_ICON from '../../../public/icon/share-icon.svg'; -// TODO 네비게이션 바를 나타내는 컴포넌트 입니다. -// TODO 상위 컴포넌트에서 Props를 받아 원하는 스타일을 보여줍니다. -// TODO 사용 예시 -// TODO
-// TODO
{}} />; -// TODO icon: 'back'을 사용할 경우 routerPage의 값을 무조건 지정해줘야 합니다. -// TODO isLogo={false}일 경우 insteadOfLogo의 값을 무조건 지정해줘야 합니다. -// TODO isButton 일 경우 textInButton의 값을 무조건 지정해줘야 합니다. -// TODO SHARE_ICON 추가 시 토스트 기능도 사용하려면 해당 컴포넌트 아래 를 추가해주세요. +// NOTE 네비게이션 바를 나타내는 컴포넌트 입니다. +// NOTE 상위 컴포넌트에서 Props를 받아 원하는 스타일을 보여줍니다. +// NOTE 사용 예시 +// NOTE
+// NOTE
{}} />; +// NOTE icon: 'back'을 사용할 경우 routerPage의 값을 무조건 지정해줘야 합니다. +// NOTE isLogo={false}일 경우 insteadOfLogo의 값을 무조건 지정해줘야 합니다. +// NOTE isButton 일 경우 textInButton의 값을 무조건 지정해줘야 합니다. +// NOTE SHARE_ICON 추가 시 토스트 기능도 사용하려면 해당 컴포넌트 아래 를 추가해주세요. + +export interface HeaderProps { + icon: 'back' | 'search' | ''; + routerPage: string; + isLogo: boolean; + insteadOfLogo: string; + isProfileIcon: boolean; + isShareIcon: boolean; + isButton: boolean; + textInButton: string; + disabled: boolean; + onClick: (e: React.MouseEvent) => void; +} function Header({ isLogo, icon, insteadOfLogo, isButton, isProfileIcon, isShareIcon, textInButton, routerPage, disabled, onClick }: HeaderProps) { const router = useRouter(); diff --git a/src/components/main/LoadMoreButton.tsx b/src/components/main/LoadMoreButton.tsx new file mode 100644 index 00000000..4e50a3e2 --- /dev/null +++ b/src/components/main/LoadMoreButton.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import Image from 'next/image'; + +interface LoadMoreButtonProps { + onClick: () => void; +} + +function LoadMoreButton({ onClick }: LoadMoreButtonProps) { + return ( +
{ + if (e.key === 'Enter' || e.key === ' ') { + onClick(); + } + }} + > +
+ plus icon +
+
더보기
+
+ ); +} + +export default LoadMoreButton; diff --git a/src/components/main/RecentEpigram.tsx b/src/components/main/RecentEpigram.tsx index c1dbc97f..251bfb78 100644 --- a/src/components/main/RecentEpigram.tsx +++ b/src/components/main/RecentEpigram.tsx @@ -1,9 +1,22 @@ -import React from 'react'; +import React, { useState } from 'react'; +import { useRouter } from 'next/router'; import useGetRecentEpigrams from '@/hooks/useGetRecentEpigrams'; import EpigramCard from '@/components/Card/EpigramCard'; +import { RecentEpigramType } from '@/schema/recentEpigram'; +import LoadMoreButton from './LoadMoreButton'; function RecentEpigrams() { - const { data, error, isLoading } = useGetRecentEpigrams(); + const router = useRouter(); + const [limit, setLimit] = useState(3); + const { data, error, isLoading } = useGetRecentEpigrams(limit); + + const handleEpigramClick = (id: number) => { + router.push(`/epigrams/${id}`); + }; + + const loadMore = () => { + setLimit((prevLimit) => prevLimit + 5); + }; if (isLoading) return

로딩 중...

; if (error) return

{error.message}

; @@ -11,7 +24,22 @@ function RecentEpigrams() { return (

최신 에피그램

- {data?.list.map((epigram) => )} + {data?.list.map((epigram: RecentEpigramType) => ( +
handleEpigramClick(epigram.id)} + role='button' + tabIndex={0} + onKeyPress={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + handleEpigramClick(epigram.id); + } + }} + > + +
+ ))} + {data && limit < data.totalCount && }
); } diff --git a/src/hooks/useGetRecentEpigrams.ts b/src/hooks/useGetRecentEpigrams.ts index 6b2f26f9..beaaa314 100644 --- a/src/hooks/useGetRecentEpigrams.ts +++ b/src/hooks/useGetRecentEpigrams.ts @@ -2,10 +2,10 @@ import { useQuery } from '@tanstack/react-query'; import getRecentEpigrams from '@/apis/getRecentEpigrams'; import { GetRecentEpigramsResponseType } from '@/schema/recentEpigram'; -const useGetRecentEpigrams = () => +const useGetRecentEpigrams = (limit: number) => useQuery({ - queryKey: ['recentEpigrams', 3], - queryFn: getRecentEpigrams, + queryKey: ['recentEpigrams', limit], + queryFn: () => getRecentEpigrams(limit), }); export default useGetRecentEpigrams; diff --git a/src/types/Header.ts b/src/types/Header.ts deleted file mode 100644 index a75d1fce..00000000 --- a/src/types/Header.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface HeaderProps { - icon: 'back' | 'search' | ''; - routerPage: string; - isLogo: boolean; - insteadOfLogo: string; - isProfileIcon: boolean; - isShareIcon: boolean; - isButton: boolean; - textInButton: string; - disabled: boolean; - onClick: (e: React.MouseEvent) => void; -}