-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] 여행 가이드북 디자인, API 연결(무한 스크롤) #15
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
1732f19
feat: api 설정, 커스텀 훅 추가
wo-o29 e2339e2
feat: ssr 적용
wo-o29 93e8513
feat: api 로직 구현
wo-o29 f0a5f08
feat: 그리드 설정
wo-o29 3ba2c0b
rename: 스타일 파일 확장자 수정
wo-o29 b65589f
feat: 무한 스크롤 구현
wo-o29 8da234b
feat: 데이터 없을 때 보여줄 UI 추가
wo-o29 b192952
feat: 로딩 컴포넌트 추가
wo-o29 0df01ac
feat: 데이터 분기 처리
wo-o29 b4c6348
feat: 글씨 테두리 추가
wo-o29 112b7ae
refactor: 로딩 분기 수정
wo-o29 f6fa61b
style: 로딩 텍스트 디자인 수정
wo-o29 d1ee77b
refactor: 타입 수정
wo-o29 c88c3be
Merge branch 'develop' into feature/guide-book-page
wo-o29 d370d9d
refactor: 악시오스 인스턴스 로직 수정
wo-o29 965e7c8
Merge branch 'develop' into feature/guide-book-page
wo-o29 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { GuideBookType } from "@/types"; | ||
|
||
import { setInstance } from "./axios"; | ||
|
||
export const getGuideBookData = async ( | ||
pageParam: number, | ||
): Promise<GuideBookType> => { | ||
const response = await setInstance( | ||
process.env.NEXT_PUBLIC_GUIDE_BOOK_API_BASE_URL!, | ||
).get( | ||
`/15123631/v1/uddi:33264f0a-158f-4a5d-95cd-99c740c8a097?page=${pageParam}&perPage=20&serviceKey=${process.env.NEXT_PUBLIC_DATA_GO_API_KEY}`, | ||
); | ||
return response.data; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import * as S from "./styled"; | ||
|
||
function Loading() { | ||
return ( | ||
<S.FireworksContainer | ||
autostart={true} | ||
options={{ | ||
particles: 200, // 입자의 수 | ||
traceLength: 10, // 입자의 길이 | ||
traceSpeed: 2, // 입자의 속도 | ||
delay: { min: 100, max: 100 }, // 입자 생성 지연 시간 범위 | ||
brightness: { min: 30, max: 100 }, // 밝기 범위 | ||
decay: { min: 0.01, max: 0.02 }, // 소멸 속도 범위 | ||
}} | ||
> | ||
<S.Container> | ||
<S.Title> | ||
<S.TitleEffect>FestiBook</S.TitleEffect> | ||
</S.Title> | ||
<S.Text> | ||
<S.TextEffect>데이터를 불러오는 중입니다...</S.TextEffect> | ||
</S.Text> | ||
<S.Spinner /> | ||
</S.Container> | ||
</S.FireworksContainer> | ||
); | ||
} | ||
|
||
export default Loading; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import styled from "@emotion/styled"; | ||
import Fireworks from "@fireworks-js/react"; | ||
|
||
import { MOBILE_MEDIA_QUERY } from "@/styles/const"; | ||
|
||
export const FireworksContainer = styled(Fireworks)` | ||
width: 100vw; | ||
height: calc(100vh - 5px); | ||
`; | ||
|
||
export const Container = styled.div` | ||
@font-face { | ||
font-family: "ONE-Mobile-POP"; | ||
src: url("https://fastly.jsdelivr.net/gh/projectnoonnu/[email protected]/ONE-Mobile-POP.woff") | ||
format("woff"); | ||
font-weight: normal; | ||
font-style: normal; | ||
} | ||
|
||
width: 50rem; | ||
min-width: 23.4375rem; | ||
position: fixed; | ||
top: 47%; | ||
left: 50%; | ||
transform: translate(-50%, -50%); | ||
font-family: "ONE-Mobile-POP"; | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
gap: 2rem; | ||
|
||
@media ${MOBILE_MEDIA_QUERY} { | ||
gap: 1rem; | ||
} | ||
`; | ||
|
||
export const Title = styled.p` | ||
font-weight: 800; | ||
font-size: 7rem; | ||
background-clip: text; | ||
background: linear-gradient(to right, #e55d87, #5fc3e4) text; | ||
|
||
@media ${MOBILE_MEDIA_QUERY} { | ||
font-size: 3.25rem; | ||
} | ||
`; | ||
|
||
export const TitleEffect = styled.span` | ||
color: transparent; | ||
-webkit-text-stroke: 0.001px #efefef; | ||
`; | ||
|
||
export const Text = styled.p` | ||
font-weight: 800; | ||
font-size: 3rem; | ||
background: linear-gradient(to right, #e55d87, #5fc3e4) text; | ||
|
||
@media ${MOBILE_MEDIA_QUERY} { | ||
font-size: 1.75rem; | ||
} | ||
`; | ||
|
||
export const TextEffect = styled.span` | ||
letter-spacing: 0.0625rem; | ||
color: transparent; | ||
-webkit-text-stroke: 0.001px #efefef; | ||
`; | ||
|
||
export const Spinner = styled.div` | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
border: 14px solid #e8e8e8; | ||
border-top: 14px solid #ab88af; | ||
border-radius: 50%; | ||
width: 6.25rem; | ||
height: 6.25rem; | ||
animation: spin 1.5s linear infinite; | ||
|
||
@media ${MOBILE_MEDIA_QUERY} { | ||
border: 10px solid #f3f3f3; | ||
border-top: 10px solid #ab88af; | ||
width: 4.375rem; | ||
height: 4.375rem; | ||
} | ||
|
||
@keyframes spin { | ||
0% { | ||
transform: rotate(0deg); /* 시작 각도 */ | ||
} | ||
100% { | ||
transform: rotate(360deg); /* 끝 각도 */ | ||
} | ||
} | ||
`; |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** | ||
* 쿼리 키 팩토리 | ||
* {@link https://tkdodo.eu/blog/effective-react-query-keys} | ||
*/ | ||
|
||
export const GUIDE_BOOK_KEYS = { | ||
all: ["guide-book"] as const, | ||
lists: () => [...GUIDE_BOOK_KEYS.all, "list"] as const, | ||
}; |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { useEffect, useRef } from "react"; | ||
|
||
import { useInfiniteQuery } from "@tanstack/react-query"; | ||
|
||
import { getGuideBookData } from "@/apis/api"; | ||
import { GUIDE_BOOK_KEYS } from "@/constants/queryKey"; | ||
|
||
export const useGetGuideBookData = () => { | ||
const { data, fetchNextPage, hasNextPage, isLoading, isFetching } = | ||
useInfiniteQuery({ | ||
queryKey: GUIDE_BOOK_KEYS.lists(), | ||
queryFn: ({ pageParam }) => getGuideBookData(pageParam), | ||
initialPageParam: 1, | ||
getNextPageParam: (lastPage, allPages) => { | ||
const count = allPages.reduce((acc, cur) => acc + cur.currentCount, 0); | ||
|
||
if (count < lastPage.totalCount) { | ||
const pageParam = lastPage.page + 1; | ||
return pageParam; | ||
} | ||
|
||
return null; | ||
}, | ||
}); | ||
|
||
const observerRef = useRef<HTMLDivElement>(null); | ||
|
||
useEffect(() => { | ||
const observer = new IntersectionObserver( | ||
(entries) => { | ||
if (!entries[0].isIntersecting) { | ||
return; | ||
} | ||
|
||
fetchNextPage(); | ||
}, | ||
{ threshold: 0.5 }, | ||
); | ||
|
||
if (!observerRef.current) { | ||
return; | ||
} | ||
|
||
observer.observe(observerRef.current); | ||
|
||
return () => observer.disconnect(); | ||
}, [fetchNextPage, hasNextPage, isFetching, isLoading]); | ||
|
||
return { | ||
guideBookList: data?.pages, | ||
hasNextPage, | ||
isLoading, | ||
isFetching, | ||
observerRef, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { GuideBookDataListType } from "@/types"; | ||
|
||
import * as S from "./styled"; | ||
|
||
interface GuideBookItemProps { | ||
data: GuideBookDataListType; | ||
} | ||
|
||
function GuideBookItem({ data }: GuideBookItemProps) { | ||
return ( | ||
<S.LinkItem href={data["가이드북 링크"]} target="_blank"> | ||
<p>{`제목: ${data["제목"]}`}</p> | ||
</S.LinkItem> | ||
); | ||
} | ||
|
||
export default GuideBookItem; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import Link from "next/link"; | ||
|
||
import styled from "@emotion/styled"; | ||
|
||
export const LinkItem = styled(Link)` | ||
width: 100%; | ||
height: 18rem; | ||
border: 1px solid #000; | ||
`; | ||
|
||
export const Frame = styled.iframe` | ||
width: 100%; | ||
height: 18rem; | ||
border: 1px solid #000; | ||
`; | ||
|
||
export const Embed = styled.embed` | ||
width: 100%; | ||
height: 18rem; | ||
border: 1px solid #000; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { dehydrate, QueryClient } from "@tanstack/react-query"; | ||
|
||
import { getGuideBookData } from "@/apis/api"; | ||
import Loading from "@/components/Loading"; | ||
import { GUIDE_BOOK_KEYS } from "@/constants/queryKey"; | ||
import { useGetGuideBookData } from "@/hooks/useGetGuideBookData"; | ||
|
||
import GuideBookItem from "./components/GuideBookItem"; | ||
import * as S from "./styled"; | ||
|
||
export const getServerSideProps = async () => { | ||
const queryClient = new QueryClient(); | ||
|
||
try { | ||
await queryClient.prefetchQuery({ | ||
queryKey: GUIDE_BOOK_KEYS.lists(), | ||
queryFn: () => getGuideBookData(1), | ||
}); | ||
|
||
return { | ||
props: { dehydrateState: dehydrate(queryClient) }, | ||
}; | ||
} catch (error) { | ||
return { | ||
props: { dehydrateState: null }, | ||
}; | ||
} | ||
}; | ||
|
||
function GuideBookPage() { | ||
const { hasNextPage, guideBookList, isLoading, isFetching, observerRef } = | ||
useGetGuideBookData(); | ||
|
||
if (isLoading) { | ||
return <Loading />; | ||
} | ||
|
||
return ( | ||
<S.Container> | ||
<S.TitleBox> | ||
<S.Title>여행 가이드북</S.Title> | ||
<S.Line /> | ||
</S.TitleBox> | ||
<S.CountBox>{`총 ${guideBookList ? guideBookList[0].totalCount : 0}건`}</S.CountBox> | ||
{guideBookList && guideBookList.length > 0 ? ( | ||
<S.ListBox> | ||
{guideBookList.map((list) => | ||
list.data.map((data) => ( | ||
<GuideBookItem key={data.제목} data={data} /> | ||
)), | ||
)} | ||
{hasNextPage && !isFetching && <S.Observer ref={observerRef} />} | ||
</S.ListBox> | ||
) : ( | ||
<S.EmptyBox> | ||
<S.LogoImage | ||
src="/icons/logo.svg" | ||
width={400} | ||
height={400} | ||
alt="로고 이미지" | ||
/> | ||
가이드북 데이터가 없습니다. | ||
</S.EmptyBox> | ||
)} | ||
</S.Container> | ||
); | ||
} | ||
|
||
export default GuideBookPage; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
가이드북키 상수로 설정해주신거 좋은것같습니다 ! 👍👍👍👍