From 5afc15e861a82c1862373ed1e55d1af4f08fe763 Mon Sep 17 00:00:00 2001 From: Jay Sheen Date: Mon, 27 Oct 2025 16:49:50 +0900 Subject: [PATCH] =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EC=88=98=EC=8B=A0=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=ED=91=B8=EC=8B=9C=20=EA=B6=8C=ED=95=9C=20?= =?UTF-8?q?=EC=97=B0=EB=8F=99=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 앱브리지에 isPushNotificationEnabled, openAppSettings 메서드 추가 - 설정 페이지에서 푸시 알림 권한 상태에 따라 알림 수신 설정 토글 표시 - 알림 수신 설정 토글 클릭 시 앱 설정 화면으로 이동 - 푸시 권한이 꺼져있으면 하위 알림 토글들(11, 21, 31, 41, 61, 62) 비활성화 - 앱이 포어그라운드로 돌아올 때 푸시 권한 상태 재확인하여 UI 업데이트 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/hooks/useAppBridge.tsx | 29 +++++++++++-- src/pages/setting/setting-page.tsx | 70 +++++++++++++++++++++++------- src/types/bridge.ts | 8 +++- src/utils/appBridge.ts | 10 +++++ 4 files changed, 98 insertions(+), 19 deletions(-) diff --git a/src/hooks/useAppBridge.tsx b/src/hooks/useAppBridge.tsx index d796d17..117b527 100644 --- a/src/hooks/useAppBridge.tsx +++ b/src/hooks/useAppBridge.tsx @@ -53,6 +53,12 @@ interface UseAppBridgeReturn { openBiometricRegistrationPopup: () => Promise; // 간편 인증 등록 팝업 닫기 closeBiometricRegistrationPopup: () => Promise; + + // 푸시 알림 권한 확인 + isPushNotificationEnabled: () => Promise; + + // 앱 설정 화면 열기 + openAppSettings: () => Promise; } export const useAppBridge = (): UseAppBridgeReturn => { @@ -214,7 +220,7 @@ export const useAppBridge = (): UseAppBridgeReturn => { console.warn('Web Share API failed:', error); } } - + // 폴백: 클립보드에 복사 const shareText = `${content.title}\n${content.text}${content.url ? `\n${content.url}` : ''}`; if (navigator.clipboard) { @@ -225,10 +231,25 @@ export const useAppBridge = (): UseAppBridgeReturn => { } return; } - + return appBridge.safeCall(() => appBridge.shareContent(content)); }, [isNativeEnvironment]); + const isPushNotificationEnabled = useCallback(async (): Promise => { + if (!isNativeEnvironment) { + return true; + } + const result = await appBridge.safeCall(() => appBridge.isPushNotificationEnabled(), false); + return result || false; + }, [isNativeEnvironment]); + + const openAppSettings = useCallback(async (): Promise => { + if (!isNativeEnvironment) { + return; + } + return appBridge.safeCall(() => appBridge.openAppSettings()); + }, [isNativeEnvironment]); + return { isNativeEnvironment, isAndroid, @@ -249,6 +270,8 @@ export const useAppBridge = (): UseAppBridgeReturn => { requestRefreshToken, registerBiometric, openBiometricRegistrationPopup, - closeBiometricRegistrationPopup + closeBiometricRegistrationPopup, + isPushNotificationEnabled, + openAppSettings }; }; \ No newline at end of file diff --git a/src/pages/setting/setting-page.tsx b/src/pages/setting/setting-page.tsx index 036269b..c4ce8ae 100644 --- a/src/pages/setting/setting-page.tsx +++ b/src/pages/setting/setting-page.tsx @@ -5,15 +5,18 @@ import { LoginTypeBottomSheet } from '@/entities/alarm/ui/login-type-bottom-shee import { ServiceLanguageBottomSheet } from '@/entities/alarm/ui/service-language-bottom-sheet'; import { AppLanguage, HeaderType, LoginType } from '@/entities/common/model/types'; import { useStore } from '@/shared/model/store'; -import { +import { useSetHeaderTitle, useSetHeaderType, useSetFooterMode } from '@/widgets/sub-layout/use-sub-layout'; import { ChangeEvent, useEffect, useState } from 'react'; +import { useAppBridge } from '@/hooks/useAppBridge'; export const SettingPage = () => { let userInfo = useStore.getState().UserStore.userInfo; + const { isPushNotificationEnabled, openAppSettings } = useAppBridge(); + useSetHeaderTitle('설정'); useSetHeaderType(HeaderType.LeftArrow); useSetFooterMode(false); @@ -26,6 +29,7 @@ export const SettingPage = () => { const {mutateAsync: appAlarmFind} = useAppAlarmFindMutation(); const {mutateAsync: appAlarmConsent} = useAppAlarmConsentMutation(); + const [pushNotificationEnabled, setPushNotificationEnabled] = useState(false); const [alarmSetting, setAlarmSetting] = useState>({ '21': false, '11': false, @@ -39,6 +43,16 @@ export const SettingPage = () => { const onClickPrivacyPolicy = () => { window.open('https://www.nicevan.co.kr/privacy-policy', '_blank'); }; + + const checkPushNotificationStatus = () => { + isPushNotificationEnabled().then((enabled) => { + setPushNotificationEnabled(enabled); + }); + }; + + const onClickPushNotificationToggle = () => { + openAppSettings(); + }; const callAppAlarmFind = () => { if(userInfo.usrid){ @@ -87,6 +101,26 @@ export const SettingPage = () => { useEffect(() => { callAppAlarmFind(); + checkPushNotificationStatus(); + + // 앱이 포어그라운드로 돌아올 때 푸시 알림 권한 상태 재확인 + const handleVisibilityChange = () => { + if (document.visibilityState === 'visible') { + checkPushNotificationStatus(); + } + }; + + const handleFocus = () => { + checkPushNotificationStatus(); + }; + + document.addEventListener('visibilitychange', handleVisibilityChange); + window.addEventListener('focus', handleFocus); + + return () => { + document.removeEventListener('visibilitychange', handleVisibilityChange); + window.removeEventListener('focus', handleFocus); + }; }, []); return ( @@ -95,8 +129,8 @@ export const SettingPage = () => {
알림 수신 설정
-
@@ -108,9 +142,10 @@ export const SettingPage = () => {
서비스 운영 및 장애