Skip to content

Feat/#111 맛집 상세 페이지에 네이버 지도 및 카카오택시 딥링크 기능 추가#112

Merged
leeleeleeleejun merged 8 commits intodevelopfrom
feat/#111
Feb 18, 2026
Merged

Feat/#111 맛집 상세 페이지에 네이버 지도 및 카카오택시 딥링크 기능 추가#112
leeleeleeleejun merged 8 commits intodevelopfrom
feat/#111

Conversation

@leeleeleeleejun
Copy link
Member

@leeleeleeleejun leeleeleeleejun commented Feb 18, 2026

#️⃣연관된 이슈

📝작업 내용

맛집 상세 페이지에 네이버 지도와 카카오택시 딥링크 기능을 추가하고, 모바일/데스크톱 환경에 따라 적절하게 동작하도록 구현했습니다.

1. 네이버 지도 딥링크 기능 추가 (openNaverMap)

모바일 : 네이버 지도 앱 실행 → 앱 없으면 웹으로 폴백
데스크톱 : 네이버 지도 웹 페이지 새 탭으로 열기

2. 카카오택시 딥링크 기능 추가

모바일 : 카카오택시 앱 실행 → 앱 없으면 앱스토어로 이동
데스크톱 : 토스트 메시지로 모바일 전용 안내

3. 딥링크 공통 로직 캡슐화

문제점
앱 실행 후 돌아왔을 때 타임아웃이 실행되어 폴백 URL로도 이동하는 버그 발생

해결

  • openDeepLink 공통 함수 구현 (apps/web/app/_utils/openDeepLink/)
  • visibilitychange 이벤트로 앱 실행 감지
  • 앱으로 전환되면 폴백 타임아웃 자동 취소

스크린샷 (선택)

2026-02-19.1.43.48.mov

