설정 페이지 및 관련 컴포넌트 다국어(localization) 적용
- 설정 페이지 전체 텍스트 다국어 지원 - 로그인 방식 선택 bottom sheet 다국어 적용 - 서비스 언어 선택 bottom sheet 다국어 적용 - 앱브리지에서 언어 설정 조회 기능 추가 - 페이지 로드 시 앱브리지 언어 설정으로 초기화 - AppLanguage enum 값 변경 (KO/EN → ko/en) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
import { APP_LOGIN_TYPE } from "@/entities/common/model/constant";
|
|
||||||
import { LoginType } from "@/entities/common/model/types";
|
import { LoginType } from "@/entities/common/model/types";
|
||||||
import { IMAGE_ROOT } from "@/shared/constants/common";
|
import { IMAGE_ROOT } from "@/shared/constants/common";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export interface LoginTypeBottomSheetProps {
|
export interface LoginTypeBottomSheetProps {
|
||||||
loginTypeBottomSheetOn: boolean;
|
loginTypeBottomSheetOn: boolean;
|
||||||
setLoginTypeBottomSheetOn: (loginTypeBottomSheetOn: boolean) => void;
|
setLoginTypeBottomSheetOn: (loginTypeBottomSheetOn: boolean) => void;
|
||||||
loginType: LoginType;
|
loginType: LoginType;
|
||||||
setLoginType: (loginType: LoginType) => void;
|
setLoginType: (loginType: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LoginTypeBottomSheet = ({
|
export const LoginTypeBottomSheet = ({
|
||||||
@@ -15,11 +15,12 @@ export const LoginTypeBottomSheet = ({
|
|||||||
loginType,
|
loginType,
|
||||||
setLoginType
|
setLoginType
|
||||||
}: LoginTypeBottomSheetProps) => {
|
}: LoginTypeBottomSheetProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const onClickToClose = () => {
|
const onClickToClose = () => {
|
||||||
setLoginTypeBottomSheetOn(false);
|
setLoginTypeBottomSheetOn(false);
|
||||||
};
|
};
|
||||||
const onChangeLoginType = (type: LoginType) => {
|
const onChangeLoginType = (type: string) => {
|
||||||
setLoginType(type);
|
setLoginType(type);
|
||||||
onClickToClose();
|
onClickToClose();
|
||||||
};
|
};
|
||||||
@@ -30,14 +31,14 @@ export const LoginTypeBottomSheet = ({
|
|||||||
<div className="bottomsheet">
|
<div className="bottomsheet">
|
||||||
<div className="bottomsheet-header">
|
<div className="bottomsheet-header">
|
||||||
<div className="bottomsheet-title">
|
<div className="bottomsheet-title">
|
||||||
<h2>로그인 방식을 선택하세요.</h2>
|
<h2>{t('settings.loginType.title')}</h2>
|
||||||
<button
|
<button
|
||||||
className="close-btn"
|
className="close-btn"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={ IMAGE_ROOT + '/ico_close.svg' }
|
src={ IMAGE_ROOT + '/ico_close.svg' }
|
||||||
alt="닫기"
|
alt={t('common.close')}
|
||||||
onClick={ onClickToClose }
|
onClick={ onClickToClose }
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
@@ -49,12 +50,12 @@ export const LoginTypeBottomSheet = ({
|
|||||||
<ul className="list-style-circle link">
|
<ul className="list-style-circle link">
|
||||||
<li
|
<li
|
||||||
className={ `${(loginType === LoginType.ID)? 'selected': ''}` }
|
className={ `${(loginType === LoginType.ID)? 'selected': ''}` }
|
||||||
onClick={ () => onChangeLoginType(LoginType.ID) }
|
onClick={ () => onChangeLoginType('ID') }
|
||||||
>{ APP_LOGIN_TYPE[LoginType.ID] }</li>
|
>{t('settings.loginType.idPassword')}</li>
|
||||||
<li
|
<li
|
||||||
className={ `${(loginType === LoginType.BIOMETRIC)? 'selected': ''}` }
|
className={ `${(loginType === LoginType.BIOMETRIC)? 'selected': ''}` }
|
||||||
onClick={ () => onChangeLoginType(LoginType.BIOMETRIC) }
|
onClick={ () => onChangeLoginType('BIOMETRIC') }
|
||||||
>{ APP_LOGIN_TYPE[LoginType.BIOMETRIC] }</li>
|
>{t('settings.loginType.biometric')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,26 +1,31 @@
|
|||||||
import { APP_LANGUAGE } from "@/entities/common/model/constant";
|
import { APP_LANGUAGE } from "@/entities/common/model/constant";
|
||||||
import { AppLanguage } from "@/entities/common/model/types";
|
import { AppLanguage } from "@/entities/common/model/types";
|
||||||
import { IMAGE_ROOT } from "@/shared/constants/common";
|
import { IMAGE_ROOT } from "@/shared/constants/common";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export interface ServiceLanguageBottomSheetProps {
|
export interface ServiceLanguageBottomSheetProps {
|
||||||
serviceLanguageBottomSheetOn: boolean;
|
serviceLanguageBottomSheetOn: boolean;
|
||||||
setServiceLanguageBottomSheetOn: (serviceLanguageBottomSheetOn: boolean) => void;
|
setServiceLanguageBottomSheetOn: (serviceLanguageBottomSheetOn: boolean) => void;
|
||||||
appLanguage: AppLanguage;
|
appLanguage: AppLanguage;
|
||||||
setAppLanguage: (appLanguage: AppLanguage) => void;
|
setAppLanguage: (appLanguage: AppLanguage) => void;
|
||||||
|
changeLanguage: (language: string) => void | Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ServiceLanguageBottomSheet = ({
|
export const ServiceLanguageBottomSheet = ({
|
||||||
serviceLanguageBottomSheetOn,
|
serviceLanguageBottomSheetOn: _serviceLanguageBottomSheetOn,
|
||||||
setServiceLanguageBottomSheetOn,
|
setServiceLanguageBottomSheetOn,
|
||||||
appLanguage,
|
appLanguage,
|
||||||
setAppLanguage
|
setAppLanguage,
|
||||||
|
changeLanguage
|
||||||
}: ServiceLanguageBottomSheetProps) => {
|
}: ServiceLanguageBottomSheetProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const onClickToClose = () => {
|
const onClickToClose = () => {
|
||||||
setServiceLanguageBottomSheetOn(false);
|
setServiceLanguageBottomSheetOn(false);
|
||||||
};
|
};
|
||||||
const onChangeServiceLanguage = (language: AppLanguage) => {
|
const onChangeServiceLanguage = (language: AppLanguage) => {
|
||||||
setAppLanguage(language);
|
setAppLanguage(language);
|
||||||
|
changeLanguage(language);
|
||||||
onClickToClose();
|
onClickToClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,14 +35,14 @@ export const ServiceLanguageBottomSheet = ({
|
|||||||
<div className="bottomsheet">
|
<div className="bottomsheet">
|
||||||
<div className="bottomsheet-header">
|
<div className="bottomsheet-header">
|
||||||
<div className="bottomsheet-title">
|
<div className="bottomsheet-title">
|
||||||
<h2>서비스 언어를 선택하세요.</h2>
|
<h2>{t('settings.serviceLanguage.title')}</h2>
|
||||||
<button
|
<button
|
||||||
className="close-btn"
|
className="close-btn"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={ IMAGE_ROOT + '/ico_close.svg' }
|
src={ IMAGE_ROOT + '/ico_close.svg' }
|
||||||
alt="닫기"
|
alt={t('common.close')}
|
||||||
onClick={ onClickToClose }
|
onClick={ onClickToClose }
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
@@ -46,12 +51,8 @@ export const ServiceLanguageBottomSheet = ({
|
|||||||
|
|
||||||
<div className="bottomsheet-content">
|
<div className="bottomsheet-content">
|
||||||
<div className="bottom-section">
|
<div className="bottom-section">
|
||||||
<p className="fs16">※ 미지원 언어일 경우 ENGLISH 자동 설정</p>
|
<p className="fs16">{t('settings.serviceLanguage.notice')}</p>
|
||||||
<ul className="list-style-circle link">
|
<ul className="list-style-circle link">
|
||||||
<li
|
|
||||||
className={ `${(appLanguage === AppLanguage.DEVICE)? 'selected': ''}` }
|
|
||||||
onClick={ () => onChangeServiceLanguage(AppLanguage.DEVICE) }
|
|
||||||
>{ APP_LANGUAGE[AppLanguage.DEVICE] }</li>
|
|
||||||
<li
|
<li
|
||||||
className={ `${(appLanguage === AppLanguage.KO)? 'selected': ''}` }
|
className={ `${(appLanguage === AppLanguage.KO)? 'selected': ''}` }
|
||||||
onClick={ () => onChangeServiceLanguage(AppLanguage.KO) }
|
onClick={ () => onChangeServiceLanguage(AppLanguage.KO) }
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { PATHS } from "@/shared/constants/paths";
|
|||||||
import { SortTypeKeys } from "./types";
|
import { SortTypeKeys } from "./types";
|
||||||
|
|
||||||
export const APP_LANGUAGE = {
|
export const APP_LANGUAGE = {
|
||||||
DEVICE: '기기 설정 언어',
|
// DEVICE: '기기 설정 언어',
|
||||||
KO: '한국어',
|
ko: '한국어',
|
||||||
EN: 'ENGLISH',
|
en: 'English',
|
||||||
};
|
};
|
||||||
export const APP_LOGIN_TYPE = {
|
export const APP_LOGIN_TYPE = {
|
||||||
ID: 'ID/PW 입력',
|
ID: 'ID/PW 입력',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export enum AppLanguage {
|
export enum AppLanguage {
|
||||||
DEVICE = 'DEVICE',
|
// DEVICE = 'DEVICE',
|
||||||
KO = 'KO',
|
KO = 'ko',
|
||||||
EN = 'EN'
|
EN = 'en'
|
||||||
};
|
};
|
||||||
export enum LoginType {
|
export enum LoginType {
|
||||||
ID = 'ID',
|
ID = 'ID',
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ interface UseAppBridgeReturn {
|
|||||||
getNotificationSetting: () => Promise<boolean>;
|
getNotificationSetting: () => Promise<boolean>;
|
||||||
|
|
||||||
setNotificationSetting: (enabled: boolean) => Promise<NotificationSettingResponse>;
|
setNotificationSetting: (enabled: boolean) => Promise<NotificationSettingResponse>;
|
||||||
|
|
||||||
|
// 언어 설정 조회
|
||||||
|
getLanguage: () => Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAppBridge = (): UseAppBridgeReturn => {
|
export const useAppBridge = (): UseAppBridgeReturn => {
|
||||||
@@ -294,6 +297,14 @@ export const useAppBridge = (): UseAppBridgeReturn => {
|
|||||||
}
|
}
|
||||||
}, [isAndroid]);
|
}, [isAndroid]);
|
||||||
|
|
||||||
|
const getLanguage = useCallback(async (): Promise<string> => {
|
||||||
|
if (!isNativeEnvironment) {
|
||||||
|
return localStorage.getItem('i18nextLng') || 'ko';
|
||||||
|
}
|
||||||
|
const result = await appBridge.safeCall(() => appBridge.getLanguage(), 'ko');
|
||||||
|
return result || 'ko';
|
||||||
|
}, [isNativeEnvironment]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isNativeEnvironment,
|
isNativeEnvironment,
|
||||||
isAndroid,
|
isAndroid,
|
||||||
@@ -319,6 +330,7 @@ export const useAppBridge = (): UseAppBridgeReturn => {
|
|||||||
openAppSettings,
|
openAppSettings,
|
||||||
getLoginType,
|
getLoginType,
|
||||||
getNotificationSetting,
|
getNotificationSetting,
|
||||||
setNotificationSetting
|
setNotificationSetting,
|
||||||
|
getLanguage
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -75,6 +75,32 @@
|
|||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"failed": "Failed"
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "Settings",
|
||||||
|
"notificationSettings": "Notification Settings",
|
||||||
|
"noticeAlarms": "Notice Alarms",
|
||||||
|
"serviceOperation": "Service Operation & Failures",
|
||||||
|
"interestFreeEvent": "Interest-Free Benefits & Events",
|
||||||
|
"servicePolicyChange": "Service & Policy Changes",
|
||||||
|
"niceNews": "NICE News & Other Information",
|
||||||
|
"settlementAlarms": "Settlement Alarms",
|
||||||
|
"settlementStatus": "Settlement Status",
|
||||||
|
"settlementLimit": "Settlement Limit Alarm",
|
||||||
|
"marketingConsent": "Marketing Information Consent",
|
||||||
|
"loginTypeSetting": "Login Type",
|
||||||
|
"serviceLanguageSetting": "Language",
|
||||||
|
"logout": "Logout",
|
||||||
|
"privacyPolicy": "Privacy Policy",
|
||||||
|
"loginType": {
|
||||||
|
"title": "Please select a login type.",
|
||||||
|
"idPassword": "ID/PW Login",
|
||||||
|
"biometric": "Biometric Authentication"
|
||||||
|
},
|
||||||
|
"serviceLanguage": {
|
||||||
|
"title": "Please select language.",
|
||||||
|
"notice": "※ If the language is not supported, English will be set automatically"
|
||||||
|
}
|
||||||
|
},
|
||||||
"support": {
|
"support": {
|
||||||
"notice": {
|
"notice": {
|
||||||
"title": "Notice",
|
"title": "Notice",
|
||||||
|
|||||||
@@ -75,6 +75,32 @@
|
|||||||
"completed": "완료",
|
"completed": "완료",
|
||||||
"failed": "실패"
|
"failed": "실패"
|
||||||
},
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "설정",
|
||||||
|
"notificationSettings": "알림 수신 설정",
|
||||||
|
"noticeAlarms": "공지사항 알림",
|
||||||
|
"serviceOperation": "서비스 운영 및 장애",
|
||||||
|
"interestFreeEvent": "무이자 혜택 및 이벤트",
|
||||||
|
"servicePolicyChange": "서비스 이용 및 정책 변경",
|
||||||
|
"niceNews": "NICE소식 및 기타 정보",
|
||||||
|
"settlementAlarms": "정산 알림",
|
||||||
|
"settlementStatus": "정산처리 현황",
|
||||||
|
"settlementLimit": "정산한도 알림",
|
||||||
|
"marketingConsent": "마케팅 정보 수신 동의",
|
||||||
|
"loginTypeSetting": "로그인 방식 설정",
|
||||||
|
"serviceLanguageSetting": "서비스 언어 설정",
|
||||||
|
"logout": "로그아웃",
|
||||||
|
"privacyPolicy": "개인정보처리방침",
|
||||||
|
"loginType": {
|
||||||
|
"title": "로그인 방식을 선택하세요.",
|
||||||
|
"idPassword": "ID/PW 입력",
|
||||||
|
"biometric": "생체 인증"
|
||||||
|
},
|
||||||
|
"serviceLanguage": {
|
||||||
|
"title": "서비스 언어를 선택하세요.",
|
||||||
|
"notice": "※ 미지원 언어일 경우 ENGLISH 자동 설정"
|
||||||
|
}
|
||||||
|
},
|
||||||
"support": {
|
"support": {
|
||||||
"notice": {
|
"notice": {
|
||||||
"title": "공지사항",
|
"title": "공지사항",
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import {
|
|||||||
} from '@/widgets/sub-layout/use-sub-layout';
|
} from '@/widgets/sub-layout/use-sub-layout';
|
||||||
import { ChangeEvent, useCallback, useEffect, useState } from 'react';
|
import { ChangeEvent, useCallback, useEffect, useState } from 'react';
|
||||||
import { useAppBridge } from '@/hooks/useAppBridge';
|
import { useAppBridge } from '@/hooks/useAppBridge';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import appBridge from '@/utils/appBridge';
|
||||||
|
|
||||||
export const SettingPage = () => {
|
export const SettingPage = () => {
|
||||||
let userInfo = useStore.getState().UserStore.userInfo;
|
let userInfo = useStore.getState().UserStore.userInfo;
|
||||||
@@ -23,17 +25,21 @@ export const SettingPage = () => {
|
|||||||
getLoginType,
|
getLoginType,
|
||||||
getNotificationSetting,
|
getNotificationSetting,
|
||||||
setNotificationSetting: updateNotificationSetting,
|
setNotificationSetting: updateNotificationSetting,
|
||||||
isAndroid
|
isAndroid,
|
||||||
|
getLanguage
|
||||||
} = useAppBridge();
|
} = useAppBridge();
|
||||||
|
const { t, i18n } = useTranslation();
|
||||||
|
|
||||||
useSetHeaderTitle('설정');
|
useSetHeaderTitle(t('settings.title'));
|
||||||
useSetHeaderType(HeaderType.LeftArrow);
|
useSetHeaderType(HeaderType.LeftArrow);
|
||||||
useSetFooterMode(false);
|
useSetFooterMode(false);
|
||||||
|
|
||||||
const [loginTypeBottomSheetOn, setLoginTypeBottomSheetOn] = useState<boolean>(false);
|
const [loginTypeBottomSheetOn, setLoginTypeBottomSheetOn] = useState<boolean>(false);
|
||||||
const [serviceLanguageBottomSheetOn, setServiceLanguageBottomSheetOn] = useState<boolean>(false);
|
const [serviceLanguageBottomSheetOn, setServiceLanguageBottomSheetOn] = useState<boolean>(false);
|
||||||
const [loginType, setLoginType] = useState<LoginType>(LoginType.ID);
|
const [loginType, setLoginType] = useState<LoginType>(LoginType.ID);
|
||||||
const [appLanguage, setAppLanguage] = useState<AppLanguage>(AppLanguage.KO);
|
const [appLanguage, setAppLanguage] = useState<AppLanguage>(
|
||||||
|
(i18n.language === 'en' ? AppLanguage.EN : AppLanguage.KO)
|
||||||
|
);
|
||||||
|
|
||||||
const {mutateAsync: appAlarmFind} = useAppAlarmFindMutation();
|
const {mutateAsync: appAlarmFind} = useAppAlarmFindMutation();
|
||||||
const {mutateAsync: appAlarmConsent} = useAppAlarmConsentMutation();
|
const {mutateAsync: appAlarmConsent} = useAppAlarmConsentMutation();
|
||||||
@@ -71,6 +77,17 @@ export const SettingPage = () => {
|
|||||||
});
|
});
|
||||||
}, [getLoginType]);
|
}, [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 = () => {
|
const onClickPushNotificationToggle = () => {
|
||||||
openAppSettings();
|
openAppSettings();
|
||||||
};
|
};
|
||||||
@@ -142,19 +159,7 @@ export const SettingPage = () => {
|
|||||||
}
|
}
|
||||||
}, [isAndroid, notificationSetting, updateNotificationSetting, getNotificationSetting]);
|
}, [isAndroid, notificationSetting, updateNotificationSetting, getNotificationSetting]);
|
||||||
|
|
||||||
const callAppAlarmFind = () => {
|
const responseAlarmSetting = useCallback((data: AppAlarmFindResponse) => {
|
||||||
if(userInfo.usrid){
|
|
||||||
let params: AppAlarmFindParams = {
|
|
||||||
usrid: userInfo.usrid,
|
|
||||||
appCl: MERCHANT_ADMIN_APP.MERCHANT_ADMIN_APP
|
|
||||||
};
|
|
||||||
appAlarmFind(params).then((rs: AppAlarmFindResponse) => {
|
|
||||||
responseAlarmSetting(rs);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const responseAlarmSetting = (data: AppAlarmFindResponse) => {
|
|
||||||
let responseAlarms: Record<string, boolean> = {};
|
let responseAlarms: Record<string, boolean> = {};
|
||||||
for(let i=0;i<data.alarmAgree.length;i++){
|
for(let i=0;i<data.alarmAgree.length;i++){
|
||||||
let item = data.alarmAgree[i];
|
let item = data.alarmAgree[i];
|
||||||
@@ -164,11 +169,23 @@ export const SettingPage = () => {
|
|||||||
responseAlarms['' + appNotificationSubCategory] = appNotificationAllowed;
|
responseAlarms['' + appNotificationSubCategory] = appNotificationAllowed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setAlarmSetting({
|
setAlarmSetting(prevState => ({
|
||||||
...alarmSetting,
|
...prevState,
|
||||||
...responseAlarms
|
...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) => {
|
const callAppAlarmConsent = (value: boolean, alarmCode: string) => {
|
||||||
if(userInfo.usrid){
|
if(userInfo.usrid){
|
||||||
@@ -178,7 +195,7 @@ export const SettingPage = () => {
|
|||||||
appNotificationSubCategory: alarmCode,
|
appNotificationSubCategory: alarmCode,
|
||||||
appNotificationAllowed: value
|
appNotificationAllowed: value
|
||||||
};
|
};
|
||||||
appAlarmConsent(params).then((rs: AppAlarmConsentResponse) => {
|
appAlarmConsent(params).then((_rs: AppAlarmConsentResponse) => {
|
||||||
setAlarmSetting({
|
setAlarmSetting({
|
||||||
...alarmSetting,
|
...alarmSetting,
|
||||||
...{ ['' + alarmCode]: value }
|
...{ ['' + alarmCode]: value }
|
||||||
@@ -187,23 +204,65 @@ export const SettingPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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(() => {
|
useEffect(() => {
|
||||||
callAppAlarmFind();
|
callAppAlarmFind();
|
||||||
checkPushNotificationStatus();
|
checkPushNotificationStatus();
|
||||||
loadLoginType();
|
loadLoginType();
|
||||||
loadNotificationSetting(); // ✅ 추가
|
loadNotificationSetting();
|
||||||
|
loadLanguage();
|
||||||
|
|
||||||
// 앱이 포어그라운드로 돌아올 때 푸시 알림 권한 상태 재확인
|
// 앱이 포어그라운드로 돌아올 때 푸시 알림 권한 상태 재확인
|
||||||
const handleVisibilityChange = () => {
|
const handleVisibilityChange = () => {
|
||||||
if (document.visibilityState === 'visible') {
|
if (document.visibilityState === 'visible') {
|
||||||
checkPushNotificationStatus();
|
checkPushNotificationStatus();
|
||||||
loadNotificationSetting(); // ✅ 추가
|
loadNotificationSetting();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFocus = () => {
|
const handleFocus = () => {
|
||||||
checkPushNotificationStatus();
|
checkPushNotificationStatus();
|
||||||
loadNotificationSetting(); // ✅ 추가
|
loadNotificationSetting();
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||||
@@ -213,7 +272,7 @@ export const SettingPage = () => {
|
|||||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||||
window.removeEventListener('focus', handleFocus);
|
window.removeEventListener('focus', handleFocus);
|
||||||
};
|
};
|
||||||
}, [checkPushNotificationStatus, loadLoginType, loadNotificationSetting]);
|
}, [callAppAlarmFind, checkPushNotificationStatus, loadLoginType, loadNotificationSetting, loadLanguage]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -221,7 +280,7 @@ export const SettingPage = () => {
|
|||||||
<div className="sub-wrap">
|
<div className="sub-wrap">
|
||||||
{/* ✅ Android일 때는 앱 내 설정, 아니면 시스템 권한 표시 */}
|
{/* ✅ Android일 때는 앱 내 설정, 아니면 시스템 권한 표시 */}
|
||||||
<div className="settings-header">
|
<div className="settings-header">
|
||||||
<div className="settings-title">알림 수신 설정</div>
|
<div className="settings-title">{t('settings.notificationSettings')}</div>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -243,9 +302,9 @@ export const SettingPage = () => {
|
|||||||
<div className="settings-divider"></div>
|
<div className="settings-divider"></div>
|
||||||
|
|
||||||
<div className="settings-section">
|
<div className="settings-section">
|
||||||
<div className="settings-section-title">공지사항 알림</div>
|
<div className="settings-section-title">{t('settings.noticeAlarms')}</div>
|
||||||
<div className="settings-row">
|
<div className="settings-row">
|
||||||
<div className="settings-row-title">서비스 운영 및 장애</div>
|
<div className="settings-row-title">{t('settings.serviceOperation')}</div>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -257,7 +316,7 @@ export const SettingPage = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-row">
|
<div className="settings-row">
|
||||||
<div className="settings-row-title">무이자 혜택 및 이벤트</div>
|
<div className="settings-row-title">{t('settings.interestFreeEvent')}</div>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -269,7 +328,7 @@ export const SettingPage = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-row">
|
<div className="settings-row">
|
||||||
<div className="settings-row-title">서비스 이용 및 정책 변경</div>
|
<div className="settings-row-title">{t('settings.servicePolicyChange')}</div>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -281,7 +340,7 @@ export const SettingPage = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-row">
|
<div className="settings-row">
|
||||||
<div className="settings-row-title">NICE소식 및 기타 정보</div>
|
<div className="settings-row-title">{t('settings.niceNews')}</div>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -295,9 +354,9 @@ export const SettingPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="settings-section nopadding">
|
<div className="settings-section nopadding">
|
||||||
<div className="settings-section-title">정산 알림</div>
|
<div className="settings-section-title">{t('settings.settlementAlarms')}</div>
|
||||||
<div className="settings-row">
|
<div className="settings-row">
|
||||||
<div className="settings-row-title">정산처리 현황</div>
|
<div className="settings-row-title">{t('settings.settlementStatus')}</div>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -309,7 +368,7 @@ export const SettingPage = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-row nopadding">
|
<div className="settings-row nopadding">
|
||||||
<div className="settings-row-title">정산한도 알림</div>
|
<div className="settings-row-title">{t('settings.settlementLimit')}</div>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -326,7 +385,7 @@ export const SettingPage = () => {
|
|||||||
|
|
||||||
<div className="settings-section nopadding">
|
<div className="settings-section nopadding">
|
||||||
<div className="settings-row link">
|
<div className="settings-row link">
|
||||||
<div className="settings-row-title bd-style">마케팅 정보 수신 동의</div>
|
<div className="settings-row-title bd-style">{t('settings.marketingConsent')}</div>
|
||||||
<label className="settings-switch">
|
<label className="settings-switch">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -342,22 +401,22 @@ export const SettingPage = () => {
|
|||||||
className="settings-row link"
|
className="settings-row link"
|
||||||
onClick={ () => setLoginTypeBottomSheetOn(true) }
|
onClick={ () => setLoginTypeBottomSheetOn(true) }
|
||||||
>
|
>
|
||||||
<div className="settings-row-title bd-style">로그인 방식 설정</div>
|
<div className="settings-row-title bd-style">{t('settings.loginTypeSetting')}</div>
|
||||||
<div className="click">{ APP_LOGIN_TYPE[loginType] }</div>
|
<div className="click">{ getLoginTypeLabel(loginType) }</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="settings-row link nopadding"
|
className="settings-row link nopadding"
|
||||||
onClick={ () => setServiceLanguageBottomSheetOn(true) }
|
onClick={ () => setServiceLanguageBottomSheetOn(true) }
|
||||||
>
|
>
|
||||||
<div className="settings-row-title bd-style">서비스 언어 설정</div>
|
<div className="settings-row-title bd-style">{t('settings.serviceLanguageSetting')}</div>
|
||||||
<div className="click">{ APP_LANGUAGE[appLanguage] }</div>
|
<div className="click">{ getLanguageLabel(appLanguage) }</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="settings-divider"></div>
|
<div className="settings-divider"></div>
|
||||||
|
|
||||||
<div className="settings-row danger" onClick={onClickLogout}>
|
<div className="settings-row danger" onClick={onClickLogout}>
|
||||||
<div className="settings-row-title bd-style">로그아웃</div>
|
<div className="settings-row-title bd-style">{t('settings.logout')}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ marginTop: '10px', paddingBottom: '10px' }}>
|
<div style={{ marginTop: '10px', paddingBottom: '10px' }}>
|
||||||
@@ -370,7 +429,7 @@ export const SettingPage = () => {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
padding: '12px'
|
padding: '12px'
|
||||||
}}
|
}}
|
||||||
>개인정보처리방침</div>
|
>{t('settings.privacyPolicy')}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@@ -379,7 +438,7 @@ export const SettingPage = () => {
|
|||||||
loginTypeBottomSheetOn={ loginTypeBottomSheetOn }
|
loginTypeBottomSheetOn={ loginTypeBottomSheetOn }
|
||||||
setLoginTypeBottomSheetOn={ setLoginTypeBottomSheetOn }
|
setLoginTypeBottomSheetOn={ setLoginTypeBottomSheetOn }
|
||||||
loginType={ loginType }
|
loginType={ loginType }
|
||||||
setLoginType={ setLoginType }
|
setLoginType={ handleSetLoginType }
|
||||||
></LoginTypeBottomSheet>
|
></LoginTypeBottomSheet>
|
||||||
}
|
}
|
||||||
{ !!serviceLanguageBottomSheetOn &&
|
{ !!serviceLanguageBottomSheetOn &&
|
||||||
@@ -388,6 +447,7 @@ export const SettingPage = () => {
|
|||||||
setServiceLanguageBottomSheetOn={ setServiceLanguageBottomSheetOn }
|
setServiceLanguageBottomSheetOn={ setServiceLanguageBottomSheetOn }
|
||||||
appLanguage={ appLanguage }
|
appLanguage={ appLanguage }
|
||||||
setAppLanguage={ setAppLanguage }
|
setAppLanguage={ setAppLanguage }
|
||||||
|
changeLanguage={ changeLanguage }
|
||||||
></ServiceLanguageBottomSheet>
|
></ServiceLanguageBottomSheet>
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user