@@ -13,7 +13,6 @@ import { SettingsView } from "./views/SettingsView";
1313import { AdminView } from "./views/AdminView" ;
1414import { MarketplaceView } from "./views/MarketplaceView" ;
1515import { ChangePasswordView } from "./views/ChangePasswordView" ;
16- import { OtpView } from "./views/OtpView" ;
1716import { ForgotPasswordView } from "./views/ForgotPasswordView" ;
1817
1918// ─── Types ────────────────────────────────────────────────────
@@ -43,7 +42,7 @@ function resolveInstallMode(runtimeEnv: WebRuntimeEnv): InstallMode {
4342function getRouteFromHash ( rawHash : string ) : RouteKey {
4443 const hash = rawHash . replace ( "#" , "" ) ;
4544 if ( hash === "settings" ) return "home" ;
46- const valid : RouteKey [ ] = [ "login" , "otp" , " forgot-password", "home" , "marketplace" , "admin" , "change-password" ] ;
45+ const valid : RouteKey [ ] = [ "login" , "forgot-password" , "home" , "marketplace" , "admin" , "change-password" ] ;
4746 return ( valid as string [ ] ) . includes ( hash ) ? ( hash as RouteKey ) : "login" ;
4847}
4948
@@ -125,8 +124,8 @@ function App({ installMode }: { installMode: InstallMode }) {
125124 } , [ ] ) ;
126125
127126 const effectiveRoute = useMemo < RouteKey > ( ( ) => {
128- // OTP 대기 중: otp 화면만 허용
129- if ( pendingOtpEmail ) return "otp " ;
127+ // OTP 대기 중: login 화면 유지 (LoginView 내부에서 step 전환)
128+ if ( pendingOtpEmail ) return "login " ;
130129 // 미인증: login / forgot-password만 허용
131130 if ( ! isAuthenticated ) {
132131 return route === "forgot-password" ? "forgot-password" : "login" ;
@@ -154,10 +153,9 @@ function App({ installMode }: { installMode: InstallMode }) {
154153 const email = ( formData . get ( "email" ) as string | null ) ?? "user@fieldstack.dev" ;
155154 const password = formData . get ( "password" ) as string | null ;
156155
157- // mock: "otp1234" → 2FA OTP 화면으로 이동
156+ // mock: "otp1234" → LoginView 내 OTP step으로 전환
158157 if ( password === "otp1234" ) {
159158 setPendingOtpEmail ( email ) ;
160- navigate ( "otp" ) ;
161159 return ;
162160 }
163161
@@ -236,7 +234,7 @@ function App({ installMode }: { installMode: InstallMode }) {
236234 navigate ( "login" ) ;
237235 } ;
238236
239- // Login page (no shell)
237+ // Login page (no shell) — OTP step도 이 안에서 처리
240238 if ( effectiveRoute === "login" ) {
241239 return (
242240 < main className = "auth-shell" >
@@ -246,6 +244,9 @@ function App({ installMode }: { installMode: InstallMode }) {
246244 onQuickLogin = { onQuickLogin }
247245 onForgotPassword = { ( ) => navigate ( "forgot-password" ) }
248246 showDevBypass = { installMode === "bypass" }
247+ pendingEmail = { pendingOtpEmail }
248+ onOtpVerified = { onOtpVerified }
249+ onOtpCancel = { onOtpCancel }
249250 />
250251 </ section >
251252 </ main >
@@ -257,17 +258,6 @@ function App({ installMode }: { installMode: InstallMode }) {
257258 return < ForgotPasswordView onBack = { ( ) => navigate ( "login" ) } /> ;
258259 }
259260
260- // 2FA OTP 인증 (no shell)
261- if ( effectiveRoute === "otp" ) {
262- return (
263- < OtpView
264- email = { pendingOtpEmail ?? "" }
265- onVerified = { onOtpVerified }
266- onCancel = { onOtpCancel }
267- />
268- ) ;
269- }
270-
271261 // 비밀번호 강제 변경 (shell 없이 전체 화면)
272262 if ( effectiveRoute === "change-password" ) {
273263 return (
0 commit comments