diff --git a/frontend/src/components/mypage/PushAlert/PushToggle.tsx b/frontend/src/components/mypage/PushAlert/PushToggle.tsx
new file mode 100644
index 000000000..6b6337267
--- /dev/null
+++ b/frontend/src/components/mypage/PushAlert/PushToggle.tsx
@@ -0,0 +1,22 @@
+import Toggle from 'components/@common/Toggle';
+import usePushAlert from 'hooks/@common/usePushAlert';
+import PushStatus from 'models/PushStatus';
+
+const PushToggle = () => {
+ const pushSupport = PushStatus.getIsSupport();
+ const notificationDenied = PushStatus.getPermission();
+ const { currentSubscribe, subscribeAlert, unSubscribeAlert } = usePushAlert();
+
+ return (
+
+ );
+};
+
+export default PushToggle;
diff --git a/frontend/src/components/mypage/PushAlert/index.tsx b/frontend/src/components/mypage/PushAlert/index.tsx
index c8ac82be1..29876d233 100644
--- a/frontend/src/components/mypage/PushAlert/index.tsx
+++ b/frontend/src/components/mypage/PushAlert/index.tsx
@@ -1,11 +1,9 @@
-import Toggle from 'components/@common/Toggle';
+import { Suspense } from 'react';
import { PushAlertContent, PushAlertWrapper, WarnParagraph } from './PushAlert.style';
-import usePushAlert from 'hooks/@common/usePushAlert';
import PushStatus from 'models/PushStatus';
+import PushToggle from './PushToggle';
const PushAlert = () => {
- const { currentSubscribe, subscribeAlert, unSubscribeAlert } = usePushAlert();
-
const pushSupport = PushStatus.getIsSupport();
const notificationDenied = PushStatus.getPermission();
@@ -13,14 +11,9 @@ const PushAlert = () => {
리마인더 알림 받기
-
+ 로딩중잉ㅂ니다?}>
+
+
{!pushSupport && 지원하지 않는 브라우저 또는 os입니다.}
{notificationDenied === 'denied' && (
diff --git a/frontend/src/hooks/@common/usePushAlert.ts b/frontend/src/hooks/@common/usePushAlert.ts
index 757a63abf..c82abd35a 100644
--- a/frontend/src/hooks/@common/usePushAlert.ts
+++ b/frontend/src/hooks/@common/usePushAlert.ts
@@ -1,6 +1,6 @@
import useWebPush from 'hooks/queries/auth/useWebPush';
+import FCMMessaging from 'models/FCMMessaging';
import PushStatus from 'models/PushStatus';
-import { getCurrentToken } from 'utils/firebase';
import useAddToast from './useAddToast';
const usePushAlert = () => {
@@ -14,21 +14,22 @@ const usePushAlert = () => {
}
// subscribe를 하지 않으려면 해당 토큰을 제거해야 한다.
+
const permission = await Notification.requestPermission();
+ PushStatus.setPermission(permission);
if (permission !== 'granted') {
addToast({ type: 'info', message: '알림이 허용되지 않았습니다', time: 3000 });
- PushStatus.setPermission(permission);
return;
}
-
// TODO: 사용자가 처음 알림 설정을 한 것인지 아니면 기존에
try {
let token = PushStatus.getCurrentToken();
// 이중 throw... 이게 괜찮은걸까?
if (token === null) {
- token = await getCurrentToken();
+ // TODO: 여기서 시간이 좀 걸림;;
+ token = await FCMMessaging.getCurrentToken();
if (token === null) throw new Error();
}
diff --git a/frontend/src/hooks/queries/auth/useWebPush.ts b/frontend/src/hooks/queries/auth/useWebPush.ts
index 2b56d00d3..e4d85305e 100644
--- a/frontend/src/hooks/queries/auth/useWebPush.ts
+++ b/frontend/src/hooks/queries/auth/useWebPush.ts
@@ -1,8 +1,8 @@
import { useMutation, useQueryClient, useSuspenseQuery } from '@tanstack/react-query';
import useAddToast from 'hooks/@common/useAddToast';
+import FCMMessaging from 'models/FCMMessaging';
import PushStatus from 'models/PushStatus';
import WebPushSubscribeAPI, { SUBSCRIBE_URL } from 'apis/webPush';
-import { deleteCurrentToken, getCurrentToken } from 'utils/firebase';
import noRetryIfUnauthorized from 'utils/noRetryIfUnauthorized';
import throwOnInvalidStatus from 'utils/throwOnInvalidStatus';
@@ -34,8 +34,8 @@ const useWebPush = () => {
queryClient.setQueryData([SUBSCRIBE_URL], context?.prevData);
addToast({ type: 'error', message: error.message });
- await deleteCurrentToken();
- const currentToken = await getCurrentToken();
+ await FCMMessaging.deleteCurrentToken();
+ const currentToken = await FCMMessaging.getCurrentToken();
PushStatus.setCurrentToken(currentToken);
},
onSettled: () => {
@@ -59,8 +59,8 @@ const useWebPush = () => {
return { prevData };
},
onSuccess: async () => {
- await deleteCurrentToken();
- const currentToken = await getCurrentToken();
+ await FCMMessaging.deleteCurrentToken();
+ const currentToken = await FCMMessaging.getCurrentToken();
PushStatus.setCurrentToken(currentToken);
},
onError: (error, __, context) => {
diff --git a/frontend/src/models/FCMMessaging.ts b/frontend/src/models/FCMMessaging.ts
new file mode 100644
index 000000000..a4d3fb3cf
--- /dev/null
+++ b/frontend/src/models/FCMMessaging.ts
@@ -0,0 +1,70 @@
+import { Analytics, getAnalytics } from 'firebase/analytics';
+import { FirebaseApp, FirebaseOptions, initializeApp } from 'firebase/app';
+import { Messaging, deleteToken, getMessaging, getToken, onMessage } from 'firebase/messaging';
+
+const firebaseConfig = {
+ apiKey: 'AIzaSyAOEUhyDZ1FQ2Ly77t-TNEqzb-686teUKU',
+ authDomain: 'pium-7ddfe.firebaseapp.com',
+ projectId: 'pium-7ddfe',
+ storageBucket: 'pium-7ddfe.appspot.com',
+ messagingSenderId: '66938335591',
+ appId: '1:66938335591:web:88ebf4f7f9dba08031ffc2',
+ measurementId: 'G-8SL2D547VW',
+};
+
+class FCMMessaging {
+ private app: FirebaseApp | null = null;
+ private messaging: Messaging | null = null;
+ private analytics: Analytics | null = null;
+
+ constructor(config: FirebaseOptions) {
+ this.app = initializeApp(config);
+ this.analytics = getAnalytics(this.app);
+ }
+
+ checkMessaging() {
+ return this.messaging ? true : false;
+ }
+
+ registerMessaging() {
+ if (!this.app) throw new Error('메세지 등록을 위해서는 FCM 초기화가 필요합니다.');
+ this.messaging = getMessaging(this.app);
+ }
+
+ setOnMessaging() {
+ if (!this.messaging) return;
+ onMessage(this.messaging, (payload) => {
+ const { notification } = payload;
+
+ const notificationTitle = notification?.title ?? '피움 알림';
+ const notificationOptions = {
+ body: notification?.body ?? '내용이 없습니다',
+ icon: notification?.icon ?? './assets/favicon-32x32.png',
+ };
+ const foregroundNotification = new Notification(notificationTitle, notificationOptions);
+
+ foregroundNotification.onclick = function (event) {
+ event.preventDefault();
+ foregroundNotification.close();
+ };
+ });
+ }
+
+ async getCurrentToken() {
+ if (!this.messaging) throw new Error('등록된 메세지가 없어서 토큰을 반환할 수 없습니다');
+ const permission = Notification.permission;
+
+ if (permission !== 'granted') return null;
+
+ return await getToken(this.messaging, {
+ vapidKey: process.env.VAPID_PUBLIC_KEY ?? '',
+ });
+ }
+
+ async deleteCurrentToken() {
+ if (!this.messaging) throw new Error('등록된 메세지가 없어서 토큰을 삭제할 수 없습니다');
+ return await deleteToken(this.messaging);
+ }
+}
+
+export default new FCMMessaging(firebaseConfig);
diff --git a/frontend/src/models/PushStatus.ts b/frontend/src/models/PushStatus.ts
index da659114f..edbf5c058 100644
--- a/frontend/src/models/PushStatus.ts
+++ b/frontend/src/models/PushStatus.ts
@@ -1,5 +1,5 @@
// TODO: 클래스로 변환해서 사용해보기
-import { deleteCurrentToken } from 'utils/firebase';
+import FCMMessaging from './FCMMessaging';
type NotificationPermission = 'granted' | 'default' | 'denied';
@@ -17,7 +17,7 @@ export const isSupported =
const initialPushStatus: PushStatusState = {
pushSupport: isSupported,
currentToken: null,
- notificationPermission: Notification.permission,
+ notificationPermission: 'default',
};
class PushStatus {
@@ -28,7 +28,7 @@ class PushStatus {
if (pushStatus.notificationPermission !== 'granted') {
this.pushStatus.currentToken = null;
- await deleteCurrentToken();
+ await FCMMessaging.deleteCurrentToken();
}
}
@@ -47,7 +47,7 @@ class PushStatus {
async setPermission(permission: NotificationPermission) {
if (permission !== 'granted') {
this.pushStatus.currentToken = null;
- await deleteCurrentToken();
+ await FCMMessaging.deleteCurrentToken();
}
this.pushStatus.notificationPermission = permission;
diff --git a/frontend/src/registerServiceWork.ts b/frontend/src/registerServiceWork.ts
index afd686020..53bbb20ff 100644
--- a/frontend/src/registerServiceWork.ts
+++ b/frontend/src/registerServiceWork.ts
@@ -1,9 +1,12 @@
-import PushStatus, { isSupported } from 'models/PushStatus';
-import { getCurrentToken } from 'utils/firebase';
+import { isSupported } from 'firebase/messaging';
+import FCMMessaging from 'models/FCMMessaging';
+import PushStatus, { isSupported as isBrowserSupport } from 'models/PushStatus';
const registerPwaServiceWorker = async (workerPath: string) => {
// 지원하지 않는 브라우저라면 return;
- if (!isSupported) {
+ const FCMSupported = await isSupported();
+
+ if (!isBrowserSupport || !FCMSupported) {
return;
}
// 기존에 있던 서비스 워커를 가져옴
@@ -22,16 +25,13 @@ const registerPwaServiceWorker = async (workerPath: string) => {
}
}
- // 새로운 서비스워커로 업데이트
- // 초기에 시작할 때 currentToken을 일단 받음
- // permission을 물어보지 않아서 getCurrentToken을 받아올 수 없음.
-
- const currentToken = await getCurrentToken();
+ FCMMessaging.registerMessaging();
+ FCMMessaging.setOnMessaging();
PushStatus.updatePushStatus({
- notificationPermission: Notification.permission,
- currentToken,
- pushSupport: isSupported,
+ notificationPermission: 'default',
+ currentToken: null,
+ pushSupport: FCMSupported && isBrowserSupport,
});
};
diff --git a/frontend/src/utils/firebase.ts b/frontend/src/utils/firebase.ts
deleted file mode 100644
index 76617b5c5..000000000
--- a/frontend/src/utils/firebase.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-// Import the functions you need from the SDKs you need
-import { getAnalytics } from 'firebase/analytics';
-import { initializeApp } from 'firebase/app';
-import { deleteToken, getMessaging, getToken, onMessage } from 'firebase/messaging';
-
-// TODO: Add SDKs for Firebase products that you want to use
-// https://firebase.google.com/docs/web/setup#available-libraries
-
-// Your web app's Firebase configuration
-// For Firebase JS SDK v7.20.0 and later, measurementId is optional
-const firebaseConfig = {
- apiKey: 'AIzaSyAOEUhyDZ1FQ2Ly77t-TNEqzb-686teUKU',
- authDomain: 'pium-7ddfe.firebaseapp.com',
- projectId: 'pium-7ddfe',
- storageBucket: 'pium-7ddfe.appspot.com',
- messagingSenderId: '66938335591',
- appId: '1:66938335591:web:88ebf4f7f9dba08031ffc2',
- measurementId: 'G-8SL2D547VW',
-};
-
-// Initialize Firebase
-const app = initializeApp(firebaseConfig);
-const analytics = getAnalytics(app);
-const messaging = getMessaging(app);
-
-/**
- * firebase에서 pushManager를 등록하지 않고도 값 사용이 가능한 이유.
- *
- * getToken 메서드에서 getTokenInternal이라는 메서드를 return 하는데, getPushSubscription 이라는 메서드에서 pushManager를 통해서 serviceWorker에 등록을 하기 때문.
- * getTokenInternal를 호출 하기 전 vapidKey를 업데이트 하고, 해당 messaging 객체를 넘겨준다.
- *
- * https://github.dev/firebase/firebase-js-sdk
- */
-
-const getCurrentToken = async () => {
- const permission = Notification.permission;
-
- if (permission !== 'granted') return null;
-
- return await getToken(messaging, {
- vapidKey: process.env.VAPID_PUBLIC_KEY ?? '',
- });
-};
-
-const deleteCurrentToken = async () => await deleteToken(messaging);
-
-onMessage(messaging, (payload) => {
- const { notification } = payload;
-
- const notificationTitle = notification?.title ?? '피움 알림';
- const notificationOptions = {
- body: notification?.body ?? '내용이 없습니다',
- icon: notification?.icon ?? './assets/favicon-32x32.png',
- };
- const foregroundNotification = new Notification(notificationTitle, notificationOptions);
-
- foregroundNotification.onclick = function (event) {
- event.preventDefault();
- foregroundNotification.close();
- };
-});
-
-export { analytics, messaging, getCurrentToken, deleteCurrentToken };