Skip to content
15 changes: 15 additions & 0 deletions apps/admin/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,26 @@ const nextConfig: NextConfig = {
hostname: 't1.daumcdn.net',
pathname: '/**',
},
{
protocol: 'https',
hostname: 't1.kakaocdn.net',
pathname: '/**',
},
{
protocol: 'http',
hostname: 't1.kakaocdn.net',
pathname: '/**',
},
{
protocol: 'https',
hostname: 'blog.kakaocdn.net',
pathname: '/**',
},
{
protocol: 'https',
hostname: process.env.NEXT_PUBLIC_API_URL_HOST || '', //테스트용 주소
pathname: '/**',
},
Comment on lines +38 to +42
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

환경변수 미설정 시 빈 문자열 hostname 문제

process.env.NEXT_PUBLIC_API_URL_HOST가 설정되지 않은 경우 빈 문자열이 hostname으로 전달되어 Next.js 이미지 최적화가 실패하거나 예상치 못한 보안 문제가 발생할 수 있습니다.

🔎 제안하는 수정

환경변수가 설정된 경우에만 패턴 추가:

-      {
-        protocol: 'https',
-        hostname: process.env.NEXT_PUBLIC_API_URL_HOST || '', //테스트용 주소
-        pathname: '/**',
-      },
+      ...(process.env.NEXT_PUBLIC_API_URL_HOST
+        ? [
+            {
+              protocol: 'https' as const,
+              hostname: process.env.NEXT_PUBLIC_API_URL_HOST,
+              pathname: '/**',
+            },
+          ]
+        : []),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
protocol: 'https',
hostname: process.env.NEXT_PUBLIC_API_URL_HOST || '', //테스트용 주소
pathname: '/**',
},
...(process.env.NEXT_PUBLIC_API_URL_HOST
? [
{
protocol: 'https' as const,
hostname: process.env.NEXT_PUBLIC_API_URL_HOST,
pathname: '/**',
},
]
: []),
🤖 Prompt for AI Agents
In apps/admin/next.config.ts around lines 43-47, do not pass an empty string as
hostname to Next.js image remotePatterns; instead build the remotePatterns array
dynamically and only push the { protocol: 'https', hostname:
process.env.NEXT_PUBLIC_API_URL_HOST, pathname: '/**' } entry when
process.env.NEXT_PUBLIC_API_URL_HOST is non-empty (truthy). Modify the config to
check the env var (e.g., if (process.env.NEXT_PUBLIC_API_URL_HOST)
remotePatterns.push(...)) so hostname is never an empty string and Next.js image
optimization/security issues are avoided.

],
},
}
Expand Down
19 changes: 14 additions & 5 deletions apps/admin/src/app/requests/[id]/RequestDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import { Banner } from '@repo/ui/components/Banner'
import type { RequestDetail } from './_api/types'
import { CLIENT_PATH } from '@/consts/path'
import { requestReview } from './_api/services/request'
import { Location } from './_components/Location/Location'
import { Menus } from './_components/Menus/Menus'
import { Section } from './_components/Section'
import { Location } from './_components/Location'
import { Menus } from './_components/Menus'
import { Description } from './_components/Description'
import { Tags } from './_components/Tags'
import { ActionButtonGroup } from './_components/ActionButtonGroup'
import { RejectModal } from './_components/RejectModal'

Expand Down Expand Up @@ -70,9 +72,16 @@ export const RequestDetailPage = ({ data }: Props) => {
/>
)}
<Column className={'flex-1 justify-around gap-4 px-5'}>
<Location location={location} />
<Menus menus={menus} />
<Description description={description} tags={tags} />
<Section icon={'pin'} title={'위치'}>
<Location location={location} />
</Section>
<Section icon={'note'} title={'메뉴'}>
<Menus menus={menus} />
</Section>
<Section icon={'smile'} title={'소개'}>
<Description description={description} />
<Tags tags={tags} />
</Section>
<ActionButtonGroup onOpen={onOpen} handleReview={handleReview} />
</Column>
</VerticalScrollArea>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
import { Column, Flex } from '@repo/ui/components/Layout'
import { Chip } from '@repo/ui/components/Chip'
import { Text } from '@repo/ui/components/Text'
import { RequestDetail } from '../../_api/types'
import type { RequestDetail } from '../../_api/types'

