Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion app/join/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
'use client';

import { useRouter } from 'next/navigation';
import { useState } from 'react';

export default function JoinMeetingPage() {
const [name, setName] = useState('');
const [password, setPassword] = useState('');
const [isRemembered, setIsRemembered] = useState(true);
const router = useRouter();

// 이름/비번 유효성 검사 (입력값이 있을 때만 버튼 활성화)
const isFormValid = name.length > 0 && password.length === 4;
Expand All @@ -15,6 +17,7 @@ export default function JoinMeetingPage() {
if (!isFormValid) return;

console.log('참여 요청:', { name, password, isRemembered });
router.push('/meeting');
};

return (
Expand Down Expand Up @@ -101,7 +104,7 @@ export default function JoinMeetingPage() {
<button
type="submit"
disabled={!isFormValid}
className={`text-gray-2 h-12 w-full rounded-sm py-4 pt-3 pb-2.5 text-lg font-semibold transition-colors md:max-w-sm ${
className={`text-gray-2 mt-6 h-12 w-full rounded-sm py-4 pt-3 pb-2.5 text-lg font-semibold transition-colors md:max-w-sm ${
isFormValid
? 'hover:bg-blue-8 bg-blue-5' // 활성화 상태
: 'bg-gray-4 cursor-not-allowed' // 비활성화 상태
Expand Down
7 changes: 6 additions & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import './globals.css';
import type { Metadata } from 'next';
import Script from 'next/script';
import localFont from 'next/font/local';
import Header from '../components/header';
import Footer from '../components/footer';
import GlobalModal from '@/components/globalModal';
import GlobalModal from '@/components/modal/globalModal';

const pretendard = localFont({
src: [
Expand Down Expand Up @@ -38,6 +39,10 @@ export default function RootLayout({
<main className="flex-1">{children}</main>
<Footer />
<GlobalModal />
<Script
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_MAP_KEY}&libraries=services,clusterer&autoload=false`}
strategy="beforeInteractive"
/>
Comment on lines +42 to +45

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check the structure and find the layout file
fd -t f "layout.tsx" | head -20

Repository: SWYP-mingling/Frontend

Length of output: 80


🏁 Script executed:

# Read the app/layout.tsx file to verify the code at lines 42-45
if [ -f "app/layout.tsx" ]; then
  wc -l app/layout.tsx
fi

Repository: SWYP-mingling/Frontend

Length of output: 83


🏁 Script executed:

# Look for environment variable definitions
fd -t f -g ".env*"

Repository: SWYP-mingling/Frontend

Length of output: 273


🏁 Script executed:

# Search for NEXT_PUBLIC_KAKAO_MAP_KEY usage across the codebase
rg -n "NEXT_PUBLIC_KAKAO_MAP_KEY" --type-list

Repository: SWYP-mingling/Frontend

Length of output: 455


🏁 Script executed:

# Read the entire app/layout.tsx file
cat -n app/layout.tsx

Repository: SWYP-mingling/Frontend

Length of output: 2127


🏁 Script executed:

# Search for .env files including hidden ones
fd -H -t f -g ".env*"

Repository: SWYP-mingling/Frontend

Length of output: 48


🏁 Script executed:

# Search for NEXT_PUBLIC_KAKAO_MAP_KEY usage
rg "NEXT_PUBLIC_KAKAO_MAP_KEY"

Repository: SWYP-mingling/Frontend

Length of output: 222


🏁 Script executed:

# Search for any Kakao-related code
rg -i "kakao" -n

Repository: SWYP-mingling/Frontend

Length of output: 1227


🏁 Script executed:

# Search for error handling or map initialization
rg -n "useEffect|onload|onerror" app/layout.tsx

Repository: SWYP-mingling/Frontend

Length of output: 48


🏁 Script executed:

# Look for map-related component files
fd -t f -e "tsx" -e "ts" | xargs rg -l "kakao\|map" 2>/dev/null | head -20

Repository: SWYP-mingling/Frontend

Length of output: 48


🏁 Script executed:

# Check for any console error logs or error handling
rg -n "console\.(error|warn)|catch|Error" app/layout.tsx

Repository: SWYP-mingling/Frontend

Length of output: 48


🏁 Script executed:

# Read the KakaoMap component to understand error handling
cat -n components/map/kakaoMap.tsx

Repository: SWYP-mingling/Frontend

Length of output: 1338


🏁 Script executed:

# Check the types/kakao.d.ts file
cat -n types/kakao.d.ts

Repository: SWYP-mingling/Frontend

Length of output: 186


🏁 Script executed:

# Search for environment variable configuration in config files
fd -t f \( -name "*.config.*" -o -name "next.config.*" -o -name "tsconfig.json" \)

Repository: SWYP-mingling/Frontend

Length of output: 296


🏁 Script executed:

# Search for config files
fd -t f "next.config"

Repository: SWYP-mingling/Frontend

Length of output: 80


🏁 Script executed:

# Look for environment configuration or setup documentation
fd -t f -e "md" | xargs rg -l "NEXT_PUBLIC_KAKAO_MAP_KEY" 2>/dev/null

Repository: SWYP-mingling/Frontend

Length of output: 50


🏁 Script executed:

# Check if there's a .env.example or documentation
fd -H -t f \( -name ".env*" -o -name "*example*" -o -name "README*" \)

Repository: SWYP-mingling/Frontend

Length of output: 296


🏁 Script executed:

# Check for environment files and docs
find . -maxdepth 2 -type f \( -name ".env*" -o -name "README*" -o -name "*.md" \) 2>/dev/null

Repository: SWYP-mingling/Frontend

Length of output: 112


🏁 Script executed:

# Read next.config.ts
cat -n next.config.ts

Repository: SWYP-mingling/Frontend

Length of output: 247


🏁 Script executed:

# Check package.json for how environment variables are handled
if [ -f "package.json" ]; then
  head -50 package.json
fi

Repository: SWYP-mingling/Frontend

Length of output: 1181


Kakao SDK 키 미설정 시 조용히 실패할 수 있습니다.

NEXT_PUBLIC_KAKAO_MAP_KEY가 비어 있으면 appkey=undefined로 스크립트가 로드되어 유효하지 않은 키로 인해 SDK 로딩에 실패합니다. KakaoMap 컴포넌트의 if (!window.kakao) return; 체크에 의해 지도 영역이 완전히 비어지며, 사용자에게는 실패 원인을 알 수 없습니다. 키 존재 여부를 가드하거나 로드 실패 시 명확한 오류 메시지를 표시하는 것이 안전합니다.

🛠️ 제안 수정안
 export default function RootLayout({
   children,
 }: Readonly<{
   children: React.ReactNode;
 }>) {
+  const kakaoKey = process.env.NEXT_PUBLIC_KAKAO_MAP_KEY;
+
   return (
     <html lang="ko" className={pretendard.variable}>
       <body className="flex min-h-screen flex-col">
         <Header />
         <main className="flex-1">{children}</main>
         <Footer />
         <GlobalModal />
-        <Script
-          src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_MAP_KEY}&libraries=services,clusterer&autoload=false`}
-          strategy="beforeInteractive"
-        />
+        {kakaoKey && (
+          <Script
+            src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${kakaoKey}&libraries=services,clusterer&autoload=false`}
+            strategy="beforeInteractive"
+          />
+        )}
       </body>
     </html>
   );
 }
🤖 Prompt for AI Agents
In `@app/layout.tsx` around lines 42 - 45, The Script tag loads the Kakao SDK even
if NEXT_PUBLIC_KAKAO_MAP_KEY is empty, leading to silent failures in KakaoMap
(which only checks if window.kakao exists). Add a guard around the Script
insertion that checks process.env.NEXT_PUBLIC_KAKAO_MAP_KEY and skip loading the
SDK when missing, and/or attach an onError handler to the Script to surface a
clear error message; update the app layout where the Script is rendered and
ensure KakaoMap (or its parent) displays a user-facing error if the key is
absent or the script fails to load (reference NEXT_PUBLIC_KAKAO_MAP_KEY, the
Script component, and KakaoMap/window.kakao).

</body>
</html>
);
Expand Down
135 changes: 135 additions & 0 deletions app/meeting/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
'use client';

import { useState } from 'react';
import Image from 'next/image';
import KakaoMap from '@/components/map/kakaoMap';
import StationSearch from '@/components/meeting/stationSearch';
import { useOpenModal } from '@/hooks/useOpenModal';

// 목 데이터 (참여자 목록)
const MOCK_PARTICIPANTS = [
{ id: 1, name: '안', station: '홍대입구역', status: 'pending', color: 'bg-blue-500' },
{ id: 2, name: '손', station: '성수역', status: 'pending', color: 'bg-orange-400' },
{ id: 3, name: '김', station: '강남역', status: 'done', color: 'bg-red-500' },
{ id: 4, name: '이', station: '건대입구역', status: 'done', color: 'bg-purple-600' },
];

// [NEW] 목 데이터 (검색용 역 리스트) - 실제로는 API 등에서 가져올 데이터
const SEARCH_STATIONS = [
'검단오류(검단산업단지)',
'광교(경기대)',
'구의(광진구청)',
'굽은다리(강동구민회관앞)',
'금정역',
'강남역',
'홍대입구역',
'서울역',
];

export default function MeetingPage() {
// 선택된 역 상태 관리
const [selectedStation, setSelectedStation] = useState<string | null>(null);
const openModal = useOpenModal();

return (
// 전체 화면 배경 및 중앙 정렬
<div className="flex items-center justify-center p-0 md:min-h-[calc(100vh-200px)] md:py-25">
{/* 메인 컨테이너 (반응형 박스) */}
<div className="flex h-full w-full flex-col overflow-hidden bg-white md:h-175 md:w-174 md:flex-row md:gap-4 md:rounded-xl lg:w-215">
{/* [LEFT PANEL] 데스크탑 전용 정보 영역 */}
<section className="border-gray-1 flex w-full flex-col gap-5 bg-white md:w-77.5 md:gap-10">
{/* 타이머 섹션 */}
<div className="px-5 pt-10 md:p-0">
<div className="flex items-start justify-between">
<div className="text-[22px] leading-[1.364] font-semibold tracking-[-1.948%]">
<h2 className="text-gray-9">
투표 마감 시간
<br />
<span className="text-blue-5">03: 45</span> 남았습니다
</h2>
<p className="text-gray-5 mt-2 text-[15px] font-normal">
아직 입력 안 한 모임원 2명
</p>
</div>
<button
className="text-blue-5 bg-blue-1 hover:bg-blue-2 flex h-6 w-30 cursor-pointer items-center gap-0.5 rounded px-3 py-1.5 text-[11px] font-semibold transition-colors"
type="button"
onClick={(e) => openModal('SHARE', e)}
>
<Image src="/icon/share.svg" alt="공유 아이콘" width={12} height={12} />
참여 링크 공유하기
</button>
</div>
</div>

{/* 모바일 전용 지도 영역 */}
<KakaoMap className="relative block aspect-video h-93.5 bg-gray-100 md:hidden" />

{/* 출발지 검색 창 컴포넌트 */}
<StationSearch
stations={SEARCH_STATIONS}
selectedStation={selectedStation}
onSelect={setSelectedStation}
/>

<div className="bg-gray-1 relative h-1 w-full md:hidden"></div>

{/* 참여 현황 */}
<div className="flex flex-1 flex-col gap-3 overflow-hidden px-5 md:gap-3.5 md:p-0">
{/* [1] 상단 고정 영역 */}
<div className="flex items-center justify-between bg-white">
<h3 className="text-gray-9 text-xl font-semibold">참여현황</h3>
<span className="text-gray-6 text-normal text-xs">
<span className="text-blue-5">{MOCK_PARTICIPANTS.length}명</span>이 참여 중
</span>
</div>

{/* [2] 재촉하기 배너 */}
<button
type="button"
className="bg-blue-5 hover:bg-blue-8 flex h-21 w-full cursor-pointer items-center justify-between rounded p-4 text-left text-white transition-transform active:scale-[0.98]"
onClick={(e) => openModal('NUDGE', e)}
>
<div className="flex flex-col gap-0.5">
<span className="text-lg leading-[1.44] font-semibold">
아직 입력하지 않은 친구
<br />
재촉하기
</span>
</div>

<div className="bg-gray-3 h-13 w-14"></div>
</button>

{/* [3] 출발지 컴포넌트 */}
<div className="mb-10 flex-1">
<div className="flex flex-col gap-3.5">
{MOCK_PARTICIPANTS.map((user) => (
<div
key={user.id}
className="border-gray-2 flex h-17 items-center justify-between rounded border bg-white px-5"
>
<span className="text-gray-8 text-[17px] font-semibold">{user.station}</span>
<div className="flex items-center gap-1.5">
<div
className={`flex h-7 w-7 items-center justify-center rounded-full text-xs font-normal text-white ${user.color}`}
>
{user.name}
</div>
<span className="text-gray-8 text-[15px]">안가연</span>
</div>
Comment on lines +112 to +120

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

참여자 이름이 고정 문자열로 렌더링됩니다
목 데이터와 불일치해 모든 항목이 동일한 이름으로 보입니다.

🔧 제안 수정
-                      <span className="text-gray-8 text-[15px]">안가연</span>
+                      <span className="text-gray-8 text-[15px]">{user.name}</span>
📝 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
<span className="text-gray-8 text-[17px] font-semibold">{user.station}</span>
<div className="flex items-center gap-1.5">
<div
className={`flex h-7 w-7 items-center justify-center rounded-full text-xs font-normal text-white ${user.color}`}
>
{user.name}
</div>
<span className="text-gray-8 text-[15px]">안가연</span>
</div>
<span className="text-gray-8 text-[17px] font-semibold">{user.station}</span>
<div className="flex items-center gap-1.5">
<div
className={`flex h-7 w-7 items-center justify-center rounded-full text-xs font-normal text-white ${user.color}`}
>
{user.name}
</div>
<span className="text-gray-8 text-[15px]">{user.name}</span>
</div>
🤖 Prompt for AI Agents
In `@app/meeting/page.tsx` around lines 112 - 120, The participant name is
hardcoded as "안가연" causing all items to show the same name; update the span that
currently renders the static string to use the participant's property (e.g.,
user.name or user.displayName) instead, e.g., replace the static text inside the
span with the dynamic value and add a safe fallback (like user.name ||
'Unknown') to avoid undefined names; locate the span near the avatar block that
uses user.color and user.name to make this change.

</div>
))}
</div>
</div>
</div>
</section>

{/* [RIGHT PANEL] 데스크탑 전용 지도 영역 */}
<section className="hidden h-full flex-1 bg-gray-100 md:block">
<KakaoMap className="h-full w-full" />
</section>
</div>
</div>
);
}
4 changes: 2 additions & 2 deletions app/share/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { useState } from 'react';

export default function ShareLinkPage() {
const [link, setLink] = useState('www.abcabc');

Check warning on line 9 in app/share/page.tsx

View workflow job for this annotation

GitHub Actions / build

'setLink' is assigned a value but never used

Check warning on line 9 in app/share/page.tsx

View workflow job for this annotation

GitHub Actions / build

'setLink' is assigned a value but never used
const { isVisible, show } = useToast();

const handleCopyLink = async () => {
Expand All @@ -21,11 +21,11 @@

return (
<div className="flex flex-col items-center justify-center bg-white px-5 py-10 md:py-25">
<h3 className="text-gray-10 mb-9 text-center text-2xl leading-[1.334] font-bold md:text-4xl">
<h2 className="text-gray-10 mb-9 text-center text-2xl leading-[1.334] font-bold md:text-4xl">
모임이 만들어졌어요!
<br />
링크를 공유해주세요
</h3>
</h2>

<section className="mb-9 flex h-70 w-80 max-w-sm items-center justify-center rounded-2xl bg-gray-200 md:w-90">
<div className="text-gray-10 text-center font-semibold">
Expand Down
8 changes: 4 additions & 4 deletions components/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import Link from 'next/link';
import Image from 'next/image';
import { useModalStore } from '@/store/useModalStore';
import { useOpenModal } from '@/hooks/useOpenModal';

const ICON = ['threads', 'instagram'];

const Footer = () => {
const { onOpen } = useModalStore();
const openModal = useOpenModal();

return (
<footer className="bg-gray-1 flex h-59 items-center md:h-35">
Expand All @@ -29,7 +29,7 @@ const Footer = () => {
</Link>
<button
type="button"
onClick={() => onOpen('FEEDBACK')}
onClick={(e) => openModal('FEEDBACK', e)}
className="text-gray-7 cursor-pointer text-[16px]"
>
피드백남기기
Expand All @@ -40,7 +40,7 @@ const Footer = () => {
<div className="text-gray-4 flex gap-3">
{ICON.map((item, idx) => (
<Link href={`https://www.${item}.com/`} key={idx}>
<Image src={`/${item}.svg`} alt={`${item} Logo`} width={24} height={24} />
<Image src={`/icon/${item}.svg`} alt={`${item} Logo`} width={24} height={24} />
</Link>
))}
</div>
Expand Down
27 changes: 0 additions & 27 deletions components/globalModal.tsx

This file was deleted.

8 changes: 4 additions & 4 deletions components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

import Link from 'next/link';
import Image from 'next/image';
import { useModalStore } from '@/store/useModalStore';
import { useOpenModal } from '@/hooks/useOpenModal';

const Header = () => {
const { onOpen } = useModalStore();
const openModal = useOpenModal();

return (
<header className="border-gray-1 sticky top-0 right-0 left-0 flex h-15 items-center justify-center border-b bg-white">
<header className="border-gray-1 top-0 right-0 left-0 flex h-15 items-center justify-center border-b bg-white">
<div className="mx-5 my-2.5 flex w-300 items-center justify-between md:mx-12.5 lg:mx-42.5">
<Link href="/" className="shrink-0">
<Image src="/logo.svg" alt="Mingling Logo" width={112} height={40} priority />
Expand All @@ -19,7 +19,7 @@ const Header = () => {
</Link>
<button
type="button"
onClick={() => onOpen('FEEDBACK')}
onClick={(e) => openModal('FEEDBACK', e)}
className="text-gray-5 p-2 text-[16px] transition-colors hover:text-gray-900"
>
피드백남기기
Expand Down
37 changes: 37 additions & 0 deletions components/map/kakaoMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use client';

import { useEffect, useRef } from 'react';

interface KakaoMapProps {
className?: string; // Tailwind 클래스를 받기 위해
}

export default function KakaoMap({ className }: KakaoMapProps) {
const mapContainer = useRef<HTMLDivElement>(null);

useEffect(() => {
// 1. 카카오 스크립트가 로드되지 않았으면 중단
if (!window.kakao) return;

// 2. 카카오 맵 로드 (autoload=false라서 명시적으로 load 호출 필요)
window.kakao.maps.load(() => {
const container = mapContainer.current;
Comment on lines +12 to +18

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "kakaoMap.tsx" -type f 2>/dev/null | head -20

Repository: SWYP-mingling/Frontend

Length of output: 95


🏁 Script executed:

git ls-files | grep -i "kakao" | head -20

Repository: SWYP-mingling/Frontend

Length of output: 110


🏁 Script executed:

cat -n components/map/kakaoMap.tsx | head -40

Repository: SWYP-mingling/Frontend

Length of output: 1338


🏁 Script executed:

wc -l components/map/kakaoMap.tsx

Repository: SWYP-mingling/Frontend

Length of output: 96


🏁 Script executed:

grep -r "window.kakao" . --include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" -n | head -20

Repository: SWYP-mingling/Frontend

Length of output: 630


🏁 Script executed:

grep -r "kakao" . --include="*.html" --include="*.tsx" --include="*.ts" -n | grep -i "script\|sdk\|load" | head -20

Repository: SWYP-mingling/Frontend

Length of output: 295


🏁 Script executed:

grep -r "console.warn\|console.error\|useEffect" . --include="*.tsx" --include="*.ts" -A 2 | head -50

Repository: SWYP-mingling/Frontend

Length of output: 4237


🏁 Script executed:

cat -n app/layout.tsx | grep -A 5 -B 5 "kakao"

Repository: SWYP-mingling/Frontend

Length of output: 494


카카오 맵 SDK 미로드 시 무음으로 종료되어 디버깅이 어렵습니다.

window.kakao가 없을 때 아무 피드백 없이 종료되므로, 개발 단계에서 SDK 로드 실패 원인을 파악하기 어렵습니다. 최소한 콘솔 경고를 추가하거나 사용자에게 대체 UI를 제공하는 것이 좋습니다.

🛠️ 제안 수정안
-    if (!window.kakao) return;
+    if (!window.kakao) {
+      console.warn('Kakao Maps SDK is not loaded.');
+      return;
+    }
📝 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
useEffect(() => {
// 1. 카카오 스크립트가 로드되지 않았으면 중단
if (!window.kakao) return;
// 2. 카카오 맵 로드 (autoload=false라서 명시적으로 load 호출 필요)
window.kakao.maps.load(() => {
const container = mapContainer.current;
useEffect(() => {
// 1. 카카오 스크립트가 로드되지 않았으면 중단
if (!window.kakao) {
console.warn('Kakao Maps SDK is not loaded.');
return;
}
// 2. 카카오 맵 로드 (autoload=false라서 명시적으로 load 호출 필요)
window.kakao.maps.load(() => {
const container = mapContainer.current;
🤖 Prompt for AI Agents
In `@components/map/kakaoMap.tsx` around lines 12 - 18, The silent early return in
the useEffect (the check "if (!window.kakao) return;") makes SDK load failures
invisible; update useEffect to detect missing window.kakao and handle it by
logging a clear console.warn/error and setting component state (e.g., sdkError
or sdkLoaded boolean) so the render can show fallback UI or an error message
instead of failing silently; keep the existing window.kakao.maps.load(...) path
unchanged but ensure the missing-SDK branch reports the problem and exposes it
to the UI for debugging (refer to useEffect, window.kakao,
window.kakao.maps.load, and the mapContainer ref).

if (!container) return;

const options = {
center: new window.kakao.maps.LatLng(37.5563, 126.9224), // 홍대입구역 좌표
level: 3, // 지도 확대 레벨
};

// 지도 생성
const map = new window.kakao.maps.Map(container, options);

// (선택) 마커 추가 예시
const markerPosition = new window.kakao.maps.LatLng(37.5563, 126.9224);
const marker = new window.kakao.maps.Marker({ position: markerPosition });
marker.setMap(map);
});
}, []);

return <div ref={mapContainer} className={className} />;
}
Loading
Loading