From f8660bdd4b3f166bbc4ff0b76d699d3ff8a7a2a8 Mon Sep 17 00:00:00 2001 From: Kangdy Date: Tue, 24 Feb 2026 21:01:17 +0900 Subject: [PATCH 1/2] =?UTF-8?q?chore:=20@next/third-parties=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=ED=95=9C=20Google=20Analytics=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/layout.tsx | 2 ++ package.json | 1 + pnpm-lock.yaml | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/app/layout.tsx b/app/layout.tsx index 8cfc97c..a0e2476 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -6,6 +6,7 @@ import Header from '../components/header'; import Footer from '../components/footer'; import GlobalModal from '@/components/modal/globalModal'; import QueryProvider from '@/components/providers/queryProvider'; +import { GoogleAnalytics } from '@next/third-parties/google'; const pretendard = localFont({ src: [ @@ -49,6 +50,7 @@ export default function RootLayout({ strategy="beforeInteractive" /> + ); } diff --git a/package.json b/package.json index bcb223e..f6dbc53 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "eslint" }, "dependencies": { + "@next/third-parties": "^16.1.6", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-tooltip": "^1.1.3", "@tanstack/react-query": "^5.90.16", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54dad2e..40c351b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@next/third-parties': + specifier: ^16.1.6 + version: 16.1.6(next@16.1.6(@babel/core@7.28.5)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) '@radix-ui/react-dialog': specifier: ^1.1.15 version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -453,6 +456,12 @@ packages: cpu: [x64] os: [win32] + '@next/third-parties@16.1.6': + resolution: {integrity: sha512-/cLY1egaH529ylSMSK+C8dA3nWDLL4hOFR4fca9OLWWxjcNwzsbuq2pPb/tmdWL9Zj3K1nTjd1pWQoSlaDQ0VA==} + peerDependencies: + next: ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0-beta.0 + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2245,6 +2254,9 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + third-party-capital@1.0.20: + resolution: {integrity: sha512-oB7yIimd8SuGptespDAZnNkzIz+NWaJCu2RMsbs4Wmp9zSDUM8Nhi3s2OOcqYuv3mN4hitXc8DVx+LyUmbUDiA==} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -2747,6 +2759,12 @@ snapshots: '@next/swc-win32-x64-msvc@16.1.6': optional: true + '@next/third-parties@16.1.6(next@16.1.6(@babel/core@7.28.5)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': + dependencies: + next: 16.1.6(@babel/core@7.28.5)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + third-party-capital: 1.0.20 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4642,6 +4660,8 @@ snapshots: tapable@2.3.0: {} + third-party-capital@1.0.20: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) From babf8e470406b974a3d2a2d2c3ebe9103bb06735 Mon Sep 17 00:00:00 2001 From: Kangdy Date: Wed, 25 Feb 2026 22:53:30 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EB=AA=A8=EC=9E=84=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1(url=5Fcreated)=20GA4=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=8A=B8=EB=9E=98=ED=82=B9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/create/page.tsx | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/app/create/page.tsx b/app/create/page.tsx index c0a0ee6..474e94a 100644 --- a/app/create/page.tsx +++ b/app/create/page.tsx @@ -7,6 +7,7 @@ import { useCreateMeeting } from '@/hooks/api/mutation/useCreateMeeting'; import type { MeetingCreateRequest } from '@/types/api'; import { useToast } from '@/hooks/useToast'; import Toast from '@/components/ui/toast'; +import { sendGAEvent } from '@next/third-parties/google'; export default function Page() { const [meetingName, setMeetingName] = useState(''); @@ -123,7 +124,7 @@ export default function Page() { const purposes = getPurposes(); - // capacity 처리: "아직 안정해졌어요" 체크 시 30으로 설정 + // capacity 처리: "아직 안정해졌어요" 체크 시 10으로 설정 const capacity = isParticipantUndecided ? 10 : participantCount || 1; const requestData: MeetingCreateRequest = { @@ -142,6 +143,27 @@ export default function Page() { const { meetingId } = result.data; console.log('생성된 ID:', meetingId); + // --- [GA4 이벤트 전송 로직 추가] --- + if (typeof window !== 'undefined') { + // 1. 브라우저 식별자(browser_id) 확인 및 생성 (Get or Create) + let browserId = localStorage.getItem('browser_id'); + if (!browserId) { + // 없으면 새로 발급해서 브라우저에 각인! + const randomStr = Math.random().toString(36).substring(2, 15); + browserId = `bid_${randomStr}${Date.now().toString(36)}`; + localStorage.setItem('browser_id', browserId); + } + + // 2. 방 만든 브라우저가 누구인지 식별자를 담아서 이벤트 전송 + sendGAEvent('event', 'url_created', { + meeting_url_id: meetingId, + participant_count_expected: capacity, + browser_id: browserId, + entry_method: 'url_direct', + }); + } + // ----------------------------------- + // purposes를 localStorage에 저장 (장소 추천 카테고리로 사용) const purposes = getPurposes(); if (purposes.length > 0) {