import { registerFcmToken, deleteFcmToken, } from '../lib/shared'; import { PushNotifications } from '@capacitor/push-notifications'; import { Capacitor } from '@capacitor/core'; /** AndroidManifest default_notification_channel_id 와 동일 */ export const FCM_CHANNEL_ID = 'goldenchart_trade_signals'; export interface FcmPayload { type?: string; market?: string; signalId?: string; signalType?: string; price?: string; } type FcmHandlers = { onForeground?: (title: string, body: string, data?: FcmPayload) => void; onTap?: (data: FcmPayload) => void; }; let initialized = false; let listenersAttached = false; async function ensureAndroidNotificationChannel(): Promise { if (Capacitor.getPlatform() !== 'android') return; try { await PushNotifications.createChannel({ id: FCM_CHANNEL_ID, name: '매매 시그널 알림', description: '전략 조건 일치 시 매수·매도 푸시', importance: 5, visibility: 1, vibration: true, }); } catch (e) { console.warn('[FCM] createChannel failed', e); } } function attachListeners(handlers: FcmHandlers): void { if (listenersAttached) return; listenersAttached = true; void PushNotifications.addListener('registration', async token => { try { await registerFcmToken(token.value); console.info('[FCM] token registered with server'); } catch (e) { console.warn('[FCM] token register failed', e); } }); void PushNotifications.addListener('registrationError', err => { console.warn('[FCM] registration error', err); }); void PushNotifications.addListener('pushNotificationReceived', notification => { const title = notification.title ?? 'GoldenChart'; const body = notification.body ?? ''; handlers.onForeground?.(title, body, notification.data as FcmPayload); }); void PushNotifications.addListener('pushNotificationActionPerformed', action => { handlers.onTap?.(action.notification.data as FcmPayload); }); } /** * FCM 토큰 등록 (로그인 후 호출 — 서버 fcm_push_enabled 와 별개로 토큰만 등록) */ export async function initFcmPush(handlers: FcmHandlers = {}): Promise { if (!Capacitor.isNativePlatform()) { console.info('[FCM] Web dev — native push skipped'); return false; } await ensureAndroidNotificationChannel(); attachListeners(handlers); const perm = await PushNotifications.checkPermissions(); if (perm.receive !== 'granted') { const req = await PushNotifications.requestPermissions(); if (req.receive !== 'granted') { console.warn('[FCM] notification permission denied'); return false; } } if (!initialized) { await PushNotifications.register(); initialized = true; } return true; } export async function unregisterFcmPush(): Promise { if (!Capacitor.isNativePlatform()) return; try { await deleteFcmToken(); } catch { /* ignore */ } initialized = false; } export async function checkPushPermission(): Promise<'granted' | 'denied' | 'prompt'> { if (!Capacitor.isNativePlatform()) return 'prompt'; const perm = await PushNotifications.checkPermissions(); if (perm.receive === 'granted') return 'granted'; if (perm.receive === 'denied') return 'denied'; return 'prompt'; }