Skip to content

Commit

Permalink
Feat: 커뮤니티 - 여행지 페이지 완성 (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
jihostudy authored Sep 29, 2024
2 parents 49a1472 + 85a3d82 commit 90105e0
Show file tree
Hide file tree
Showing 24 changed files with 1,337 additions and 72 deletions.
17 changes: 15 additions & 2 deletions app/(route)/(header)/community/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
'use client'

import { QueryClientProvider } from '@tanstack/react-query'
import React, { ReactNode } from 'react'

import { queryClient } from '@/lib/HTTP/http'

interface CommunityLayoutProps {
children: React.ReactNode
modal: React.ReactNode
}

const CommunityLayout = ({ children }: CommunityLayoutProps): ReactNode => {
return <div className='mt-24'>{children}</div>
const CommunityLayout = ({ children, modal }: CommunityLayoutProps): ReactNode => {
return (
<div className='mt-24'>
<QueryClientProvider client={queryClient}>
{children}
{modal}
</QueryClientProvider>
</div>
)
}

export default CommunityLayout
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React, { ReactNode } from 'react'

import Loading from '@/components/common/Loading'

interface LoadingPageProps {}

const LoadingPage = ({}: LoadingPageProps): ReactNode => {
return (
<div className='fixed inset-0 z-10 flex items-center justify-center bg-black bg-opacity-40'>
<Loading size={40} />
</div>
)
}

export default LoadingPage
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { ReactNode } from 'react'

import PlaceDetail from '@/components/community/place/PlaceDetail'
import { DetailPlace } from '@/components/community/place/placeType'

interface CommunityPlaceDetailProps {
params: {
placeId: string
}
}

const getPlace = async (placeId: string) => {
try {
const res = await fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}/place?placeId=${placeId}`)

if (!res.ok) {
const error = new Error('An error occurred while fetching places')
error.message = await res.json()
throw error
}

const data = await res.json()
return data
} catch (error) {
console.log(error)
}
}

const CommunityPlaceDetail = async ({ params }: CommunityPlaceDetailProps): Promise<ReactNode> => {
const detailPlace: DetailPlace = await getPlace(params.placeId)

return (
<div className='fixed inset-0 z-10 flex items-center justify-center bg-black bg-opacity-40'>
<div className='relative flex h-4/5 w-3/5 min-w-[600px] flex-col rounded-[30px] border-[1px] border-black bg-white'>
<PlaceDetail place={detailPlace} />
</div>
</div>
)
}

export default CommunityPlaceDetail
3 changes: 3 additions & 0 deletions app/(route)/(header)/community/place/@modal/default.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Default() {
return null
}
15 changes: 15 additions & 0 deletions app/(route)/(header)/community/place/detail/[placeId]/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React, { ReactNode } from 'react'

import Loading from '@/components/common/Loading'

interface LoadingPageProps {}

const LoadingPage = ({}: LoadingPageProps): ReactNode => {
return (
<div className='fixed inset-0 z-10 flex items-center justify-center bg-black bg-opacity-40'>
<Loading size={40} />
</div>
)
}

export default LoadingPage
41 changes: 41 additions & 0 deletions app/(route)/(header)/community/place/detail/[placeId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { ReactNode } from 'react'

import PlaceDetail from '@/components/community/place/PlaceDetail'
import { DetailPlace } from '@/components/community/place/placeType'

interface CommunityPlaceDetailProps {
params: {
placeId: string
}
}

const getPlace = async (placeId: string) => {
try {
const res = await fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}/place?placeId=${placeId}`)

if (!res.ok) {
const error = new Error('An error occurred while fetching places')
error.message = await res.json()
throw error
}

const data = await res.json()
return data
} catch (error) {
console.log(error)
}
}

const CommunityPlaceDetail = async ({ params }: CommunityPlaceDetailProps): Promise<ReactNode> => {
const detailPlace: DetailPlace = await getPlace(params.placeId)

return (
<div className='fixed inset-0 z-10 flex items-center justify-center bg-black bg-opacity-40'>
<div className='relative flex h-4/5 w-3/5 min-w-[600px] flex-col rounded-[30px] border-[1px] border-black bg-white'>
<PlaceDetail place={detailPlace} />
</div>
</div>
)
}

export default CommunityPlaceDetail
17 changes: 17 additions & 0 deletions app/(route)/(header)/community/place/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, { ReactNode } from 'react'

interface CommunityPlaceLayoutProps {
children: React.ReactNode
modal: React.ReactNode
}

const CommunityPlaceLayout = ({ children, modal }: CommunityPlaceLayoutProps): ReactNode => {
return (
<div>
{children}
{modal}
</div>
)
}