💬리뷰 요구사항(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 위치 상세 화면에 카카오택시 및 네이버 지도 바로가기 버튼 추가
    • 장소 미리보기 및 장소 등록 화면에 지도가 포함된 위치 미리보기 컴포넌트 추가
    • 모바일에서 외부 앱으로 이동하는 딥링크 지원 및 자동 대체(스토어/웹) 동작 추가
    • 모바일 기기(iOS/Android) 감지로 플랫폼별 동작 최적화

- 네이버 지도 앱/웹으로 이동하는 openNaverMap 유틸 함수 구현
- Location 컴포넌트에 네이버 지도로 이동 버튼 추가 (지도 우측 상단)
- 모바일: 네이버 지도 앱 실행 (미설치 시 웹으로 폴백)
- 데스크톱: 네이버 지도 웹 페이지를 새 탭으로 열기
- 장소명과 좌표를 파라미터로 전달하여 정확한 위치 표시
- 카카오택시 앱으로 이동하는 openKakaoTaxi 유틸 함수 구현
- Location 컴포넌트에 카카오택시 호출 버튼 추가 (지도 우측 상단)
- 모바일: 카카오택시 앱 실행 (미설치 시 앱스토어로 이동)
- 데스크톱: 모바일 전용 안내 토스트 메시지 표시
- MapButton 컴포넌트로 리팩토링하여 네이버 지도와 카카오택시 버튼 통합
- 버튼 세로 배치 및 hover 효과 추가 (scale-105)
- openDeepLink 유틸 함수 추가: 앱 실행 감지 및 폴백 처리 로직 캡슐화
- visibilitychange 이벤트로 앱 실행 감지 후 타임아웃 취소 -> 앱이 열리면 폴백 URL로 이동하지 않도록 개선
- device 유틸 함수 추가: isMobileDevice, isIOSDevice 함수로 중복 제거
- 각 URL 생성 로직 분리
@leeleeleeleejun leeleeleeleejun self-assigned this Feb 18, 2026
@leeleeleeleejun leeleeleeleejun linked an issue Feb 18, 2026 that may be closed by this pull request
2 tasks
@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

Walkthrough

모바일 감지 유틸리티와 딥링크 핸들러를 추가하고, 네이버맵·카카오택시 연동 유틸 및 Location 컴포넌트(장소명 전달, 버튼 오버레이)를 도입합니다.

Changes

Cohort / File(s) Summary
기기 감지 유틸리티
apps/web/app/_utils/device/device.ts, apps/web/app/_utils/device/index.ts
모바일 및 iOS 판별 함수 isMobileDevice, isIOSDevice 추가 및 재내보내기.
딥링크 처리
apps/web/app/_utils/openDeepLink/openDeepLink.ts, apps/web/app/_utils/openDeepLink/index.ts
앱 스킴으로 이동하고 visibility + 타임아웃 기반 폴백을 수행하는 openDeepLink 구현 및 재내보내기.
지도 앱 통합
apps/web/app/_utils/openKakaoTaxi/openKakaoTaxi.ts, apps/web/app/_utils/openKakaoTaxi/index.ts, apps/web/app/_utils/openNaverMap/openNaverMap.ts, apps/web/app/_utils/openNaverMap/index.ts
카카오택시·네이버맵용 URL 빌드 및 모바일에서는 딥링크(앱/스토어 폴백), 데스크톱에서는 웹 오픈/토스트 동작 구현.
장소 상세 Location 컴포넌트
apps/web/app/places/[id]/_components/Location/Location.tsx, apps/web/app/places/[id]/PlaceDetailPage.tsx
Location 컴포넌트에 placeName prop 추가, 지도 우상단에 카카오택시·네이버맵 버튼 오버레이 및 핸들러 연결.
새 장소 페이지 Location 변경
apps/web/app/places/new/_components/Step/PlacePreview/Location.tsx, apps/web/app/places/new/_components/Step/PlacePreview/PlacePreview.tsx
새로운 로컬 Location 컴포넌트 추가(지도 렌더링) 및 PlacePreview의 import 경로를 지역 상대 경로로 변경.
요청 상세 페이지 업데이트
apps/web/app/requests/[id]/RequestDetailPage.tsx
Location 호출 시 placeName prop 전달 추가.

Sequence Diagram

sequenceDiagram
    actor User as 사용자
    participant Web as 웹 앱
    participant Device as 기기 감지
    participant DeepLink as 딥링크 핸들러
    participant App as 지도 앱
    participant Fallback as 폴백 URL

    User->>Web: 지도/택시 버튼 클릭
    Web->>Device: isMobileDevice() 호출

    alt 모바일
        Web->>DeepLink: openDeepLink({appScheme, fallbackUrl, timeout})
        DeepLink->>DeepLink: visibilitychange 리스너 등록 및 타이머 시작
        DeepLink->>App: location.href = appScheme (네이티브 앱 시도)
        alt 앱 실행됨 (document.hidden)
            DeepLink->>DeepLink: 타이머 취소, 리스너 제거
        else 앱 미설치/미실행
            DeepLink->>Fallback: 타임아웃 후 fallbackUrl로 이동
        end
    else 데스크톱
        Web->>Fallback: 웹 URL 새 탭/토스트 표시
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

✨ Feature, 🔨 Refactor

Poem

🐰 딥링크 따라 폴짝폴짝 뛰네
지도에 별 찍고 택시 불러요 🚕
기기 보고 길을 정하고
앱 없으면 친절히 웹으로 안내해요
작은 당근 한 입, 배포 축하해요 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 주요 변경 사항을 정확하게 반영합니다. 맛집 상세 페이지에 네이버 지도 및 카카오택시 딥링크 기능 추가라는 핵심 변경 내용을 명확하게 설명합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#111

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (10)
apps/web/app/_utils/device/device.ts (2)

10-16: SSR 환경에서 navigator 접근 시 에러 가능성

Next.js는 서버에서도 코드를 실행할 수 있으며, navigator는 서버 환경에 존재하지 않습니다. 현재 호출처가 클릭 핸들러(클라이언트 전용)이기에 당장 문제가 되지 않을 수 있지만, 방어적으로 가드를 추가하면 안전합니다.

🛡️ 방어 코드 제안
 export const isMobileDevice = (): boolean =>
-  MOBILE_REGEX.test(navigator.userAgent)
+  typeof navigator !== 'undefined' && MOBILE_REGEX.test(navigator.userAgent)

 export const isIOSDevice = (): boolean =>
-  IOS_REGEX.test(navigator.userAgent)
+  typeof navigator !== 'undefined' && IOS_REGEX.test(navigator.userAgent)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/_utils/device/device.ts` around lines 10 - 16, isMobileDevice
and isIOSDevice access navigator.userAgent which will throw in SSR; add a
defensive guard that checks for navigator/window existence (e.g., typeof
navigator !== 'undefined' or typeof window !== 'undefined') and fall back to an
empty string before running MOBILE_REGEX.test or IOS_REGEX.test so both
functions safely return false in non-browser environments.

4-5: iPadOS 13+ 감지 누락 가능성

iPadOS 13부터 iPad의 userAgent가 데스크톱 Safari(Macintosh)로 보고되어, MOBILE_REGEXIOS_REGEX 모두 최신 iPad를 감지하지 못합니다. 카카오택시 딥링크에서 iPad 사용자가 데스크톱 분기로 빠질 수 있습니다.

현재 한국 시장에서의 주요 타겟(iPhone, Android)은 커버되므로 즉시 문제가 되지는 않지만, 추후 iPad 지원이 필요하다면 navigator.maxTouchPoints 체크를 병행하는 방식을 고려해 주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/_utils/device/device.ts` around lines 4 - 5, MOBILE_REGEX and
IOS_REGEX miss modern iPadOS devices whose userAgent reports "Macintosh", so
update the device detection logic (where MOBILE_REGEX and IOS_REGEX are used) to
also treat a "Macintosh" userAgent with navigator.maxTouchPoints > 1 as an
iPad/mobile; specifically, when evaluating isMobile/isIos fallback add a check
for navigator.maxTouchPoints > 1 && /Macintosh/i.test(navigator.userAgent) and
mark it as iOS/mobile so KakaoTaxi deep link goes to the mobile branch for
iPads.
apps/web/app/_utils/openNaverMap/openNaverMap.ts (3)

5-7: 간단한 타입은 type을 사용해 주세요.

extends를 사용하는 경우에도 교차 타입(&)으로 동일하게 표현할 수 있습니다.

♻️ 제안
-interface OpenNaverMapParams extends Coord {
-  placeName?: string
-}
+type OpenNaverMapParams = Coord & {
+  placeName?: string
+}

As per coding guidelines: "Prefer type over interface for simple types in TypeScript".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/_utils/openNaverMap/openNaverMap.ts` around lines 5 - 7, The
simple interface OpenNaverMapParams should be converted to a type alias: replace
"interface OpenNaverMapParams extends Coord { placeName?: string }" with a type
using an intersection of Coord and the extra field (e.g., type
OpenNaverMapParams = Coord & { placeName?: string }), ensuring the same symbol
name OpenNaverMapParams and preserving the optional placeName property and the
referenced Coord type.

29-32: buildNaverMapUrls 함수에 반환 타입이 누락되었습니다.

코딩 가이드라인에서 함수에 반환 타입을 명시하도록 요구하고 있습니다.

♻️ 제안
-const buildNaverMapUrls = (coords: Coord, placeName: string) => ({
+const buildNaverMapUrls = (coords: Coord, placeName: string): { app: string; web: string } => ({
   app: `nmap://place?lat=${coords.latitude}&lng=${coords.longitude}&name=${encodeURIComponent(placeName)}&appname=com.matzip`,
   web: `https://map.naver.com/p/search/${encodeURIComponent(placeName)}?c=${coords.longitude},${coords.latitude},18,0,0,0,dh`,
 })

