From df82860794c4f1d4960d3678d563ec6eb535e46c Mon Sep 17 00:00:00 2001 From: taerim Date: Fri, 22 Aug 2025 14:43:10 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=ED=91=B8=EC=8B=9C=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Time-Up/App.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Time-Up/App.tsx b/Time-Up/App.tsx index 8d0cbaa..72806b6 100644 --- a/Time-Up/App.tsx +++ b/Time-Up/App.tsx @@ -43,6 +43,7 @@ import SetRemindAlarmPage from './src/pages/SetPage/SetRemindAlarmPage'; import SetScheduleRepeatPage from './src/pages/SetScheduleRepeatPage'; import ViewScheduleDetailPage from './src/pages/ViewScheduleDetailPage'; +import { saveFCMPushToken } from './src/apis/pushToken'; import { getAccessToken } from './src/utils/storage'; import { requestWebPushToken } from './src/utils/webPush'; @@ -120,6 +121,7 @@ export default function App() { let cancelled = false; (async () => { + debugger; try { const token = await requestWebPushToken(); if (!token || cancelled) { @@ -128,12 +130,12 @@ export default function App() { } console.log('Web FCM Token:', token); - // const res = await saveFCMPushToken(token); - // if ((res as any)?.result === 'Error') { - // console.warn('웹 push-token 저장 실패:', (res as any)?.error); - // } else { - // console.log('웹 push-token 저장 성공'); - // } + const res = await saveFCMPushToken(token); + if ((res as any)?.result === 'Error') { + console.warn('웹 push-token 저장 실패:', (res as any)?.error); + } else { + console.log('웹 push-token 저장 성공'); + } } catch (e) { console.warn('웹 푸시 토큰 발급/저장 실패:', e); } From 7a727f3dda43f93feea12d5d6ffcd89957312a81 Mon Sep 17 00:00:00 2001 From: taerim Date: Fri, 22 Aug 2025 16:04:28 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=ED=91=B8=EC=8B=9C=20=EC=95=8C?= =?UTF-8?q?=EB=9E=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Time-Up/App.tsx | 29 +++++--- .../src/pages/Alarm/My/EditMyAlarmPage.tsx | 2 +- .../src/pages/Alarm/My/MyAlarmDetailPage.tsx | 2 +- Time-Up/src/pages/Alarm/My/MyAlarmPage.tsx | 1 - .../Alarm/WakeUp/EditWakeUpAlarmPage.tsx | 7 +- .../Alarm/WakeUp/WakeUpAlarmDetailPage.tsx | 2 +- .../src/pages/Onboarding/OnboardingPage.tsx | 1 - Time-Up/src/utils/webPush.ts | 69 ++++++------------- Time-Up/src/utils/webToken.ts | 69 +++++++++++++++++++ 9 files changed, 116 insertions(+), 66 deletions(-) create mode 100644 Time-Up/src/utils/webToken.ts diff --git a/Time-Up/App.tsx b/Time-Up/App.tsx index 72806b6..f4a896c 100644 --- a/Time-Up/App.tsx +++ b/Time-Up/App.tsx @@ -43,9 +43,9 @@ import SetRemindAlarmPage from './src/pages/SetPage/SetRemindAlarmPage'; import SetScheduleRepeatPage from './src/pages/SetScheduleRepeatPage'; import ViewScheduleDetailPage from './src/pages/ViewScheduleDetailPage'; -import { saveFCMPushToken } from './src/apis/pushToken'; import { getAccessToken } from './src/utils/storage'; -import { requestWebPushToken } from './src/utils/webPush'; +import { initWebPush } from './src/utils/webPush'; +import { requestWebPushToken } from './src/utils/webToken'; const queryClient = new QueryClient(); @@ -121,7 +121,6 @@ export default function App() { let cancelled = false; (async () => { - debugger; try { const token = await requestWebPushToken(); if (!token || cancelled) { @@ -130,12 +129,12 @@ export default function App() { } console.log('Web FCM Token:', token); - const res = await saveFCMPushToken(token); - if ((res as any)?.result === 'Error') { - console.warn('웹 push-token 저장 실패:', (res as any)?.error); - } else { - console.log('웹 push-token 저장 성공'); - } + // const res = await saveFCMPushToken(token); + // if ((res as any)?.result === 'Error') { + // console.warn('웹 push-token 저장 실패:', (res as any)?.error); + // } else { + // console.log('웹 push-token 저장 성공'); + // } } catch (e) { console.warn('웹 푸시 토큰 발급/저장 실패:', e); } @@ -146,6 +145,18 @@ export default function App() { }; }, []); + useEffect(() => { + (async () => { + try { + const token = await initWebPush(); + console.log('FCM 웹 토큰:', token); + // 이미 토큰 저장 API는 구현했다 했으니 여기선 로깅만 + } catch (e) { + console.warn('웹 푸시 초기화 실패:', e); + } + })(); + }, []); + if (!mapsLoaded || !initialRoute) return null; const content = ( diff --git a/Time-Up/src/pages/Alarm/My/EditMyAlarmPage.tsx b/Time-Up/src/pages/Alarm/My/EditMyAlarmPage.tsx index ff6e019..23a86f7 100644 --- a/Time-Up/src/pages/Alarm/My/EditMyAlarmPage.tsx +++ b/Time-Up/src/pages/Alarm/My/EditMyAlarmPage.tsx @@ -466,7 +466,7 @@ export default function EditMyAlarmPage() { - + diff --git a/Time-Up/src/pages/Alarm/My/MyAlarmDetailPage.tsx b/Time-Up/src/pages/Alarm/My/MyAlarmDetailPage.tsx index 8f5290e..c8b8bfa 100644 --- a/Time-Up/src/pages/Alarm/My/MyAlarmDetailPage.tsx +++ b/Time-Up/src/pages/Alarm/My/MyAlarmDetailPage.tsx @@ -172,7 +172,7 @@ export default function MyAlarmDetailPage() { - + diff --git a/Time-Up/src/pages/Alarm/My/MyAlarmPage.tsx b/Time-Up/src/pages/Alarm/My/MyAlarmPage.tsx index 75a9cb9..98aa8b3 100644 --- a/Time-Up/src/pages/Alarm/My/MyAlarmPage.tsx +++ b/Time-Up/src/pages/Alarm/My/MyAlarmPage.tsx @@ -92,7 +92,6 @@ export default function MyAlarmPage() { } }; - // const handleToggleAutoAlarm = async () => { // try { // if (nextAutoAlarm?.auto_alarm_id != null) { diff --git a/Time-Up/src/pages/Alarm/WakeUp/EditWakeUpAlarmPage.tsx b/Time-Up/src/pages/Alarm/WakeUp/EditWakeUpAlarmPage.tsx index 4e81252..090efae 100644 --- a/Time-Up/src/pages/Alarm/WakeUp/EditWakeUpAlarmPage.tsx +++ b/Time-Up/src/pages/Alarm/WakeUp/EditWakeUpAlarmPage.tsx @@ -6,7 +6,7 @@ import { AlarmItem } from '@/src/types/alarm'; import { toPutWakeupAlarmRequest } from '@/src/utils/alarmTransform'; import { BottomSheetModal, BottomSheetView } from '@gorhom/bottom-sheet'; import React, { useCallback, useMemo, useRef, useState } from 'react'; -import { Dimensions, Platform, ScrollView, Text, TextInput, TouchableOpacity, View } from 'react-native'; +import { Dimensions, Platform, Text, TextInput, TouchableOpacity, View } from 'react-native'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import ToggleSwitch from '../../../components/common/ToggleSwitch'; import { Day, useAlarmContext } from '../../../contexts/AlarmContext'; @@ -159,7 +159,6 @@ export default function EditWakeUpAlarmPage() { return ( - - + 반복요일 @@ -356,12 +355,12 @@ export default function EditWakeUpAlarmPage() { - + ); diff --git a/Time-Up/src/pages/Alarm/WakeUp/WakeUpAlarmDetailPage.tsx b/Time-Up/src/pages/Alarm/WakeUp/WakeUpAlarmDetailPage.tsx index 622cd27..fb1266f 100644 --- a/Time-Up/src/pages/Alarm/WakeUp/WakeUpAlarmDetailPage.tsx +++ b/Time-Up/src/pages/Alarm/WakeUp/WakeUpAlarmDetailPage.tsx @@ -182,7 +182,7 @@ export default function WakeUpAlarmDetailPage() { - + diff --git a/Time-Up/src/pages/Onboarding/OnboardingPage.tsx b/Time-Up/src/pages/Onboarding/OnboardingPage.tsx index 61789f6..d20ed83 100644 --- a/Time-Up/src/pages/Onboarding/OnboardingPage.tsx +++ b/Time-Up/src/pages/Onboarding/OnboardingPage.tsx @@ -67,7 +67,6 @@ export default function OnboardingPage() { } if (data.success?.isNew) { - debugger; try { await refreshAlarms(); } catch (e) { diff --git a/Time-Up/src/utils/webPush.ts b/Time-Up/src/utils/webPush.ts index f3a7ce0..a7cdb4c 100644 --- a/Time-Up/src/utils/webPush.ts +++ b/Time-Up/src/utils/webPush.ts @@ -1,6 +1,7 @@ // src/utils/webPush.ts +// webPush.ts (예: 앱 시작 시 1회 호출) import { initializeApp } from 'firebase/app'; -import { getMessaging, getToken } from 'firebase/messaging'; +import { getMessaging, getToken, isSupported, onMessage } from 'firebase/messaging'; const firebaseConfig = { apiKey: "AIzaSyAEAKbupll7pRrAuhCtI0SbHRAx-rXj7oM", @@ -11,59 +12,31 @@ const firebaseConfig = { }; const app = initializeApp(firebaseConfig); -export const messaging = getMessaging(app); -// 1) 푸시 권한 요청 + 2) 서비스워커 등록 + 3) FCM 웹 토큰 발급 -// export async function requestWebPushToken(): Promise { -// if (!('Notification' in window)) return null; - -// const permission = await Notification.requestPermission(); -// if (permission !== 'granted') return null; - -// // 이미 public/index.html에서 /firebase-messaging-sw.js 를 등록했지만, -// // 안전하게 등록 객체를 getToken에 넘겨 위치를 명시. (Firebase 공식 지원) -// const registration = await navigator.serviceWorker.getRegistration('/') -// ?? await navigator.serviceWorker.register('/firebase-messaging-sw.js'); - -// const token = await getToken(messaging, { -// vapidKey: 'BK6LHOnQzm8od0iib8gPwgv7K6eI43xNDDhpVRLkNTXWZ4jVfxCfaTwy-HPNqHeoiPyM3C3o7sUhPIOHBSetyUc', -// serviceWorkerRegistration: registration, -// }); - -// return token || null; -// } +export async function initWebPush() { + const supported = await isSupported(); + if (!supported) { + console.warn('이 브라우저는 FCM을 지원하지 않습니다.'); + return null; + } -export async function requestWebPushToken(): Promise { - if (!('Notification' in window)) return null; + const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js', { scope: '/' }); - const permission = await Notification.requestPermission(); - if (permission !== 'granted') { - console.warn('웹 푸시 권한 거부됨'); + const perm = await Notification.requestPermission(); + if (perm !== 'granted') { + console.warn('알림 권한이 거부되었습니다.'); return null; } - let registration = await navigator.serviceWorker.getRegistration('/'); - if (!registration) { - registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js', { scope: '/' }); - } + const messaging = getMessaging(app); + const token = await getToken(messaging, { + vapidKey: 'BK6LHOnQzm8od0iib8gPwgv7K6eI43xNDDhpVRLkNTXWZ4jVfxCfaTwy-HPNqHeoiPyM3C3o7sUhPIOHBSetyUc', + serviceWorkerRegistration: registration, + }); - // 2) 활성화(ready)까지 대기 - await navigator.serviceWorker.ready; + onMessage(messaging, (payload) => { + console.log('[foreground] FCM payload:', payload); + }); - try { - const token = await getToken(messaging, { - vapidKey: 'BK6LHOnQzm8od0iib8gPwgv7K6eI43xNDDhpVRLkNTXWZ4jVfxCfaTwy-HPNqHeoiPyM3C3o7sUhPIOHBSetyUc', - serviceWorkerRegistration: registration, - }); - if (!token) { - console.warn('토큰이 비어 있음 (권한/HTTPS/도메인/스코프 확인 필요)'); - return null; - } - console.log('Web FCM Token:', token); // 정상 발급 - return token; - } catch (e: any) { - console.error('getToken 실패:', e?.code, e?.message, e); - return null; - } + return token; } - diff --git a/Time-Up/src/utils/webToken.ts b/Time-Up/src/utils/webToken.ts new file mode 100644 index 0000000..6bf9cd9 --- /dev/null +++ b/Time-Up/src/utils/webToken.ts @@ -0,0 +1,69 @@ +// src/utils/webToken.ts +import { initializeApp } from 'firebase/app'; +import { getMessaging, getToken } from 'firebase/messaging'; + +const firebaseConfig = { + apiKey: "AIzaSyAEAKbupll7pRrAuhCtI0SbHRAx-rXj7oM", + authDomain: "timeup-80358.firebaseapp.com", + projectId: "timeup-80358", + messagingSenderId: "482152461783", + appId: "1:482152461783:web:8ee854bcf8cad1ab3bc792", +}; + +const app = initializeApp(firebaseConfig); +export const messaging = getMessaging(app); + +// 1) 푸시 권한 요청 + 2) 서비스워커 등록 + 3) FCM 웹 토큰 발급 +// export async function requestWebPushToken(): Promise { +// if (!('Notification' in window)) return null; + +// const permission = await Notification.requestPermission(); +// if (permission !== 'granted') return null; + +// // 이미 public/index.html에서 /firebase-messaging-sw.js 를 등록했지만, +// // 안전하게 등록 객체를 getToken에 넘겨 위치를 명시. (Firebase 공식 지원) +// const registration = await navigator.serviceWorker.getRegistration('/') +// ?? await navigator.serviceWorker.register('/firebase-messaging-sw.js'); + +// const token = await getToken(messaging, { +// vapidKey: 'BK6LHOnQzm8od0iib8gPwgv7K6eI43xNDDhpVRLkNTXWZ4jVfxCfaTwy-HPNqHeoiPyM3C3o7sUhPIOHBSetyUc', +// serviceWorkerRegistration: registration, +// }); + +// return token || null; +// } + +export async function requestWebPushToken(): Promise { + if (!('Notification' in window)) return null; + + const permission = await Notification.requestPermission(); + if (permission !== 'granted') { + console.warn('웹 푸시 권한 거부됨'); + return null; + } + + let registration = await navigator.serviceWorker.getRegistration('/'); + if (!registration) { + registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js', { scope: '/' }); + } + + // 2) 활성화(ready)까지 대기 + await navigator.serviceWorker.ready; + + try { + const token = await getToken(messaging, { + vapidKey: 'BK6LHOnQzm8od0iib8gPwgv7K6eI43xNDDhpVRLkNTXWZ4jVfxCfaTwy-HPNqHeoiPyM3C3o7sUhPIOHBSetyUc', + serviceWorkerRegistration: registration, + }); + if (!token) { + console.warn('토큰이 비어 있음 (권한/HTTPS/도메인/스코프 확인 필요)'); + return null; + } + console.log('Web FCM Token:', token); // 정상 발급 + return token; + } catch (e: any) { + console.error('getToken 실패:', e?.code, e?.message, e); + return null; + } +} +