앱브리지 getLoginType 메소드 추가 및 로그인 방식 설정 초기화

- 앱브리지에 getLoginType 메소드 추가
- 설정 페이지에서 로그인 방식을 앱에서 가져와 초기화
- 로그인 타입을 지문/안면에서 생체 인증으로 통합

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jay Sheen
2025-10-27 18:32:07 +09:00
parent d9ebc2c51f
commit 56ab761464
7 changed files with 53 additions and 22 deletions

View File

@@ -52,13 +52,9 @@ export const LoginTypeBottomSheet = ({
onClick={ () => onChangeLoginType(LoginType.ID) } onClick={ () => onChangeLoginType(LoginType.ID) }
>{ APP_LOGIN_TYPE[LoginType.ID] }</li> >{ APP_LOGIN_TYPE[LoginType.ID] }</li>
<li <li
className={ `${(loginType === LoginType.FINGER)? 'selected': ''}` } className={ `${(loginType === LoginType.BIOMETRIC)? 'selected': ''}` }
onClick={ () => onChangeLoginType(LoginType.FINGER) } onClick={ () => onChangeLoginType(LoginType.BIOMETRIC) }
>{ APP_LOGIN_TYPE[LoginType.FINGER] }</li> >{ APP_LOGIN_TYPE[LoginType.BIOMETRIC] }</li>
<li
className={ `${(loginType === LoginType.FACE)? 'selected': ''}` }
onClick={ () => onChangeLoginType(LoginType.FACE) }
>{ APP_LOGIN_TYPE[LoginType.FACE] }</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -8,8 +8,7 @@ export const APP_LANGUAGE = {
}; };
export const APP_LOGIN_TYPE = { export const APP_LOGIN_TYPE = {
ID: 'ID/PW 입력', ID: 'ID/PW 입력',
FINGER: '지문 인증', BIOMETRIC: '생체 인증',
FACE: '안면 인증'
}; };
export const DEFAULT_PAGE_PARAM = { export const DEFAULT_PAGE_PARAM = {
cursor: null, cursor: null,

View File

@@ -5,8 +5,7 @@ export enum AppLanguage {
}; };
export enum LoginType { export enum LoginType {
ID = 'ID', ID = 'ID',
FINGER = 'FINGER', BIOMETRIC = 'BIOMETRIC',
FACE = 'FACE'
}; };
export enum SuccessResult { export enum SuccessResult {
SUCCESS = 'SUCCESS', SUCCESS = 'SUCCESS',

View File

@@ -59,6 +59,9 @@ interface UseAppBridgeReturn {
// 앱 설정 화면 열기 // 앱 설정 화면 열기
openAppSettings: () => Promise<void>; openAppSettings: () => Promise<void>;
// 로그인 방식 설정 조회
getLoginType: () => Promise<string>;
} }
export const useAppBridge = (): UseAppBridgeReturn => { export const useAppBridge = (): UseAppBridgeReturn => {
@@ -250,6 +253,14 @@ export const useAppBridge = (): UseAppBridgeReturn => {
return appBridge.safeCall(() => appBridge.openAppSettings()); return appBridge.safeCall(() => appBridge.openAppSettings());
}, [isNativeEnvironment]); }, [isNativeEnvironment]);
const getLoginType = useCallback(async (): Promise<string> => {
if (!isNativeEnvironment) {
return 'ID';
}
const result = await appBridge.safeCall(() => appBridge.getLoginType(), 'ID');
return result || 'ID';
}, [isNativeEnvironment]);
return { return {
isNativeEnvironment, isNativeEnvironment,
isAndroid, isAndroid,
@@ -272,6 +283,7 @@ export const useAppBridge = (): UseAppBridgeReturn => {
openBiometricRegistrationPopup, openBiometricRegistrationPopup,
closeBiometricRegistrationPopup, closeBiometricRegistrationPopup,
isPushNotificationEnabled, isPushNotificationEnabled,
openAppSettings openAppSettings,
getLoginType
}; };
}; };

View File

@@ -11,12 +11,12 @@ import {
useSetHeaderType, useSetHeaderType,
useSetFooterMode useSetFooterMode
} from '@/widgets/sub-layout/use-sub-layout'; } from '@/widgets/sub-layout/use-sub-layout';
import { ChangeEvent, useEffect, useState } from 'react'; import { ChangeEvent, useCallback, useEffect, useState } from 'react';
import { useAppBridge } from '@/hooks/useAppBridge'; import { useAppBridge } from '@/hooks/useAppBridge';
export const SettingPage = () => { export const SettingPage = () => {
let userInfo = useStore.getState().UserStore.userInfo; let userInfo = useStore.getState().UserStore.userInfo;
const { isPushNotificationEnabled, openAppSettings } = useAppBridge(); const { isPushNotificationEnabled, openAppSettings, logout, getLoginType } = useAppBridge();
useSetHeaderTitle('설정'); useSetHeaderTitle('설정');
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
@@ -45,11 +45,22 @@ export const SettingPage = () => {
window.open('https://www.nicevan.co.kr/privacy-policy', '_blank'); window.open('https://www.nicevan.co.kr/privacy-policy', '_blank');
}; };
const checkPushNotificationStatus = () => { const onClickLogout = () => {
logout();
};
const checkPushNotificationStatus = useCallback(() => {
console.log('checkPushNotificationStatus');
isPushNotificationEnabled().then((enabled) => { isPushNotificationEnabled().then((enabled) => {
setPushNotificationEnabled(enabled); setPushNotificationEnabled(enabled);
}); });
}; }, [isPushNotificationEnabled]);
const loadLoginType = useCallback(() => {
getLoginType().then((type) => {
setLoginType(type as LoginType);
});
}, [getLoginType]);
const onClickPushNotificationToggle = () => { const onClickPushNotificationToggle = () => {
openAppSettings(); openAppSettings();
@@ -103,6 +114,7 @@ export const SettingPage = () => {
useEffect(() => { useEffect(() => {
callAppAlarmFind(); callAppAlarmFind();
checkPushNotificationStatus(); checkPushNotificationStatus();
loadLoginType();
// 앱이 포어그라운드로 돌아올 때 푸시 알림 권한 상태 재확인 // 앱이 포어그라운드로 돌아올 때 푸시 알림 권한 상태 재확인
const handleVisibilityChange = () => { const handleVisibilityChange = () => {
@@ -122,7 +134,7 @@ export const SettingPage = () => {
document.removeEventListener('visibilitychange', handleVisibilityChange); document.removeEventListener('visibilitychange', handleVisibilityChange);
window.removeEventListener('focus', handleFocus); window.removeEventListener('focus', handleFocus);
}; };
}, []); }, [checkPushNotificationStatus, loadLoginType]);
return ( return (
<> <>
@@ -131,7 +143,12 @@ export const SettingPage = () => {
<div className="settings-header"> <div className="settings-header">
<div className="settings-title"> </div> <div className="settings-title"> </div>
<label className="settings-switch" onClick={onClickPushNotificationToggle}> <label className="settings-switch" onClick={onClickPushNotificationToggle}>
<input type="checkbox" checked={pushNotificationEnabled} readOnly /> <input
type="checkbox"
checked={pushNotificationEnabled}
readOnly
onClick={(e) => e.preventDefault()}
/>
<span className="slider"></span> <span className="slider"></span>
</label> </label>
</div> </div>
@@ -234,7 +251,7 @@ export const SettingPage = () => {
</div> </div>
</div> </div>
<div <div
className="settings-row link" className="settings-row link"
onClick={ () => setLoginTypeBottomSheetOn(true) } onClick={ () => setLoginTypeBottomSheetOn(true) }
> >
@@ -242,7 +259,7 @@ export const SettingPage = () => {
<div className="click">{ APP_LOGIN_TYPE[loginType] }</div> <div className="click">{ APP_LOGIN_TYPE[loginType] }</div>
</div> </div>
<div <div
className="settings-row link nopadding" className="settings-row link nopadding"
onClick={ () => setServiceLanguageBottomSheetOn(true) } onClick={ () => setServiceLanguageBottomSheetOn(true) }
> >
@@ -252,7 +269,7 @@ export const SettingPage = () => {
<div className="settings-divider"></div> <div className="settings-divider"></div>
<div className="settings-row danger"> <div className="settings-row danger" onClick={onClickLogout}>
<div className="settings-row-title bd-style"></div> <div className="settings-row-title bd-style"></div>
</div> </div>

View File

@@ -71,7 +71,10 @@ export enum BridgeMessageType {
IS_PUSH_NOTIFICATION_ENABLED = 'isPushNotificationEnabled', IS_PUSH_NOTIFICATION_ENABLED = 'isPushNotificationEnabled',
// 앱 설정 화면 열기 // 앱 설정 화면 열기
OPEN_APP_SETTINGS = 'openAppSettings' OPEN_APP_SETTINGS = 'openAppSettings',
// 로그인 방식 설정
GET_LOGIN_TYPE = 'getLoginType'
} }
export interface DeviceInfo { export interface DeviceInfo {

View File

@@ -205,6 +205,11 @@ class AppBridge {
return this.sendMessage(BridgeMessageType.OPEN_APP_SETTINGS); return this.sendMessage(BridgeMessageType.OPEN_APP_SETTINGS);
} }
// 로그인 방식 설정 조회
async getLoginType(): Promise<string> {
return this.sendMessage(BridgeMessageType.GET_LOGIN_TYPE);
}
// 네이티브 환경 체크 // 네이티브 환경 체크
isNativeEnvironment(): boolean { isNativeEnvironment(): boolean {
return !!( return !!(