import { useAppAlarmConsentMutation } from '@/entities/alarm/api/use-app-alarm-consent-mutation'; import { useAppAlarmFindMutation } from '@/entities/alarm/api/use-app-alarm-find-mutation'; import { AppAlarmConsentParams, AppAlarmConsentResponse, AppAlarmFindParams, AppAlarmFindResponse, MERCHANT_ADMIN_APP } from '@/entities/alarm/model/types'; import { LoginTypeBottomSheet } from '@/entities/alarm/ui/login-type-bottom-sheet'; import { ServiceLanguageBottomSheet } from '@/entities/alarm/ui/service-language-bottom-sheet'; import { APP_LANGUAGE, APP_LOGIN_TYPE } from '@/entities/common/model/constant'; import { AppLanguage, HeaderType, LoginType } from '@/entities/common/model/types'; import { useStore } from '@/shared/model/store'; import { useSetHeaderTitle, useSetHeaderType, useSetFooterMode } from '@/widgets/sub-layout/use-sub-layout'; import { ChangeEvent, useCallback, useEffect, useState } from 'react'; import { useAppBridge } from '@/hooks/useAppBridge'; import { useTranslation } from 'react-i18next'; import appBridge from '@/utils/appBridge'; import { Dialog } from '@/shared/ui/dialogs/dialog'; export const SettingPage = () => { let userInfo = useStore.getState().UserStore.userInfo; const { isPushNotificationEnabled, openAppSettings, logout, getLoginType, getNotificationSetting, setNotificationSetting: updateNotificationSetting, isAndroid, getLanguage } = useAppBridge(); const { t, i18n } = useTranslation(); useSetHeaderTitle(t('settings.title')); useSetHeaderType(HeaderType.LeftArrow); useSetFooterMode(false); const [loginTypeBottomSheetOn, setLoginTypeBottomSheetOn] = useState(false); const [serviceLanguageBottomSheetOn, setServiceLanguageBottomSheetOn] = useState(false); const [loginType, setLoginType] = useState(LoginType.ID); const [appLanguage, setAppLanguage] = useState( (i18n.language === 'en' ? AppLanguage.EN : AppLanguage.KO) ); const {mutateAsync: appAlarmFind} = useAppAlarmFindMutation(); const {mutateAsync: appAlarmConsent} = useAppAlarmConsentMutation(); const [pushNotificationEnabled, setPushNotificationEnabled] = useState(false); const [notificationSetting, setNotificationSetting] = useState(true); const [alarmSetting, setAlarmSetting] = useState>({ '21': false, '11': false, '31': false, '41': false, '61': false, '62': false, '15': false }); const [dialogOpen, setDialogOpen] = useState(false); const onClickPolicy = () => { window.open('https://www.nicepay.co.kr/cs/terms/policy1.do', '_blank'); }; const onClickLogout = () => { setDialogOpen(true); }; const checkPushNotificationStatus = useCallback(() => { console.log('checkPushNotificationStatus'); isPushNotificationEnabled().then((enabled) => { setPushNotificationEnabled(enabled); }); }, [isPushNotificationEnabled]); const loadLoginType = useCallback(() => { getLoginType().then((type) => { setLoginType(type as LoginType); }); }, [getLoginType]); const loadLanguage = useCallback(() => { getLanguage().then((language) => { const languageType = language === 'en' ? AppLanguage.EN : AppLanguage.KO; setAppLanguage(languageType); // i18n 언어도 동기화 if (i18n.language !== language) { i18n.changeLanguage(language); } }); }, [getLanguage, i18n]); const onClickPushNotificationToggle = () => { openAppSettings(); }; // 알림 설정 로드 (Android만) const loadNotificationSetting = useCallback(async () => { if (!isAndroid) { console.log('[loadNotificationSetting] Not Android, skipping'); return; } try { console.log('[loadNotificationSetting] Calling getNotificationSetting()...'); const enabled = await getNotificationSetting(); console.log('[loadNotificationSetting] Received value from bridge:', enabled); console.log('[loadNotificationSetting] Type of enabled:', typeof enabled); setNotificationSetting(enabled); console.log('[loadNotificationSetting] State updated to:', enabled); } catch (error) { console.error('[loadNotificationSetting] Failed to load notification setting:', error); } }, [isAndroid, getNotificationSetting]); // 알림 설정 토글 핸들러 (Android만) const onClickNotificationSettingToggle = useCallback(async () => { if (!isAndroid) { console.log('[onClickNotificationSettingToggle] Not Android, skipping'); return; } try { const newValue = !notificationSetting; console.log('[onClickNotificationSettingToggle] to save:', newValue); const result = await updateNotificationSetting(newValue); console.log('[onClickNotificationSettingToggle] result:', result); // ✅ needsPermission이 true이면 설정 화면으로 이동한 것 if (result && typeof result === 'object' && 'needsPermission' in result && result.needsPermission) { console.log('[onClickNotificationSettingToggle] Permission needed - opened settings'); // 설정이 변경되지 않았으므로 상태 유지 return; } // ✅ 성공한 경우에만 상태 업데이트 if (result && typeof result === 'object' && 'enabled' in result) { setNotificationSetting(result.enabled); console.log('[onClickNotificationSettingToggle] State updated to:', result.enabled); } else { // Fallback setNotificationSetting(newValue); console.log('[onClickNotificationSettingToggle] State updated to (fallback):', newValue); } // ✅ 저장 후 바로 다시 읽어서 확인 console.log('[onClickNotificationSettingToggle] Verifying saved value...'); const verifyValue = await getNotificationSetting(); console.log('[onClickNotificationSettingToggle] Verified value:', verifyValue); if (verifyValue !== result?.enabled && !result?.needsPermission) { console.error('[onClickNotificationSettingToggle] WARNING: Saved value != Verified value', { saved: result?.enabled, verified: verifyValue }); } } catch (error) { console.error('[onClickNotificationSettingToggle] Failed to update notification setting:', error); } }, [isAndroid, notificationSetting, updateNotificationSetting, getNotificationSetting]); const responseAlarmSetting = useCallback((data: AppAlarmFindResponse) => { let responseAlarms: Record = {}; for(let i=0;i ({ ...prevState, ...responseAlarms })); }, []); const callAppAlarmFind = useCallback(() => { if(userInfo.usrid){ let params: AppAlarmFindParams = { usrid: userInfo.usrid, appCl: MERCHANT_ADMIN_APP.MERCHANT_ADMIN_APP }; appAlarmFind(params).then((rs: AppAlarmFindResponse) => { responseAlarmSetting(rs); }); } }, [userInfo.usrid, appAlarmFind, responseAlarmSetting]); const callAppAlarmConsent = (value: boolean, alarmCode: string) => { if(userInfo.usrid){ let params: AppAlarmConsentParams = { usrid: userInfo.usrid, appCl: MERCHANT_ADMIN_APP.MERCHANT_ADMIN_APP, appNotificationSubCategory: alarmCode, appNotificationAllowed: value }; appAlarmConsent(params).then((_rs: AppAlarmConsentResponse) => { setAlarmSetting({ ...alarmSetting, ...{ ['' + alarmCode]: value } }); }); } }; const changeLanguage = async (language: string) => { // 웹 언어 변경 i18n.changeLanguage(language); localStorage.setItem('i18nextLng', language); // 네이티브 환경에서 네이티브 언어도 변경 if (appBridge.isNativeEnvironment()) { try { await appBridge.setLanguage(language); } catch (error) { console.error('Failed to set native language:', error); } } }; const getLoginTypeLabel = (type: LoginType): string => { switch (type) { case LoginType.ID: return t('settings.loginType.idPassword'); case LoginType.BIOMETRIC: return t('settings.loginType.biometric'); default: return ''; } }; const getLanguageLabel = (language: AppLanguage): string => { switch (language) { case AppLanguage.KO: return '한국어'; case AppLanguage.EN: return 'English'; default: return ''; } }; const handleSetLoginType = (type: string) => { setLoginType(type as LoginType); }; useEffect(() => { callAppAlarmFind(); checkPushNotificationStatus(); loadLoginType(); loadNotificationSetting(); loadLanguage(); // 앱이 포어그라운드로 돌아올 때 푸시 알림 권한 상태 재확인 const handleVisibilityChange = () => { if (document.visibilityState === 'visible') { checkPushNotificationStatus(); loadNotificationSetting(); } }; const handleFocus = () => { checkPushNotificationStatus(); loadNotificationSetting(); }; document.addEventListener('visibilitychange', handleVisibilityChange); window.addEventListener('focus', handleFocus); return () => { document.removeEventListener('visibilitychange', handleVisibilityChange); window.removeEventListener('focus', handleFocus); }; }, [callAppAlarmFind, checkPushNotificationStatus, loadLoginType, loadNotificationSetting, loadLanguage]); return ( <>
{/* ✅ Android일 때는 앱 내 설정, 아니면 시스템 권한 표시 */}
{t('settings.notificationSettings')}
{t('settings.noticeAlarms')}
{t('settings.serviceOperation')}
{t('settings.interestFreeEvent')}
{t('settings.servicePolicyChange')}
{t('settings.niceNews')}
{t('settings.settlementAlarms')}
{t('settings.settlementStatus')}
{t('settings.settlementLimit')}
{t('settings.marketingConsent')}
setLoginTypeBottomSheetOn(true) } >
{t('settings.loginTypeSetting')}
{ getLoginTypeLabel(loginType) }
setServiceLanguageBottomSheetOn(true) } >
{t('settings.serviceLanguageSetting')}
{ getLanguageLabel(appLanguage) }
{t('settings.termsAndPrivacy')}
{t('settings.logout')}
{ !!loginTypeBottomSheetOn && } { !!serviceLanguageBottomSheetOn && } { !!dialogOpen && setDialogOpen(false)} message={t('settings.logoutConfirm')} afterLeave={() => setDialogOpen(false)} buttonLabel={[t('common.cancel'), t('common.confirm')]} onConfirmClick={() => { console.log(t('common.confirm')); logout(); }} onCancelClick={() => setDialogOpen(false)} /> } ); };