팝업알림 오류

This commit is contained in:
Macbook
2026-06-05 12:38:19 +09:00
parent e0ef5845a2
commit a52383376b
@@ -223,18 +223,41 @@ export const TradeNotificationProvider: React.FC<ProviderProps> = ({
let newlyArrived: TradeNotificationItem[] = [];
setAllNotifications(prev => {
/**
* rawServerList=true 는 앱 초기 로드(새로고침·로그인 직후)이므로
* 이미 존재하는 서버 이력을 실시간 신규 알림으로 취급하지 않는다.
* 실제 새 알림 판단은 STOMP addNotification 과 일반 refreshHistory 에서만 한다.
*/
if (!opts?.rawServerList) {
/**
* 일반 폴링·serverOnly 경로: 이미 목록에 없는 미읽음 신호만 신규 도착으로 판정.
*/
newlyArrived = items.filter(
item =>
!item.isRead &&
!readIdsRef.current.has(item.id) && // readIds 에 없는(진짜 새) 알림만
!prev.some(p => p.id === item.id), // 이미 목록에 없는 알림만
);
} else if (popupEnabled) {
/**
* rawServerList=true (앱 시작·로그인 직후) + 팝업 ON:
*
* 기존 로직은 서버 이력을 "실시간 신규 알림"으로 취급하지 않아
* suppressBefore 이후 생성된 미읽음 신호가 배지에는 표시되지만
* 팝업은 전혀 뜨지 않는 문제가 있었다.
*
* 서버 재시작·짧은 연결 끊김 등으로 STOMP 를 놓친 신호도 팝업으로
* 보여줘야 하므로, suppressBefore 이후에 생성된 미읽음 신호 전체를
* newlyArrived 에 포함시킨다.
*
* suppressBefore == 0 (전체닫기 이력 없음) 인 경우 최근 2시간 이내
* 신호로 범위를 제한해 과도한 팝업을 방지한다.
*/
const cutoff = suppressBeforeRef.current > 0
? suppressBeforeRef.current * 1000 // 마지막 전체닫기 이후 신호
: Date.now() - 2 * 60 * 60 * 1000; // 또는 최근 2시간
newlyArrived = items.filter(
item =>
!item.isRead &&
!readIdsRef.current.has(item.id) &&
item.receivedAt > cutoff,
);
}
if (opts?.serverOnly || opts?.rawServerList) {
@@ -266,7 +289,8 @@ export const TradeNotificationProvider: React.FC<ProviderProps> = ({
for (const n of newlyArrived) map.set(n.id, n);
return [...map.values()].slice(0, MAX_TOAST_QUEUE);
});
if (soundEnabled) {
// rawServerList (앱 시작) 시 기존 미읽음 신호 팝업은 사운드 없이 조용히 표시
if (soundEnabled && !opts?.rawServerList) {
playTradeAlertSound(alertSoundId);
}
}
@@ -275,13 +299,19 @@ export const TradeNotificationProvider: React.FC<ProviderProps> = ({
}
}, [popupEnabled, soundEnabled, alertSoundId]);
const prevSessionKeyRef = useRef(settingsSessionKey);
useEffect(() => {
if (!settingsLoaded) return;
const isSessionSwitch = prevSessionKeyRef.current !== settingsSessionKey;
prevSessionKeyRef.current = settingsSessionKey;
/**
* 앱 설정이 DB 에서 로드 완료된 시점에 readIds 를 즉시 동기화한다.
* STOMP 가 앱 시작 직후 구독 시 readIds 가 아직 빈 상태여서 이미 닫은
* 알림이 다시 팝업으로 뜨는 타이밍 버그를 방지한다.
* 세션 전환 시 allSeenIdsRef 초기화해 이전 세션 알림 ID 가 잔류하지 않게 한다.
* 세션 전환(로그인·로그아웃) 시 allSeenIdsRef 초기화해 이전 세션 ID 잔류 방지.
*/
allSeenIdsRef.current = new Set();
const dbRead = loadReadIds();
@@ -292,7 +322,17 @@ export const TradeNotificationProvider: React.FC<ProviderProps> = ({
}
// 전체닫기·삭제 시각 복원 (재접속 후에도 오래된 신호 팝업 방지)
suppressBeforeRef.current = loadSuppressBefore();
/**
* [버그 수정] 기존 코드는 항상 setToastNotifications([]) 로 초기화했는데,
* 이 경우 STOMP 가 설정 로드보다 먼저 도착한 토스트까지 소거되는 race condition 이 있었다.
* 세션 전환(로그인·로그아웃) 시에만 초기화하고, 단순 설정 로드 완료 시에는
* 초기화하지 않는다 — rawServerList 로드가 최신 토스트를 올바르게 추가한다.
*/
if (isSessionSwitch) {
setToastNotifications([]);
}
void refreshHistory({ serverOnly: true, rawServerList: true });
}, [refreshHistory, settingsLoaded, settingsSessionKey]);