As per coding guidelines: "return types required on functions".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/_utils/openNaverMap/openNaverMap.ts` around lines 29 - 32, The
function buildNaverMapUrls lacks an explicit return type; update its signature
to declare a return type of an object with string properties "app" and "web"
(i.e., a type describing { app: string; web: string }) for the parameters
(coords: Coord, placeName: string) so the function explicitly returns that typed
object; locate buildNaverMapUrls and add the return type annotation while
leaving the implementation intact.

1-3: import 순서가 코딩 가이드라인과 맞지 않습니다.

가이드라인에 따르면 절대 경로 import(@/...)가 상대 경로 import(../...)보다 먼저 와야 합니다.

♻️ 제안
-import { openDeepLink } from '../openDeepLink'
-import { isMobileDevice } from '../device'
 import { Coord } from '@/map/_utils/toLatLng'
+import { openDeepLink } from '../openDeepLink'
+import { isMobileDevice } from '../device'

As per coding guidelines: "Organize imports in the following order: Node/built-in, external packages, absolute imports, relative imports".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/_utils/openNaverMap/openNaverMap.ts` around lines 1 - 3, Imports
in openNaverMap.ts are ordered incorrectly; move the absolute import (Coord from
'@/map/_utils/toLatLng') above the relative imports so imports follow the
project's ordering rule (node/built-in, external, absolute, then relative).
Locate the import statements for Coord, openDeepLink, and isMobileDevice and
reorder them so "import { Coord } from '@/map/_utils/toLatLng'" appears before
the relative imports "import { openDeepLink } from '../openDeepLink'" and
"import { isMobileDevice } from '../device' to comply with the guideline.
apps/web/app/_utils/openKakaoTaxi/openKakaoTaxi.ts (2)