export default CommunityPlaceLayout
2 changes: 1 addition & 1 deletion app/(route)/(header)/community/place/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface CommunityPlacePageProps {}
const CommunityPlacePage = ({}: CommunityPlacePageProps): ReactNode => {
return (
<div className='flex h-screen w-full justify-center'>
<div className='flex h-screen w-[80%] flex-col'>
<div className='flex h-screen w-[80%] max-w-[1400px] flex-col'>
<PlaceBanner />
<PopularPlace />
<PlaceFilter />
Expand Down
14 changes: 11 additions & 3 deletions components/common/KakaoMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import { colorSet, ColorType } from '@/public/colors/colors'

import { MAP_MARKER_COLORS, SpriteMapMarker } from './MapPin'

const KakaoMap = (): ReactNode => {
type KakaoMapProps = {
modalLat?: number
modalLng?: number
}

const KakaoMap = ({ modalLat, modalLng }: KakaoMapProps): ReactNode => {
useKakaoLoader() // 카카오 지도 로딩
const { pins, center, focusedPlacePin } = useMapStore()

Expand All @@ -27,8 +32,8 @@ const KakaoMap = (): ReactNode => {
id='map'
center={{
// 지도의 중심좌표
lat: center.latitude,
lng: center.longitude,
lat: modalLat || center.latitude,
lng: modalLng || center.longitude,
}}
isPanto={true}
style={{
Expand All @@ -37,6 +42,9 @@ const KakaoMap = (): ReactNode => {
}}
level={6} // 지도의 확대 레벨
>
{modalLat && modalLng && (
<SpriteMapMarker geo={{ latitude: modalLat, longitude: modalLng }} order={0} id='focus' />
)}
{pins?.map((dayPin, dayPinIndex) =>
dayPin.map((pin, index) => <SpriteMapMarker key={index} geo={pin} day={dayPinIndex} order={index} id='pins' />),
)}
Expand Down
8 changes: 5 additions & 3 deletions components/common/Loading.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React, { ReactNode } from 'react'

import LucideIcon from '@/lib/icons/LucideIcon'
interface LoadingProps {}
const Loading = ({}: LoadingProps): ReactNode => {
return <LucideIcon name='LoaderCircle' className='animate-spin' size={16} />
interface LoadingProps {
size?: number
}
const Loading = ({ size }: LoadingProps): ReactNode => {
return <LucideIcon name='LoaderCircle' className='animate-spin' size={size || 16} />
}

export default Loading
36 changes: 20 additions & 16 deletions components/community/place/PlaceBanner.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
import Image from 'next/image'
import React, { ReactNode } from 'react'

import BusanImg from '@/public/images/busan.jpg'
import { cn } from '@/lib/utils/cn'
import communityPlaceImg from '@/public/images/communityPlaceImg.jpg'

interface PlaceBannerProps {}

const PlaceBanner = ({}: PlaceBannerProps): ReactNode => {
return (
<>
<p className='my-5'>{`홈 > 커뮤니티 > 여행지`}</p>
<div className='flex gap-20'>
<Image src={BusanImg} alt='BusanImg' height={400} className='rounded-md' />
<div className='flex flex-col justify-center gap-6 text-xl'>
<div>
<div className='text-4xl'>✏️</div>
<p>다양한 여행지를 둘러보세요.</p>
</div>
<div>
<div className='text-4xl'>🔖</div>
<p>여행하고 싶은 곳을 저장해두세요.</p>
</div>
<div>
<div className='text-4xl'>✉️</div>
<p>유명 여행지를 동행인에게 공유해보세요.</p>
</div>
<div className='flex items-center justify-center gap-16 max-[1200px]:flex-col max-[1200px]:items-center max-[1200px]:gap-10'>
<Image
src={communityPlaceImg}
alt='BusanImg'
height={400}
width={600}
className={cn('rounded-md shadow-tb-shadow')}
/>
<div className='flex flex-col justify-center gap-20 text-xl max-[1200px]:gap-10'>
<p className='text-3xl font-semibold'>
다양한 <span className='text-tbPrimaryHover'>여행지</span>를 둘러보세요
</p>
<p className='ml-28 text-3xl font-semibold'>
<span className='text-tbPrimaryHover'>여행하고 싶은 곳</span>을 저장해두세요
</p>
<p className='text-3xl font-semibold'>
유명 여행지를 <span className='text-tbPrimaryHover'>동행인</span>에게 공유해보세요
</p>
</div>
</div>
</>
Expand Down
54 changes: 54 additions & 0 deletions components/community/place/PlaceCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Image from 'next/image'
import Link from 'next/link'
import React, { ReactNode } from 'react'

import { PLACE_DEFAULT_IMAGE } from '@/lib/constants/dummy_data'
import LucideIcon from '@/lib/icons/LucideIcon'
import { removeTagsAndParentheses } from '@/lib/utils/stringUtils'
import BusanImg from '@/public/images/busan.jpg'

import { CommunityPlace } from './placeType'

interface PlaceCardProps {
place: CommunityPlace
commentsNum: number
}

const PlaceCard = ({ place, commentsNum }: PlaceCardProps): ReactNode => {
return (
<Link
href={`/community/place/detail/${place.placeId}`}
scroll={false}
className='block h-[95%] w-[90%] rounded-lg p-3 shadow-tb-shadow hover:scale-105 hover:cursor-pointer'
>
<Image
src={place.imgSrc || PLACE_DEFAULT_IMAGE || BusanImg}
alt='BusanImg'
width={200}
height={200}
quality={100}
className='mb-2 h-2/3 w-full rounded-lg'
/>
<div className='flex flex-col justify-between pl-2'>
<h2 className='truncate text-lg font-medium'>{removeTagsAndParentheses(place.placeName)}</h2>
<p># {place.category}</p>
<div className='flex gap-3'>
<div className='flex items-center gap-1'>
<LucideIcon name='Star' fill='tbPrimary' strokeWidth={0} />
<p>{place.star}</p>
</div>
<div className='flex items-center gap-1'>
<LucideIcon name='Bookmark' strokeWidth={3} />
<p>{place.scrapped || 0}</p>
</div>
<div className='flex items-center gap-1'>
<LucideIcon name='MessageCircle' strokeWidth={3} />
<p>{commentsNum || 0}</p>
</div>
</div>
</div>
</Link>
)
}

export default PlaceCard
Loading

0 comments on commit 90105e0

Please sign in to comment.