Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b3dd347
feat: 레이아웃 컴포넌트에서 폰트를 Pretendard로 변경하고 스타일 적용
leeleeleeleejun Oct 5, 2025
1c7acbd
feat: 캠퍼스별 요청 목록 컴포넌트 추가 및 메인 페이지 레이아웃 구성
leeleeleeleejun Oct 9, 2025
c2ea5b3
feat: API 및 클라이언트 경로 상수 추가
leeleeleeleejun Oct 9, 2025
b0b1db8
feat: RequestListItem 컴포넌트에 상세 페이지 이동 링크 추가 및 placeId 프로퍼티 추가
leeleeleeleejun Oct 9, 2025
967898b
feat: Banner component를 packages프로젝트(디자인 시스템)으로 이동
leeleeleeleejun Oct 9, 2025
1388211
feat: Banner 컴포넌트의 tailwind 클래스 이름에 prefix 'ui:' 추가
leeleeleeleejun Oct 9, 2025
3ae0ffc
chore: web 프로젝트의 package.json에서 keen-slider 의존성 삭제
leeleeleeleejun Oct 9, 2025
ee1d102
feat: RequestsByCampus 컴포넌트에 MOCK_DATA를 사용하여 요청 목록 리팩토링
leeleeleeleejun Oct 9, 2025
a338f35
chore: react-naver-maps와 @types/navermaps를 catalog로 관리하도록 package.jso…
leeleeleeleejun Oct 10, 2025
c1456e6
feat: RequestDetail type 정의
leeleeleeleejun Oct 11, 2025
2bf4d4e
feat: ActionButtonGroup component 추가
leeleeleeleejun Oct 11, 2025
bb38dda
feat: Description 컴포넌트 추가
leeleeleeleejun Oct 11, 2025
5a09419
feat: Menus 및 Menu 컴포넌트 추가
leeleeleeleejun Oct 11, 2025
e232559
refactor: @repo/utils 생성 및 toLatLng.ts를 @repo/utils으로 이동
leeleeleeleejun Oct 11, 2025
c8a20bc
feat: NaverMapProvider 컴포넌트 추가
leeleeleeleejun Oct 11, 2025
02bceeb
refactor: @repo/utils 생성 및 toLatLng.ts를 @repo/utils으로 이동 추가
leeleeleeleejun Oct 11, 2025
94a59e2
feat: Location 컴포넌트 추가
leeleeleeleejun Oct 11, 2025
ebcc0ee
feat: RequestDetailPage 컴포넌트 추가
leeleeleeleejun Oct 11, 2025
8131e9e
chore: apps/admin에 hreoUI 라이브러리 설치 및 설정
leeleeleeleejun Oct 11, 2025
4465c40
feat: RejectModal 컴포넌트 추가
leeleeleeleejun Oct 11, 2025
f1418c0
refactor: API_PATH 앞에 / 추가
leeleeleeleejun Oct 11, 2025
5038e66
refactor: Request type 위치 이동
leeleeleeleejun Oct 11, 2025
b85a8ae
refactor: packages/utils 삭제
leeleeleeleejun Oct 12, 2025
0a4073c
refactor: tsconfig.json에 rootDir 추가
leeleeleeleejun Oct 12, 2025
6cd082b
refactor: components폴더 app/_components로 변경 및 이동
leeleeleeleejun Oct 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion apps/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
"react": "catalog:",
"react-dom": "catalog:",
"next": "catalog:",
"@repo/ui": "workspace:*"
"@heroui/react": "catalog:",
"@heroui/system": "catalog:",
"@heroui/theme": "catalog:",
"@repo/ui": "workspace:*",
"react-naver-maps": "catalog:"
},
"devDependencies": {
"@next/eslint-plugin-next": "catalog:",
Expand All @@ -26,6 +30,7 @@
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"@tailwindcss/postcss": "catalog:",
"@types/navermaps": "catalog:",
"postcss": "catalog:",
"tailwindcss":"catalog:",
"autoprefixer": "catalog:",
Expand Down
Binary file added apps/admin/public/fonts/PretendardVariable.woff2
Binary file not shown.
10 changes: 10 additions & 0 deletions apps/admin/src/app/NaverMapProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use client'

import { NavermapsProvider } from 'react-naver-maps'
import { ReactNode } from 'react'

export const NaverMapProvider = ({ children }: { children: ReactNode }) => {
const ncpKeyId = process.env.NEXT_PUBLIC_NAVER_MAP_ID || ''
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

환경 변수 누락 시 처리 검증 필요

NEXT_PUBLIC_NAVER_MAP_ID가 설정되지 않은 경우 빈 문자열이 전달됩니다. Naver Maps API가 빈 문자열을 허용하는지, 아니면 런타임 오류가 발생할 수 있는지 확인하세요. 필요한 경우 환경 변수가 누락되었을 때 경고를 표시하거나 에러를 던지는 것을 고려하세요.

다음 스크립트로 환경 변수 설정을 확인할 수 있습니다:


🏁 Script executed:

#!/bin/bash
# Description: Check for NEXT_PUBLIC_NAVER_MAP_ID usage and .env configuration

# Search for environment variable references
rg -n "NEXT_PUBLIC_NAVER_MAP_ID" --type-add 'env:*.env*' --type env

# Check if .env files exist and contain the variable
fd -e env -e env.local -e env.development --exec cat {}

Length of output: 148


다음 스크립트로 코드와 .env* 파일에서 NEXT_PUBLIC_NAVER_MAP_ID 사용 및 정의 여부를 확인하세요.


🏁 Script executed:

#!/bin/bash
echo "1) 코드에서 process.env.NEXT_PUBLIC_NAVER_MAP_ID 사용 검색"
rg -nP "process\.env\.NEXT_PUBLIC_NAVER_MAP_ID"

echo "2) 코드에서 NEXT_PUBLIC_NAVER_MAP_ID 문자 검색"
rg -n "NEXT_PUBLIC_NAVER_MAP_ID"

echo "3) 리포지토리 루트 및 하위에서 숨김 .env* 파일 목록"
fd --hidden --glob ".env*" --max-depth 2

echo "4) .env* 파일에서 변수 정의 검색"
fd --hidden --glob ".env*" --max-depth 2 -x grep -Hn "NEXT_PUBLIC_NAVER_MAP_ID" {}

Length of output: 550


환경 변수 필수 설정 및 누락 처리
현재 process.env.NEXT_PUBLIC_NAVER_MAP_ID.env*에 정의되어 있지 않아 빈 문자열이 기본값으로 할당됩니다. 빌드/배포 환경에서 반드시 해당 변수를 설정하도록 보장하거나, 누락 시 예외를 던지거나 명확한 에러 메시지를 표시하도록 처리하세요.

🤖 Prompt for AI Agents
In apps/admin/src/app/NaverMapProvider.tsx around line 7, the assignment const
ncpKeyId = process.env.NEXT_PUBLIC_NAVER_MAP_ID || '' silently falls back to an
empty string when the env var is missing; change this to validate presence at
startup and fail fast: read process.env.NEXT_PUBLIC_NAVER_MAP_ID, and if it's
undefined/empty throw a clear Error (or process.exit with a logged error) that
includes the variable name and instructions to set it, so builds/deploys will
fail when the required env var is not provided.


return <NavermapsProvider ncpKeyId={ncpKeyId}>{children}</NavermapsProvider>
}
8 changes: 8 additions & 0 deletions apps/admin/src/app/_api/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { IconType } from '@repo/ui/components/Icon'

export type Request = {
placeId: string
placeName: string
icon: IconType
requestDate: string
}
31 changes: 31 additions & 0 deletions apps/admin/src/app/_components/RequestListItem/RequestListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Column, Flex } from '@repo/ui/components/Layout'
import { cn } from '@repo/ui/utils/cn'
import { Text } from '@repo/ui/components/Text'
import { Icon } from '@repo/ui/components/Icon'
import { CLIENT_PATH } from '@/consts/path'
import { Request } from '@/app/_api/types'

