feat(WEB): FCM 푸시 알림 시스템 구현

- FCMProvider 컨텍스트 및 useFCM 훅 추가
- Capacitor FCM 플러그인 통합
- 알림 사운드 파일 추가 (default.wav, push_notification.wav)
- Firebase 메시징 패키지 의존성 추가
This commit is contained in:
2025-12-30 17:16:47 +09:00
parent d38b1242d7
commit f400f01db7
12 changed files with 927 additions and 1039 deletions

View File

@@ -0,0 +1,81 @@
'use client';
/**
* FCM Provider
*
* Capacitor 네이티브 앱에서 FCM 푸시 알림을 초기화합니다.
* RootProvider 또는 (protected)/layout.tsx에서 사용합니다.
*
* @example
* ```tsx
* // (protected)/layout.tsx
* import { FCMProvider } from '@/contexts/FCMProvider';
*
* export default function ProtectedLayout({ children }) {
* return (
* <RootProvider>
* <FCMProvider>
* {children}
* </FCMProvider>
* </RootProvider>
* );
* }
* ```
*/
import { ReactNode, createContext, useContext } from 'react';
import { useFCM } from '@/hooks/useFCM';
// ===== Context 타입 =====
interface FCMContextType {
cleanup: () => Promise<void>;
}
const FCMContext = createContext<FCMContextType | undefined>(undefined);
// ===== Provider 컴포넌트 =====
export function FCMProvider({ children }: { children: ReactNode }) {
// FCM 훅 실행 (초기화)
const { cleanup } = useFCM();
return (
<FCMContext.Provider value={{ cleanup }}>
{children}
</FCMContext.Provider>
);
}
// ===== Custom Hook =====
/**
* FCM Context 사용 훅
*
* @example
* ```tsx
* function LogoutButton() {
* const { cleanup } = useFCMContext();
*
* const handleLogout = async () => {
* await cleanup(); // FCM 토큰 해제
* // ... 로그아웃 처리
* };
* }
* ```
*/
export function useFCMContext() {
const context = useContext(FCMContext);
if (context === undefined) {
throw new Error('useFCMContext must be used within a FCMProvider');
}
return context;
}
/**
* FCM Context 안전하게 사용 (Provider 외부에서도 사용 가능)
* undefined 반환 시 FCM이 비활성화됨
*/
export function useFCMContextSafe() {
return useContext(FCMContext);
}