/** * 검증 이슈 등록·단계 변경 실시간 알림 (STOMP) */ import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { subscribeStompTopic } from '../utils/stompChartBroker'; import { VERIFICATION_ISSUE_EVENT_TOPIC, eventToToast, parseVerificationIssueEvent, shouldShowVerificationIssueEvent, type VerificationIssueToastItem, } from '../utils/verificationIssueEvents'; interface ContextValue { toasts: VerificationIssueToastItem[]; dismissToast: (id: string) => void; dismissAll: () => void; } const VerificationIssueNotificationContext = createContext(null); interface ProviderProps { /** 검증게시판 메뉴 접근 가능 */ enabled: boolean; /** 일반 설정 — 검증 이슈 알림 ON */ notifyEnabled: boolean; children: React.ReactNode; } export const VerificationIssueNotificationProvider: React.FC = ({ enabled, notifyEnabled, children, }) => { const [toasts, setToasts] = useState([]); const active = enabled && notifyEnabled; const dismissToast = useCallback((id: string) => { setToasts(prev => prev.filter(t => t.id !== id)); }, []); const dismissAll = useCallback(() => { setToasts([]); }, []); useEffect(() => { if (!active) { setToasts([]); return; } return subscribeStompTopic(VERIFICATION_ISSUE_EVENT_TOPIC, msg => { const event = parseVerificationIssueEvent(msg.body); if (!event || !shouldShowVerificationIssueEvent(event)) return; const toast = eventToToast(event); setToasts(prev => { const withoutDup = prev.filter(t => t.id !== toast.id); return [toast, ...withoutDup].slice(0, 8); }); }); }, [active]); const value = useMemo( () => ({ toasts, dismissToast, dismissAll }), [toasts, dismissToast, dismissAll], ); return ( {children} ); }; export function useVerificationIssueNotification(): ContextValue { const ctx = useContext(VerificationIssueNotificationContext); if (!ctx) { throw new Error('useVerificationIssueNotification must be used within VerificationIssueNotificationProvider'); } return ctx; }