6-8: openNaverMap과 동일한 가이드라인 이슈: type 사용 및 반환 타입 명시

OpenKakaoTaxiParamstype으로, buildKakaoTaxiUrls에는 반환 타입을 추가해 주세요.

♻️ 제안
-interface OpenKakaoTaxiParams extends Coord {
-  placeName?: string
-}
+type OpenKakaoTaxiParams = Coord & {
+  placeName?: string
+}
-const buildKakaoTaxiUrls = (coords: Coord, placeName: string) => ({
+const buildKakaoTaxiUrls = (coords: Coord, placeName: string): { app: string; store: string } => ({
   app: `kakaot://taxi?dest_lat=${coords.latitude}&dest_lng=${coords.longitude}&end_name=${encodeURIComponent(placeName)}`,
   store: isIOSDevice()
     ? 'https://apps.apple.com/kr/app/kakaotaxi/id981110422'
     : 'https://play.google.com/store/apps/details?id=com.kakao.taxi',
 })

As per coding guidelines: "Prefer type over interface for simple types in TypeScript" / "return types required on functions".

Also applies to: 30-35

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/_utils/openKakaoTaxi/openKakaoTaxi.ts` around lines 6 - 8,
Replace the interface with a type by changing OpenKakaoTaxiParams to a type
alias (e.g., type OpenKakaoTaxiParams = Coord & { placeName?: string }), and add
an explicit return type to the buildKakaoTaxiUrls function (e.g., : string[] or
another appropriate union/tuple) so the function signature declares what it
returns; update any related helper or overloads that reference
OpenKakaoTaxiParams or buildKakaoTaxiUrls (also apply the same type/return-type
changes to the other similar definitions around the buildKakaoTaxiUrls usage).

1-4: import 순서가 코딩 가이드라인과 맞지 않습니다.

절대 경로 import(@/...)가 상대 경로 import(../...)보다 먼저 와야 합니다.

♻️ 제안
 import { addToast } from '@heroui/react'
+import { Coord } from '@/map/_utils/toLatLng'
 import { openDeepLink } from '../openDeepLink'
 import { isMobileDevice, isIOSDevice } from '../device'
-import { Coord } from '@/map/_utils/toLatLng'

As per coding guidelines: "Organize imports in the following order: Node/built-in, external packages, absolute imports, relative imports".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/_utils/openKakaoTaxi/openKakaoTaxi.ts` around lines 1 - 4, The
import statements in openKakaoTaxi.ts are out of order per the project
guideline; reorder them so absolute imports (e.g., Coord from
'@/map/_utils/toLatLng') appear before relative imports (e.g., addToast from
'@heroui/react' counts as external and should remain above absolute), and then
list relative imports last (e.g., ../openDeepLink, ../device). Update the import
block to follow: external packages (addToast), absolute imports (Coord), then
relative imports (openDeepLink, isMobileDevice, isIOSDevice) so the file matches
the prescribed Node/external → absolute → relative ordering.
apps/web/app/_utils/openDeepLink/openDeepLink.ts (1)

1-5: 코딩 가이드라인: 간단한 타입에는 type 사용 권장

코딩 가이드라인에 따르면 간단한 타입에는 interface 대신 type을 사용하는 것이 권장됩니다.

♻️ 제안
-interface OpenDeepLinkParams {
-  appScheme: string
-  fallbackUrl: string
-  timeout?: number
-}
+type OpenDeepLinkParams = {
+  appScheme: string
+  fallbackUrl: string
+  timeout?: number
+}

As per coding guidelines: "Prefer type over interface for simple types in TypeScript".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/_utils/openDeepLink/openDeepLink.ts` around lines 1 - 5, Replace
the simple TypeScript interface OpenDeepLinkParams with a type alias: change
"interface OpenDeepLinkParams { appScheme: string; fallbackUrl: string;
timeout?: number }" to "type OpenDeepLinkParams = { appScheme: string;
fallbackUrl: string; timeout?: number }", keeping the same property names and
optional modifier (timeout?) and any exports/usage unchanged (e.g., where
OpenDeepLinkParams is referenced in functions or params).
apps/web/app/places/new/_components/Step/PlacePreview/Location.tsx (1)

7-11: interfacetype 사용 및 반환 타입 명시 필요

두 가지 코딩 가이드라인 위반이 있습니다.

  1. interface LocationProps → 단순 props 타입은 type 사용이 권장됩니다.
  2. Location 컴포넌트에 명시적 반환 타입이 없습니다.
♻️ 제안 수정
-interface LocationProps {
-  location: Coord
-}
+type LocationProps = {
+  location: Coord
+}

-export const Location = ({ location }: LocationProps) => {
+export const Location = ({ location }: LocationProps): JSX.Element => {

As per coding guidelines: "Prefer type over interface for simple types in TypeScript" 및 "return types required on functions".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/places/new/_components/Step/PlacePreview/Location.tsx` around
lines 7 - 11, Replace the props declaration from an interface to a type by
changing `interface LocationProps` to `type LocationProps = { location: Coord
}`, and add an explicit return type to the `Location` component signature (e.g.,
append `: JSX.Element` or use `: React.FC<LocationProps>` on `export const
Location`) so both the props and the component return type (`Coord`,
`LocationProps`, `Location`) follow the project guidelines.
apps/web/app/places/[id]/_components/Location/Location.tsx (1)

11-14: interfacetype 사용 및 반환 타입 명시 필요

LocationProps(Line 11)와 MapButtonProps(Line 64), 그리고 Location·handleOpenNaverMap·handleOpenKakaoTaxi·MapButton 함수 모두 코딩 가이드라인 위반이 있습니다.

♻️ 제안 수정
-interface LocationProps {
-  location: Coord
-  placeName: string
-}
+type LocationProps = {
+  location: Coord
+  placeName: string
+}

-export const Location = ({ location, placeName }: LocationProps) => {
+export const Location = ({ location, placeName }: LocationProps): JSX.Element => {

-  const handleOpenNaverMap = () => {
+  const handleOpenNaverMap = (): void => {

-  const handleOpenKakaoTaxi = () => {
+  const handleOpenKakaoTaxi = (): void => {
-interface MapButtonProps {
-  onClick: VoidFunction
-  imageSrc: string
-  alt: string
-}
+type MapButtonProps = {
+  onClick: VoidFunction
+  imageSrc: string
+  alt: string
+}

-const MapButton = ({ onClick, imageSrc, alt }: MapButtonProps) => (
+const MapButton = ({ onClick, imageSrc, alt }: MapButtonProps): JSX.Element => (

As per coding guidelines: "Prefer type over interface for simple types in TypeScript" 및 "return types required on functions".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/places/`[id]/_components/Location/Location.tsx around lines 11 -
14, Change the two interfaces to type aliases (replace "interface LocationProps"
and "interface MapButtonProps" with "type LocationProps = { ... }" and "type
MapButtonProps = { ... }") and add explicit return types: annotate the Location
and MapButton components to return JSX.Element and annotate handler functions
handleOpenNaverMap and handleOpenKakaoTaxi with a return type of void (or
Promise<void> if they are async). Ensure the prop type names (LocationProps,
MapButtonProps) are used in the component parameter typings so the new type
aliases replace the interfaces everywhere.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/app/places/`[id]/_components/Location/Location.tsx:
- Around line 70-81: The MapButton component's <button> has no type, causing it
to default to type="submit" inside forms; update the MapButton component
(MapButton, MapButtonProps) to add an explicit type="button" attribute on the
<button> element to prevent accidental form submissions if this component is
later rendered inside a form.
- Around line 38-49: The Column containing the MapButton components can be
rendered beneath NaverMap layers due to stacking context from Container's
overflow-hidden and the map SDK's positioned layers; fix by giving the Column
(or the MapButton wrapper) an explicit high z-index and ensuring it is
positioned (e.g., relative) so it sits above the map layers; also update the
button element inside MapButton (the clickable element referenced in this file)
to include type="button" for explicit behavior; locate the Column, MapButton,
handleOpenKakaoTaxi/handleOpenNaverMap and NaverMap symbols to apply these
changes.

---

Nitpick comments:
In `@apps/web/app/_utils/device/device.ts`:
- Around line 10-16: isMobileDevice and isIOSDevice access navigator.userAgent
which will throw in SSR; add a defensive guard that checks for navigator/window
existence (e.g., typeof navigator !== 'undefined' or typeof window !==
'undefined') and fall back to an empty string before running MOBILE_REGEX.test
or IOS_REGEX.test so both functions safely return false in non-browser
environments.
- Around line 4-5: MOBILE_REGEX and IOS_REGEX miss modern iPadOS devices whose
userAgent reports "Macintosh", so update the device detection logic (where
MOBILE_REGEX and IOS_REGEX are used) to also treat a "Macintosh" userAgent with
navigator.maxTouchPoints > 1 as an iPad/mobile; specifically, when evaluating
isMobile/isIos fallback add a check for navigator.maxTouchPoints > 1 &&
/Macintosh/i.test(navigator.userAgent) and mark it as iOS/mobile so KakaoTaxi
deep link goes to the mobile branch for iPads.

In `@apps/web/app/_utils/openDeepLink/openDeepLink.ts`:
- Around line 1-5: Replace the simple TypeScript interface OpenDeepLinkParams
with a type alias: change "interface OpenDeepLinkParams { appScheme: string;
fallbackUrl: string; timeout?: number }" to "type OpenDeepLinkParams = {
appScheme: string; fallbackUrl: string; timeout?: number }", keeping the same
property names and optional modifier (timeout?) and any exports/usage unchanged
(e.g., where OpenDeepLinkParams is referenced in functions or params).

In `@apps/web/app/_utils/openKakaoTaxi/openKakaoTaxi.ts`:
- Around line 6-8: Replace the interface with a type by changing
OpenKakaoTaxiParams to a type alias (e.g., type OpenKakaoTaxiParams = Coord & {
placeName?: string }), and add an explicit return type to the buildKakaoTaxiUrls
function (e.g., : string[] or another appropriate union/tuple) so the function
signature declares what it returns; update any related helper or overloads that
reference OpenKakaoTaxiParams or buildKakaoTaxiUrls (also apply the same
type/return-type changes to the other similar definitions around the
buildKakaoTaxiUrls usage).
- Around line 1-4: The import statements in openKakaoTaxi.ts are out of order
per the project guideline; reorder them so absolute imports (e.g., Coord from
'@/map/_utils/toLatLng') appear before relative imports (e.g., addToast from
'@heroui/react' counts as external and should remain above absolute), and then
list relative imports last (e.g., ../openDeepLink, ../device). Update the import
block to follow: external packages (addToast), absolute imports (Coord), then
relative imports (openDeepLink, isMobileDevice, isIOSDevice) so the file matches
the prescribed Node/external → absolute → relative ordering.

In `@apps/web/app/_utils/openNaverMap/openNaverMap.ts`:
- Around line 5-7: The simple interface OpenNaverMapParams should be converted
to a type alias: replace "interface OpenNaverMapParams extends Coord {
placeName?: string }" with a type using an intersection of Coord and the extra
field (e.g., type OpenNaverMapParams = Coord & { placeName?: string }), ensuring
the same symbol name OpenNaverMapParams and preserving the optional placeName
property and the referenced Coord type.
- Around line 29-32: The function buildNaverMapUrls lacks an explicit return
type; update its signature to declare a return type of an object with string
properties "app" and "web" (i.e., a type describing { app: string; web: string
}) for the parameters (coords: Coord, placeName: string) so the function
explicitly returns that typed object; locate buildNaverMapUrls and add the
return type annotation while leaving the implementation intact.
- Around line 1-3: Imports in openNaverMap.ts are ordered incorrectly; move the
absolute import (Coord from '@/map/_utils/toLatLng') above the relative imports
so imports follow the project's ordering rule (node/built-in, external,
absolute, then relative). Locate the import statements for Coord, openDeepLink,
and isMobileDevice and reorder them so "import { Coord } from
'@/map/_utils/toLatLng'" appears before the relative imports "import {
openDeepLink } from '../openDeepLink'" and "import { isMobileDevice } from
'../device' to comply with the guideline.

In `@apps/web/app/places/`[id]/_components/Location/Location.tsx:
- Around line 11-14: Change the two interfaces to type aliases (replace
"interface LocationProps" and "interface MapButtonProps" with "type
LocationProps = { ... }" and "type MapButtonProps = { ... }") and add explicit
return types: annotate the Location and MapButton components to return
JSX.Element and annotate handler functions handleOpenNaverMap and
handleOpenKakaoTaxi with a return type of void (or Promise<void> if they are
async). Ensure the prop type names (LocationProps, MapButtonProps) are used in
the component parameter typings so the new type aliases replace the interfaces
everywhere.

In `@apps/web/app/places/new/_components/Step/PlacePreview/Location.tsx`:
- Around line 7-11: Replace the props declaration from an interface to a type by
changing `interface LocationProps` to `type LocationProps = { location: Coord
}`, and add an explicit return type to the `Location` component signature (e.g.,
append `: JSX.Element` or use `: React.FC<LocationProps>` on `export const
Location`) so both the props and the component return type (`Coord`,
`LocationProps`, `Location`) follow the project guidelines.

- Container에 relative 포지셔닝 추가
- 버튼 컨테이너에 z-10 추가하여 지도 위에 표시되도록 개선
- MapButton에 type='button' 명시하여 폼 제출 방지
@leeleeleeleejun leeleeleeleejun merged commit 2e7ab33 into develop Feb 18, 2026
1 check was pending
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/web/app/places/[id]/_components/Location/Location.tsx (2)

11-14: interface 대신 type 사용 권장

LocationPropsMapButtonProps 모두 메서드나 확장이 없는 단순 타입이므로 코딩 가이드라인에 따라 interface 대신 type을 사용해야 합니다.

♻️ 제안 수정
-interface LocationProps {
+type LocationProps = {
   location: Coord
   placeName: string
-}
+}

-interface MapButtonProps {
+type MapButtonProps = {
   onClick: VoidFunction
   imageSrc: string
   alt: string
-}
+}

As per coding guidelines, "Prefer type over interface for simple types in TypeScript".

Also applies to: 64-68

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/places/`[id]/_components/Location/Location.tsx around lines 11 -
14, Replace the simple TypeScript interfaces with type aliases: change the
interface declaration for LocationProps to a type alias (type LocationProps = {
location: Coord; placeName: string }) and do the same for MapButtonProps, since
neither has methods or extends other types; update any exported/used symbol
names accordingly so all references to LocationProps and MapButtonProps continue
to work.

16-16: 모든 함수에 명시적 반환 타입 추가 필요

Location, handleOpenNaverMap, handleOpenKakaoTaxi, MapButton 모두 반환 타입이 생략되어 있습니다.

♻️ 제안 수정
-export const Location = ({ location, placeName }: LocationProps) => {
+export const Location = ({ location, placeName }: LocationProps): JSX.Element => {

-  const handleOpenNaverMap = () => {
+  const handleOpenNaverMap = (): void => {

-  const handleOpenKakaoTaxi = () => {
+  const handleOpenKakaoTaxi = (): void => {

-const MapButton = ({ onClick, imageSrc, alt }: MapButtonProps) => (
+const MapButton = ({ onClick, imageSrc, alt }: MapButtonProps): JSX.Element => (

As per coding guidelines, "return types required on functions" in TypeScript strict mode.

Also applies to: 19-19, 27-27, 70-70

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/places/`[id]/_components/Location/Location.tsx at line 16, Add
explicit TypeScript return types for the component and functions: annotate the
Location component (Location) with a component return type such as JSX.Element
or React.FC<LocationProps>, annotate the click handlers handleOpenNaverMap and
handleOpenKakaoTaxi with an explicit return type like void or (event?:
React.MouseEvent) => void, and annotate the MapButton component/function with
JSX.Element or React.FC for its props; update the function signatures for
Location, handleOpenNaverMap, handleOpenKakaoTaxi, and MapButton to include
these return types to satisfy the "return types required on functions" rule.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/app/places/`[id]/_components/Location/Location.tsx:
- Line 74: In Location.tsx replace the nonstandard Tailwind class 'border-1'
with the correct 1px utility 'border' where the class list includes "'border-1
border-gray-100'"; update the class string/array inside the Location component
(the place that builds the element classes) to use "border border-gray-100" so
the 1px border renders correctly across Tailwind versions.

---

Nitpick comments:
In `@apps/web/app/places/`[id]/_components/Location/Location.tsx:
- Around line 11-14: Replace the simple TypeScript interfaces with type aliases:
change the interface declaration for LocationProps to a type alias (type
LocationProps = { location: Coord; placeName: string }) and do the same for
MapButtonProps, since neither has methods or extends other types; update any
exported/used symbol names accordingly so all references to LocationProps and
MapButtonProps continue to work.
- Line 16: Add explicit TypeScript return types for the component and functions:
annotate the Location component (Location) with a component return type such as
JSX.Element or React.FC<LocationProps>, annotate the click handlers
handleOpenNaverMap and handleOpenKakaoTaxi with an explicit return type like
void or (event?: React.MouseEvent) => void, and annotate the MapButton
component/function with JSX.Element or React.FC for its props; update the
function signatures for Location, handleOpenNaverMap, handleOpenKakaoTaxi, and
MapButton to include these return types to satisfy the "return types required on
functions" rule.

<button
type={'button'}
className={cn(
'border-1 border-gray-100',
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

border-1은 표준 Tailwind 유틸리티 클래스가 아닐 수 있습니다

공식 Tailwind 문서의 border-width 예시는 border, border-2, border-4, border-8만 나열하며 border-1은 포함되지 않습니다. 이 클래스가 인식되지 않으면 버튼 테두리가 렌더링되지 않습니다. 1px 테두리에는 border를 사용해야 합니다.

🐛 제안 수정
-      'border-1 border-gray-100',
+      'border border-gray-100',

프로젝트의 Tailwind 버전에서 border-1이 유효한지 확인하려면 아래 스크립트를 실행하세요:

#!/bin/bash
# Description: Check Tailwind version in the project and verify if border-1 is used elsewhere

# Check Tailwind CSS version
cat package.json | grep -i tailwind 2>/dev/null
fd "package.json" --max-depth 3 --exec grep -l "tailwindcss" {} \; | xargs -I{} sh -c 'echo "=== {} ===" && grep "tailwindcss" {}'

# Check if border-1 is used elsewhere in the codebase
rg -n '\bborder-1\b' --type=tsx --type=ts --type=css
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/app/places/`[id]/_components/Location/Location.tsx at line 74, In
Location.tsx replace the nonstandard Tailwind class 'border-1' with the correct
1px utility 'border' where the class list includes "'border-1 border-gray-100'";
update the class string/array inside the Location component (the place that
builds the element classes) to use "border border-gray-100" so the 1px border
renders correctly across Tailwind versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 외부 앱 연동 (DeepLink)

1 participant