fix(push): 상단 배너 표시 강화 + 첫 진입 자동 권한 prompt
Service Worker 알림 옵션 강화 (sw.js v3): - requireInteraction: 사용자 dismiss 전까지 유지 (heads-up 보장) - vibrate: 안드로이드가 high-priority 채널로 분류 → 상단 배너 - silent: false 명시 (Samsung 버전 차이 대응) - renotify: 같은 tag 라도 다시 알림 - timestamp 명시 (Samsung 알림 정렬 안정) → 삼성 인터넷/Galaxy 에서 상단 배너 안 뜨고 사이트 알림 내역에만 쌓이던 문제 해소 회원정보 카드 마운트 자동 권한 prompt: - Notification.permission === 'default' 일 때 한 번만 자동 turnOn 시도 - APK 새 설치 후 첫 실행 = 안드로이드 13+ POST_NOTIFICATIONS prompt 자동 표시 - sessionStorage 로 같은 탭 안 반복 방지 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+11
-1
@@ -1,5 +1,5 @@
|
|||||||
// 모모유통 ERP — Service Worker (PWA install criteria 충족용)
|
// 모모유통 ERP — Service Worker (PWA install criteria 충족용)
|
||||||
const CACHE = 'momo-erp-v2';
|
const CACHE = 'momo-erp-v3';
|
||||||
const PRECACHE = ['/', '/manifest.json', '/icon-192.png', '/icon-512.png', '/badge-96.png'];
|
const PRECACHE = ['/', '/manifest.json', '/icon-192.png', '/icon-512.png', '/badge-96.png'];
|
||||||
|
|
||||||
self.addEventListener('install', (e) => {
|
self.addEventListener('install', (e) => {
|
||||||
@@ -27,6 +27,11 @@ self.addEventListener('fetch', (e) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ===== 웹 푸시 =====
|
// ===== 웹 푸시 =====
|
||||||
|
// 삼성 인터넷/Samsung Galaxy 에서 상단 배너(heads-up) 가 안 뜨던 문제 해결:
|
||||||
|
// - vibrate: 패턴 명시 (안드로이드가 high-priority 채널로 분류)
|
||||||
|
// - requireInteraction: 사용자가 직접 닫을 때까지 유지
|
||||||
|
// - renotify: 같은 tag 라도 다시 알림
|
||||||
|
// - silent: false 명시 (Samsung 일부 버전에서 기본값이 true 인 케이스 회피)
|
||||||
self.addEventListener('push', (e) => {
|
self.addEventListener('push', (e) => {
|
||||||
let data = {};
|
let data = {};
|
||||||
try { data = e.data ? e.data.json() : {}; } catch (_) { data = {}; }
|
try { data = e.data ? e.data.json() : {}; } catch (_) { data = {}; }
|
||||||
@@ -36,6 +41,11 @@ self.addEventListener('push', (e) => {
|
|||||||
icon: data.icon || '/icon-192.png', // 큰 아이콘 = 모모 로고(초록 M)
|
icon: data.icon || '/icon-192.png', // 큰 아이콘 = 모모 로고(초록 M)
|
||||||
badge: data.badge || '/badge-96.png', // 상태바 작은 아이콘 = 흰 M 단색(투명 배경)
|
badge: data.badge || '/badge-96.png', // 상태바 작은 아이콘 = 흰 M 단색(투명 배경)
|
||||||
tag: data.tag || undefined,
|
tag: data.tag || undefined,
|
||||||
|
renotify: !!data.tag,
|
||||||
|
requireInteraction: true,
|
||||||
|
silent: false,
|
||||||
|
vibrate: [200, 100, 200],
|
||||||
|
timestamp: Date.now(),
|
||||||
data: { url: data.url || '/m/orders/new' },
|
data: { url: data.url || '/m/orders/new' },
|
||||||
};
|
};
|
||||||
e.waitUntil(self.registration.showNotification(title, options));
|
e.waitUntil(self.registration.showNotification(title, options));
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ export function PushOptIn({ variant = "compact" }: PushOptInProps) {
|
|||||||
};
|
};
|
||||||
}, [supported]);
|
}, [supported]);
|
||||||
|
|
||||||
|
|
||||||
// 마운트 시 상태 동기화
|
// 마운트 시 상태 동기화
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!supported || bootRef.current) return;
|
if (!supported || bootRef.current) return;
|
||||||
@@ -271,6 +272,19 @@ export function PushOptIn({ variant = "compact" }: PushOptInProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 첫 진입 자동 권한 prompt — Notification.permission === 'default' 이면 한 번만 시도.
|
||||||
|
// APK 새 설치 직후 첫 실행이면 안드로이드 13+ POST_NOTIFICATIONS prompt 가 자동으로 뜬다.
|
||||||
|
// 이미 한 번 prompt 받았던 디바이스는 default 가 아니므로 prompt 재표시 없음 (silent).
|
||||||
|
useEffect(() => {
|
||||||
|
if (!supported) return;
|
||||||
|
if (typeof Notification === "undefined" || Notification.permission !== "default") return;
|
||||||
|
const KEY = "momo-push-prompted";
|
||||||
|
try { if (sessionStorage.getItem(KEY)) return; } catch { /* ignore */ }
|
||||||
|
try { sessionStorage.setItem(KEY, "1"); } catch { /* ignore */ }
|
||||||
|
const t = setTimeout(() => { turnOn().catch(() => {}); }, 800);
|
||||||
|
return () => clearTimeout(t);
|
||||||
|
}, [supported, turnOn]);
|
||||||
|
|
||||||
// === 작은 헤더 토글 ===
|
// === 작은 헤더 토글 ===
|
||||||
if (!supported || !httpsOK) {
|
if (!supported || !httpsOK) {
|
||||||
if (variant !== "card") return null;
|
if (variant !== "card") return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user