export const RequestListItem = ({
placeId,
placeName,
icon,
requestDate,
}: Request) => (
<li>
<Column
as={'a'}
href={CLIENT_PATH.REQUEST_DETAIL(placeId)}
className={cn('gap-1', 'py-3.5', 'border-b-1 border-gray-50')}
>
<Flex className={'gap-1'}>
<Text as={'span'} variant={'title2'}>
{placeName}
</Text>
<Icon type={icon} size={18} />
</Flex>
<Text variant={'caption2'} className={'text-gray-200'}>
등록 신청 일자: {requestDate}
</Text>
</Column>
</li>
)
1 change: 1 addition & 0 deletions apps/admin/src/app/_components/RequestListItem/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { RequestListItem } from './RequestListItem'
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Column } from '@repo/ui/components/Layout'
import { Text } from '@repo/ui/components/Text'
import { CAMPUS, type CampusType } from '@/consts/campus'
import { RequestListItem } from '@/app/_components/RequestListItem'
import { Request } from '@/app/_api/types'

type Props = {
campus: CampusType
requestList: Request[]
}

export const RequestsByCampus = ({ campus, requestList }: Props) => (
<Column as={'section'} className={'gap-1'}>
<Text variant={'heading2'} className={'text-main'}>
{CAMPUS[campus]}캠
</Text>
<ul>
{requestList.map((request) => (
<RequestListItem key={request.placeName} {...request} />
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

고유하지 않을 수 있는 key 사용

placeName을 key로 사용하고 있는데, 이름이 중복될 수 있어 React의 key prop 요구사항을 위반할 수 있습니다. placeId가 고유 식별자라면 이를 key로 사용하는 것이 더 적합합니다.

다음 diff를 적용하여 placeId를 key로 사용하세요:

-        <RequestListItem key={request.placeName} {...request} />
+        <RequestListItem key={request.placeId} {...request} />
📝 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
<RequestListItem key={request.placeName} {...request} />
<RequestListItem key={request.placeId} {...request} />
🤖 Prompt for AI Agents
In apps/admin/src/components/RequestsByCampus/RequestsByCampus.tsx around line
19, the code uses request.placeName as the React key which may not be unique;
replace it with request.placeId (the unique identifier) as the key to satisfy
React's key requirements and prevent rendering issues—ensure placeId is present
on request (or use a stable fallback only if absolutely necessary).

))}
</ul>
</Column>
)
1 change: 1 addition & 0 deletions apps/admin/src/app/_components/RequestsByCampus/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { RequestsByCampus } from './RequestsByCampus'
4 changes: 3 additions & 1 deletion apps/admin/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
@import "tailwindcss";
@import "@repo/tailwind-config";
@import "@repo/tailwind-config";
@plugin './hero.ts';
@source '../../node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}';
4 changes: 4 additions & 0 deletions apps/admin/src/app/hero.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { heroui } from '@heroui/theme'
import type { Config } from 'tailwindcss'