type Props = {
description: RequestDetail['description']
tags: RequestDetail['tags']
}

export const Description = ({ description, tags }: Props) => {
export const Description = ({ description }: Props) => {
return (
<Column className={'gap-1.5'}>
<Text>소개</Text>
<Text variant={'body2'} className={'whitespace-pre-wrap'}>
{description}
</Text>
<Flex className={'gap-1'}>
{tags.map((tag) => (
<Chip key={tag.id} icon={tag.iconKey} label={tag.name} />
))}
</Flex>
</Column>
<Text variant={'body2'} className={'whitespace-pre-wrap'}>
{description}
</Text>
)
}
25 changes: 10 additions & 15 deletions apps/admin/src/app/requests/[id]/_components/Location/Location.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { useState } from 'react'
import { Column } from '@repo/ui/components/Layout'
import { Container, Marker, NaverMap } from 'react-naver-maps'
import { Text } from '@repo/ui/components/Text'
import { toLatLng } from '../../_utils/toLatLng'
import type { RequestDetail } from '../../_api/types'

Expand All @@ -14,18 +12,15 @@ export const Location = ({ location }: Props) => {
const setLocation = toLatLng(location)

return (
<Column className={'gap-1.5'}>
<Text>위치</Text>
<Container className={'h-[150px] overflow-hidden rounded-xl'}>
<NaverMap
defaultZoom={18}
minZoom={15}
ref={setMap}
defaultCenter={setLocation}
>
<Marker position={setLocation} icon={'logo'} />
</NaverMap>
</Container>
</Column>
<Container className={'h-[150px] overflow-hidden rounded-xl'}>
<NaverMap
defaultZoom={18}
minZoom={15}
ref={setMap}
defaultCenter={setLocation}
>
<Marker position={setLocation} />
</NaverMap>
</Container>
)
}
75 changes: 36 additions & 39 deletions apps/admin/src/app/requests/[id]/_components/Menus/Menus.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Text } from '@repo/ui/components/Text'
import { Column, VerticalScrollArea } from '@repo/ui/components/Layout'
import { VerticalScrollArea } from '@repo/ui/components/Layout'
import { cn } from '@repo/ui/utils/cn'
import type { RequestDetail } from '@/app/requests/[id]/_api/types'
import { Menu } from './Menu'
Expand All @@ -22,44 +22,41 @@ export const Menus = ({ menus }: Props) => {
)

