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
49 changes: 49 additions & 0 deletions app/firebase-messaging-sw.js/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { NextResponse } from "next/server";

export const dynamic = "force-dynamic";

export async function GET() {
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};

// Firebase SDK 버전은 package.json과 일치시킵니다. (현재 12.8.0 확인됨)
const script = `
importScripts("https://www.gstatic.com/firebasejs/12.8.0/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/12.8.0/firebase-messaging-compat.js");

const firebaseConfig = ${JSON.stringify(firebaseConfig)};

if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
}
const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
console.log("[Service Worker] 백그라운드 메시지 수신:", payload);

const notificationTitle = payload.notification?.title || "새 알림";
const notificationOptions = {
body: payload.notification?.body || "",
icon: payload.notification?.icon || "/logo/logo.svg",
};

self.registration.showNotification(notificationTitle, notificationOptions);
});
`;

return new NextResponse(script, {
headers: {
"Content-Type": "application/javascript",
"Cache-Control": "no-store, no-cache, must-revalidate, proxy-revalidate",
Pragma: "no-cache",
Expires: "0",
},
});
}
14 changes: 12 additions & 2 deletions components/common/FcmInitializer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@ import { registerServiceWorkerAndGetToken } from "@/lib/firebase";
import { api } from "@/lib/axios";

const FCM_REGISTERED_KEY = "fcm_registered";
const PUBLIC_PATHS = ["/login", "/register", "/terms", "/privacy", "/reset"];
const PUBLIC_PATHS = [
"/",
"/login",
"/register",
"/terms",
"/privacy",
"/reset",
];

export default function FcmInitializer() {
const pathname = usePathname();

useEffect(() => {
// 공개 페이지에서는 실행 안 함
if (PUBLIC_PATHS.some((path) => pathname.startsWith(path))) return;
const isPublicPath = PUBLIC_PATHS.some((path) =>
path === "/" ? pathname === "/" : pathname.startsWith(path),
);
if (isPublicPath) return;

// 세션 당 1회만 실행 (페이지 이동마다 중복 등록 방지)
if (sessionStorage.getItem(FCM_REGISTERED_KEY)) return;
Expand Down
2 changes: 1 addition & 1 deletion lib/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ api.interceptors.response.use(
} catch (reissueError) {
// 재발급 실패 → 로그인 페이지로 리다이렉트
alert("로그인 세션이 만료되었습니다. 다시 로그인해주세요.");
window.location.href = "/login";
window.location.href = "/";
return Promise.reject(reissueError);
}
}
Expand Down
35 changes: 1 addition & 34 deletions lib/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,51 +24,18 @@ if (typeof window !== "undefined") {
analytics = getAnalytics(app);
}

// 서비스 워커가 active 상태가 될 때까지 기다리는 헬퍼
function waitForServiceWorkerActive(
registration: ServiceWorkerRegistration,
): Promise<ServiceWorker> {
return new Promise((resolve) => {
if (registration.active) {
resolve(registration.active);
return;
}
const sw = registration.installing ?? registration.waiting;
if (!sw) {
// fallback: navigator.serviceWorker.ready 사용
navigator.serviceWorker.ready.then((r) => resolve(r.active!));
return;
}
sw.addEventListener("statechange", function handler() {
if (sw.state === "activated") {
sw.removeEventListener("statechange", handler);
resolve(sw);
}
});
});
}

// 서비스 워커 등록 및 FCM 토큰 가져오기
export async function registerServiceWorkerAndGetToken() {
if (typeof window === "undefined" || !("serviceWorker" in navigator)) {
return null;
}

try {
// 서비스 워커 등록
// 서비스 워커 등록 (SW 자체에서 Firebase 초기화하므로 postMessage 불필요)
const registration = await navigator.serviceWorker.register(
"/firebase-messaging-sw.js",
);

// 서비스 워커가 완전히 active 상태가 될 때까지 대기
const activeSW = await waitForServiceWorkerActive(registration);

// 서비스 워커에 Firebase Config 전달 (active 보장 후)
activeSW.postMessage({
type: "INIT_FIREBASE",
config: firebaseConfig,
});

// Messaging 인스턴스 가져오기
const messaging = getMessaging(app);

Expand Down
38 changes: 0 additions & 38 deletions public/firebase-messaging-sw.js

This file was deleted.

Loading