export default heroui() as Config
37 changes: 21 additions & 16 deletions apps/admin/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
import './globals.css'
import '@repo/ui/styles.css'
import type { Metadata } from 'next'
import { Geist, Geist_Mono } from 'next/font/google'

const geistSans = Geist({
variable: '--font-geist-sans',
subsets: ['latin'],
})

const geistMono = Geist_Mono({
variable: '--font-geist-mono',
subsets: ['latin'],
})
import localFont from 'next/font/local'
import { HeroUIProvider } from '@heroui/system'
import { Column } from '@repo/ui/components/Layout'
import { NaverMapProvider } from '@/app/NaverMapProvider'

export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}

const pretendard = localFont({
src: '../../public/fonts/PretendardVariable.woff2',
display: 'swap',
weight: '45 920',
})

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<html lang='en'>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{children}
<html lang='ko' suppressHydrationWarning={true}>
<body className={pretendard.className}>
<HeroUIProvider>
<NaverMapProvider>
<div className={'flex h-svh justify-center bg-[#FEFCF9]'}>
<Column className={'relative w-full max-w-[450px] bg-white'}>
{children}
</Column>
</div>
</NaverMapProvider>
</HeroUIProvider>
</body>
</html>
)
Expand Down
40 changes: 33 additions & 7 deletions apps/admin/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
import { Column } from '@repo/ui/components/Layout'
import { Text } from '@repo/ui/components/Text'
import { Button } from '@repo/ui/components/Button'
import { VerticalScrollArea } from '@repo/ui/components/Layout'
import { RequestsByCampus } from './_components/RequestsByCampus'
import { OnlyLeftHeader } from '@repo/ui/components/Header'
import type { Request } from './_api/types'

const MOCK_DATA: Request[] = [
{
placeId: '1',
placeName: '짬뽕집',
icon: 'chinese',
requestDate: '2025-10-29',
},
{
placeId: '2',
placeName: '짬뽕집',
icon: 'chinese',
requestDate: '2025-10-29',
},
{
placeId: '3',
placeName: '짬뽕집',
icon: 'chinese',
requestDate: '2025-10-29',
},
]

export default function Home() {
return (
<Column>
<Text variant={'heading1'}>Hello World!</Text>
<Button size={'medium'}>버튼</Button>
</Column>
<>
<OnlyLeftHeader icon={'logo'} name={'대기중'} />
<VerticalScrollArea className={'gap-10 p-5'}>
<RequestsByCampus campus={'SINGWAN'} requestList={MOCK_DATA} />
<RequestsByCampus campus={'CHEANAN'} requestList={MOCK_DATA} />
<RequestsByCampus campus={'YESAN'} requestList={MOCK_DATA} />
</VerticalScrollArea>
</>
)
}
82 changes: 82 additions & 0 deletions apps/admin/src/app/request/[id]/RequestDetailPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
'use client'