return (
<Column className={'gap-2.5'}>
<Text>메뉴</Text>
<VerticalScrollArea
className={cn(
'gap-2.5',
'rounded-xl',
'bg-gray-50',
'px-4 py-3',
'max-h-60',
'show-scrollbar',
)}
>
{/*메뉴 존재 유무*/}
{menus.length === 0 && (
<Text
fontSize={'sm'}
fontWeight={'semibold'}
className={'mx-auto my-3'}
>
등록된 메뉴가 존재하지 않습니다
<VerticalScrollArea
className={cn(
'gap-2.5',
'rounded-xl',
'bg-gray-50',
'px-4 py-3',
'max-h-60',
'show-scrollbar',
)}
>
{/*메뉴 존재 유무*/}
{menus.length === 0 && (
<Text
fontSize={'sm'}
fontWeight={'semibold'}
className={'mx-auto my-3'}
>
등록된 메뉴가 존재하지 않습니다
</Text>
)}
{/*추천 메뉴 존재 유무*/}
{recommendedMenu.length > 0 && (
<>
<Text variant={'caption1'} className={'text-gray-300'}>
추천메뉴
</Text>
)}
{/*추천 메뉴 존재 유무*/}
{recommendedMenu.length > 0 && (
<>
<Text variant={'caption1'} className={'text-gray-300'}>
추천메뉴
</Text>
{recommendedMenu.map((menu, index) => (
<Menu key={index} menu={menu} />
))}
<hr className={'w-full border border-gray-200'} />
</>
)}
{unRecommendedMenu.map((menu, index) => (
<Menu key={index} menu={menu} />
))}
</VerticalScrollArea>
</Column>
{recommendedMenu.map((menu, index) => (
<Menu key={index} menu={menu} />
))}
<hr className={'w-full border border-gray-200'} />
</>
)}
{unRecommendedMenu.map((menu, index) => (
<Menu key={index} menu={menu} />
))}
</VerticalScrollArea>
)
}
21 changes: 21 additions & 0 deletions apps/admin/src/app/requests/[id]/_components/Section/Section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Column, Flex } from '@repo/ui/components/Layout'
import { Icon, type IconType } from '@repo/ui/components/Icon'
import { Text } from '@repo/ui/components/Text'

type Props = {
icon: IconType
title: string
children: React.ReactNode
}

export const Section = ({ icon, title, children }: Props) => (
<Column as={'section'} className={'gap-1.5'}>
<Flex className={'gap-1'}>
<Icon type={icon} size={16} />
<Text as={'h2'} variant={'title3'}>
{title}
</Text>
</Flex>
{children}
</Column>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Section } from './Section'
15 changes: 15 additions & 0 deletions apps/admin/src/app/requests/[id]/_components/Tags/Tags.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Flex } from '@repo/ui/components/Layout'
import { Chip } from '@repo/ui/components/Chip'
import type { RequestDetail } from '../../_api/types'

type Props = {
tags: RequestDetail['tags']
}

export const Tags = ({ tags }: Props) => (
<Flex className={'flex-wrap gap-2'}>
{tags.map((tag) => (
<Chip key={tag.id} icon={tag.iconKey} label={tag.name} />
))}
</Flex>
)
1 change: 1 addition & 0 deletions apps/admin/src/app/requests/[id]/_components/Tags/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Tags } from './Tags'
2 changes: 1 addition & 1 deletion apps/web/app/_components/PlaceListItem/PlaceListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const PlaceListItem = ({
{address}
</Text>
{tags.length > 0 && (
<Flex className={'gap-1'}>
<Flex className={'gap-1 overflow-x-auto'}>
{tags.map((tag) => (
<Chip key={tag.id} icon={tag.iconKey} label={tag.name} />
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const SwipeableArea = ({
}

return (
<div className='relative h-full w-full overflow-hidden px-8'>
<div className='relative h-full w-full overflow-x-hidden px-8'>
<motion.div
key={categoryId}
drag='x'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ export const PlaceListItem = ({
>
<Column as={'div'} className={'max-w-2/3'}>
<Flex className={'gap-1'}>
<Text as={'span'} variant={'title2'} className={'flex-1 truncate'}>
<Text as={'span'} variant={'title2'} className={'truncate'}>
{placeName}
</Text>
<Icon type={mainCategoryIcon} size={18} />
<Icon type={mainCategoryIcon} size={18} className={'min-w-4.5'} />
</Flex>
<Text variant={'caption2'} className={'text-gray-300'}>
등록 신청 일자: {requestDate}
Expand Down
6 changes: 5 additions & 1 deletion packages/ui/src/components/Chip/Chip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ export const Chip: ChipType = ({
onClick={onClick}
>
<Icon type={icon} size={16} />
<Text as={'span'} variant={'caption1'} className={'ui:text-gray-300'}>
<Text
as={'span'}
variant={'caption1'}
className={'ui:text-gray-300 ui:text-nowrap'}
>
{label}
</Text>
</Component>
Expand Down