From c440af8857b9fd3d0632b6c8c92c605d445ee155 Mon Sep 17 00:00:00 2001 From: kimtaewoo <70637743+kim3360@users.noreply.github.com> Date: Sat, 28 Feb 2026 23:21:09 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat=20:=205.=20=EC=A4=91=EA=B0=84=EC=A7=80?= =?UTF-8?q?=EC=A0=90=20=EC=82=B0=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/meeting/[id]/page.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app/meeting/[id]/page.tsx b/app/meeting/[id]/page.tsx index 64b5433..e256974 100644 --- a/app/meeting/[id]/page.tsx +++ b/app/meeting/[id]/page.tsx @@ -15,7 +15,7 @@ import MeetingInfoSection from '@/components/meeting/MeetingInfoSection'; import { useToast } from '@/hooks/useToast'; import Toast from '@/components/ui/toast'; import { getMeetingUserId, removeMeetingUserId } from '@/lib/storage'; - +import { sendGAEvent } from '@next/third-parties/google'; interface StationInfo { line: string; name: string; @@ -127,6 +127,21 @@ export default function Page() { show(); return; } + + if (typeof window !== 'undefined') { + const calculationType = id ? 'recalculated' : 'first'; + const isHost = localStorage.getItem(`browser_id`) !== null; + const role_type = isHost ? 'host' : 'participant'; + const browserId = localStorage.getItem('browser_id'); + + sendGAEvent('event', 'midpoint_calculated', { + meeting_url_id: id, + browser_id: browserId, + role: role_type, + calculation_type: calculationType, + }); + } + router.push(`/result/${id}`); }; From 6af45037de651458c78f3949967c9c413c5ba5be Mon Sep 17 00:00:00 2001 From: kimtaewoo <70637743+kim3360@users.noreply.github.com> Date: Mon, 2 Mar 2026 02:23:18 +0900 Subject: [PATCH 2/6] =?UTF-8?q?fix=20:=20=EC=A4=91=EA=B0=84=EC=A7=80?= =?UTF-8?q?=EC=A0=90=20=EC=A1=B0=ED=9A=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/meeting/[id]/page.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/meeting/[id]/page.tsx b/app/meeting/[id]/page.tsx index fd077a1..0e7af71 100644 --- a/app/meeting/[id]/page.tsx +++ b/app/meeting/[id]/page.tsx @@ -172,14 +172,14 @@ export default function Page() { if (typeof window !== 'undefined') { const calculationType = id ? 'recalculated' : 'first'; - const isHost = localStorage.getItem(`browser_id`) !== null; - const role_type = isHost ? 'host' : 'participant'; + const isHost = localStorage.getItem(`is_host_${id}`) === 'true'; + const userRole = isHost ? 'host' : 'participant'; const browserId = localStorage.getItem('browser_id'); sendGAEvent('event', 'midpoint_calculated', { meeting_url_id: id, browser_id: browserId, - role: role_type, + role: userRole, calculation_type: calculationType, }); } From cf4841fa1402e9fdba4406628ebf5209c12f7543 Mon Sep 17 00:00:00 2001 From: kimtaewoo <70637743+kim3360@users.noreply.github.com> Date: Mon, 2 Mar 2026 02:28:25 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat=20:=206.=20=EC=A4=91=EA=B0=84=EC=A7=80?= =?UTF-8?q?=EC=A0=90=20=EB=B9=84=EA=B5=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/result/[id]/page.tsx | 44 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/app/result/[id]/page.tsx b/app/result/[id]/page.tsx index a9ca6b5..5fb5325 100644 --- a/app/result/[id]/page.tsx +++ b/app/result/[id]/page.tsx @@ -149,6 +149,41 @@ export default function Page() { const [selectedResultId, setSelectedResultId] = useState(1); + // 중간지점 후보 조회 GA 이벤트 (role: meeting 페이지와 동일한 is_host_${id} 기준) + const trackMidpointCandidateViewed = useCallback( + (candidateRankOrder: number, candidateId: string) => { + if (typeof window === 'undefined' || !id) return; + let browserId = localStorage.getItem('browser_id'); + if (!browserId) { + browserId = `bid_${Math.random().toString(36).substring(2, 15)}${Date.now().toString(36)}`; + localStorage.setItem('browser_id', browserId); + } + const isHost = localStorage.getItem(`is_host_${id}`) === 'true'; + const userRole = isHost ? 'host' : 'participant'; + + sendGAEvent('event', 'midpoint_candidate_viewed', { + meeting_url_id: id, + user_cookie_id: browserId, + role: userRole, + candidate_rank_order: candidateRankOrder, + candidate_id: candidateId, + }); + }, + [id] + ); + + // 장소 리스트에서 결과보기 페이지로 돌아왔을 때 midpoint_candidate_viewed 전송 + useEffect(() => { + if (typeof window === 'undefined' || !id || locationResults.length === 0) return; + const fromRecommend = sessionStorage.getItem(`from_recommend_${id}`); + if (fromRecommend !== '1') return; + + sessionStorage.removeItem(`from_recommend_${id}`); + const selected = locationResults.find((r) => r.id === selectedResultId) ?? locationResults[0]; + const candidateId = `mid_${selected.endStation.replace(/\s+/g, '_')}`; + trackMidpointCandidateViewed(selected.id, candidateId); + }, [id, locationResults, selectedResultId, trackMidpointCandidateViewed]); + // 뒤로 가기 클릭 시 캐시 데이터 무효화 const clearRelatedCache = useCallback(() => { queryClient.removeQueries({ queryKey: ['midpoint', id] }); @@ -280,13 +315,20 @@ export default function Page() { if (meetingType) params.append('meetingType', meetingType); if (categoryParam) params.append('category', categoryParam); + if (typeof window !== 'undefined') { + sessionStorage.setItem(`from_recommend_${id}`, '1'); + } router.push(`/recommend?${params.toString()}`); }; return (
setSelectedResultId(result.id)} + onClick={() => { + setSelectedResultId(result.id); + const candidateId = `mid_${result.endStation.replace(/\s+/g, '_')}`; + trackMidpointCandidateViewed(result.id, candidateId); + }} className={`flex cursor-pointer flex-col gap-3.75 rounded border bg-white p-5 ${ selectedResultId === result.id ? 'border-blue-5 border-2' From 6f868bcaad7bbb51f688790faaf033314f1b0ab0 Mon Sep 17 00:00:00 2001 From: kimtaewoo <70637743+kim3360@users.noreply.github.com> Date: Mon, 2 Mar 2026 02:29:21 +0900 Subject: [PATCH 4/6] =?UTF-8?q?fix=20:=206.=20=EC=A4=91=EA=B0=84=EC=A7=80?= =?UTF-8?q?=EC=A0=90=20=EC=A1=B0=ED=9A=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/result/[id]/page.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/result/[id]/page.tsx b/app/result/[id]/page.tsx index 5fb5325..66b921d 100644 --- a/app/result/[id]/page.tsx +++ b/app/result/[id]/page.tsx @@ -149,15 +149,11 @@ export default function Page() { const [selectedResultId, setSelectedResultId] = useState(1); - // 중간지점 후보 조회 GA 이벤트 (role: meeting 페이지와 동일한 is_host_${id} 기준) + // 중간지점 후보 조회 GA 이벤트 const trackMidpointCandidateViewed = useCallback( (candidateRankOrder: number, candidateId: string) => { if (typeof window === 'undefined' || !id) return; - let browserId = localStorage.getItem('browser_id'); - if (!browserId) { - browserId = `bid_${Math.random().toString(36).substring(2, 15)}${Date.now().toString(36)}`; - localStorage.setItem('browser_id', browserId); - } + const browserId = localStorage.getItem('browser_id'); const isHost = localStorage.getItem(`is_host_${id}`) === 'true'; const userRole = isHost ? 'host' : 'participant'; From 5755eb67f153d3f4aea6906ff3672ce22cfcd0e6 Mon Sep 17 00:00:00 2001 From: kimtaewoo <70637743+kim3360@users.noreply.github.com> Date: Mon, 2 Mar 2026 02:30:39 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat=20:=207.=20=EC=9E=A5=EC=86=8C=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A4=91=20=ED=95=98=EB=82=98=EC=9D=98=20?= =?UTF-8?q?=EC=9E=A5=EC=86=8C=20=ED=83=90=EC=83=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/recommend/page.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app/recommend/page.tsx b/app/recommend/page.tsx index f726b29..2fd6080 100644 --- a/app/recommend/page.tsx +++ b/app/recommend/page.tsx @@ -6,6 +6,7 @@ import Image from 'next/image'; import KakaoMapRecommend from '@/components/map/kakaoMapRecommend'; import { useRecommend } from '@/hooks/api/query/useRecommend'; import { useCheckMeeting } from '@/hooks/api/query/useCheckMeeting'; +import { sendGAEvent } from '@next/third-parties/google'; function RecommendContent() { const router = useRouter(); @@ -148,6 +149,20 @@ function RecommendContent() { } }; + // 장소 리스트 중 하나 클릭 시 GA 전송 (place_list_viewed) + const handlePlaceClick = (place: (typeof places)[0]) => { + setSelectedPlaceId(place.id); + if (meetingId) { + const candidateId = `place_${String(place.id).padStart(2, '0')}`; + sendGAEvent('event', 'place_list_viewed', { + meeting_url_id: meetingId, + candidate_id: candidateId, + place_category: place.category, + rank_order: place.id, + }); + } + }; + return (
@@ -194,7 +209,7 @@ function RecommendContent() { {places.map((place) => (
setSelectedPlaceId(place.id)} + onClick={() => handlePlaceClick(place)} className={`flex cursor-pointer flex-col gap-2 rounded border p-4 ${ selectedPlaceId === place.id ? 'border-blue-5 border-2' From d7ce582456cc0171829f6b6d6fb7c45bcb507b00 Mon Sep 17 00:00:00 2001 From: kimtaewoo <70637743+kim3360@users.noreply.github.com> Date: Mon, 2 Mar 2026 02:33:23 +0900 Subject: [PATCH 6/6] =?UTF-8?q?feat=20:=208.=20=EC=B9=B4=EC=B9=B4=EC=98=A4?= =?UTF-8?q?=EB=A7=B5=20=EC=99=B8=EB=B6=80=20=EA=B2=80=EC=A6=9D=20=EC=8B=9C?= =?UTF-8?q?=EB=8F=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/recommend/page.tsx | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/app/recommend/page.tsx b/app/recommend/page.tsx index 2fd6080..9e3b47c 100644 --- a/app/recommend/page.tsx +++ b/app/recommend/page.tsx @@ -140,8 +140,28 @@ function RecommendContent() { router.back(); }; - const handleOpenKakaoMap = (e: React.MouseEvent, placeUrl?: string) => { + const handleOpenKakaoMap = ( + e: React.MouseEvent, + placeUrl?: string, + place?: (typeof places)[0] + ) => { e.stopPropagation(); + + // 카카오맵에서 보기 클릭 시 GA 전송 (external_map_opened) + if (typeof window !== 'undefined' && meetingId && place) { + const browserId = localStorage.getItem('browser_id'); + const isHost = localStorage.getItem(`is_host_${meetingId}`) === 'true'; + const userRole = isHost ? 'host' : 'participant'; + const candidateId = `place_${String(place.id).padStart(2, '0')}`; + + sendGAEvent('event', 'external_map_opened', { + meeting_url_id: meetingId, + user_cookie_id: browserId, + role: userRole, + candidate_id: candidateId, + }); + } + if (placeUrl) { window.open(placeUrl, '_blank', 'noopener,noreferrer'); } else { @@ -262,7 +282,7 @@ function RecommendContent() { {/* 하단 버튼은 조건부 렌더링 */} {selectedPlaceId === place.id ? (