import { Header } from '@repo/ui/components/Header'
import { Icon } from '@repo/ui/components/Icon'
import { Text } from '@repo/ui/components/Text'
import { Column, VerticalScrollArea } from '@repo/ui/components/Layout'
import { Banner } from '@repo/ui/components/Banner'

import { Location } from './_components/Location/Location'
import { Menus } from './_components/Menus/Menus'
import { Description } from './_components/Description'
import { ActionButtonGroup } from './_components/ActionButtonGroup'
import { useDisclosure } from '@heroui/react'
import { RejectModal } from '@/app/request/[id]/_components/RejectModal'
import { useRouter } from 'next/navigation'

export const RequestDetailPage = () => {
const { isOpen, onOpen, onOpenChange } = useDisclosure()
const { back } = useRouter()

return (
<>
<Header
left={
<button onClick={back}>
<Icon type={'arrowLeft'} />
</button>
}
center={<Text variant={'heading2'}>우돈탄 다산본점</Text>}
/>
<VerticalScrollArea className={'flex-1 py-5'}>
<Banner contents={[]} />
<Column className={'flex-1 justify-around gap-4 px-5'}>
<Location />
<Menus
menus={[
{
name: '짬뽕',
price: 20000,
isRecommended: false,
},
{
name: '짬뽕',
price: 20000,
isRecommended: false,
},
{
name: '짬뽕',
price: 20000,
isRecommended: false,
},
{
name: '짬뽕',
price: 20000,
isRecommended: false,
},
{
name: '짬뽕',
price: 20000,
isRecommended: false,
},
{
name: '짬뽕',
price: 20000,
isRecommended: false,
},
]}
/>
<Description
description={
'직원이 엄청 친절해요! 👍🏻\n' +
'근데 화장실에 좁고 냄새나요 ㅠㅠ\n' +
'그래도 짬뽕 양도 많고 불맛 나서 괜춘'
}
/>
<ActionButtonGroup onOpen={onOpen} />
</Column>
</VerticalScrollArea>
<RejectModal isOpen={isOpen} onOpenChange={onOpenChange} />
</>
)
}
31 changes: 31 additions & 0 deletions apps/admin/src/app/request/[id]/_api/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { IconType } from '@repo/ui/components/Icon'
import { Coord } from '../_utils/toLatLng'

type Photo = { photoId: string; photoUrl: string; displayOrder: number }

type Menu = { name: string; price: number; isRecommended: boolean }

type Category = {
id: string
name: string
iconKey: IconType
}

type Tag = {
id: string
name: string
iconKey: IconType
}

export type RequestDetail = {
placeId: string
placeName: string
requestDate: string
photos: Photo[]
address: string
location: Coord
description: string
menus: Menu[]
categories: Category[]
tags: Tag[]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Flex } from '@repo/ui/components/Layout'
import { cn } from '@repo/ui/utils/cn'
import { COLOR_VARIANTS } from '@repo/ui/consts/colorVariant'

type Props = {
onOpen: VoidFunction
}

export const ActionButtonGroup = ({ onOpen }: Props) => (
<Flex className={'gap-10'}>
<button
onClick={onOpen}
className={cn(
'w-full',
'rounded-lg',
'py-2',
COLOR_VARIANTS.red.text,
COLOR_VARIANTS.red.background,
)}
>
거절
</button>
<button
className={cn(
'w-full',
'rounded-lg',
'py-2',
COLOR_VARIANTS.blue.text,
COLOR_VARIANTS.blue.background,
)}
>
등록
</button>
</Flex>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ActionButtonGroup } from './ActionButtonGroup'
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Column } from '@repo/ui/components/Layout'
import { Chip } from '@repo/ui/components/Chip'
import { Text } from '@repo/ui/components/Text'
import { RequestDetail } from '../../_api/types'

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

export const Description = ({ description }: Props) => {
return (
<Column className={'gap-1.5'}>
<Text>소개</Text>
<Text variant={'body2'} className={'whitespace-pre-wrap'}>
{description}
</Text>
<div>
<Chip icon={'calculator'} label={'가성비 좋은'} />
</div>
</Column>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Description } from './Description'
Loading