From e9897d416b3e7327bbd4d4aef887eee37751ae82 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Fri, 27 Jun 2025 01:16:20 +0000
Subject: (대표님) 20250627 오전 10시 작업사항
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/login/login-form.tsx | 814 +++++++++++++++++++++++++++-------------
 1 file changed, 559 insertions(+), 255 deletions(-)

(limited to 'components/login/login-form.tsx')

diff --git a/components/login/login-form.tsx b/components/login/login-form.tsx
index 4f9fbb53..7af607b5 100644
--- a/components/login/login-form.tsx
+++ b/components/login/login-form.tsx
@@ -3,43 +3,66 @@
 import { useState, useEffect } from "react";
 import { cn } from "@/lib/utils"
 import { Button } from "@/components/ui/button"
-import { Card, CardContent } from "@/components/ui/card"
 import { Input } from "@/components/ui/input"
-import { SendIcon, Loader2, GlobeIcon, ChevronDownIcon, Ship, InfoIcon } from "lucide-react";
+import { Ship, InfoIcon, GlobeIcon, ChevronDownIcon, ArrowLeft } from "lucide-react";
 import { useToast } from "@/hooks/use-toast";
 import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem } from "@/components/ui/dropdown-menu"
 import { useTranslation } from '@/i18n/client'
 import { useRouter, useParams, usePathname, useSearchParams } from 'next/navigation';
+import { signIn, getSession } from 'next-auth/react';
+import { buttonVariants } from "@/components/ui/button"
+import Link from "next/link"
+import Image from 'next/image';
+import { useFormState } from 'react-dom';
 import {
     InputOTP,
     InputOTPGroup,
     InputOTPSlot,
 } from "@/components/ui/input-otp"
-import { signIn } from 'next-auth/react';
-import { sendOtpAction } from "@/lib/users/send-otp";
-import { verifyTokenAction } from "@/lib/users/verifyToken";
-import { buttonVariants } from "@/components/ui/button"
-import Link from "next/link"
-import Image from 'next/image'; // 추가: Image 컴포넌트 import
+import { requestPasswordResetAction } from "@/lib/users/auth/partners-auth";
+
+type LoginMethod = 'username' | 'sgips';
 
 export function LoginForm({
     className,
     ...props
 }: React.ComponentProps<"div">) {
-
     const params = useParams() || {};
     const pathname = usePathname() || '';
     const router = useRouter();
     const searchParams = useSearchParams();
-    const token = searchParams?.get('token') || null;
-    const [showCredentialsForm, setShowCredentialsForm] = useState(false);
-
 
     const lng = params.lng as string;
     const { t, i18n } = useTranslation(lng, 'login');
-
     const { toast } = useToast();
 
+    // 상태 관리
+    const [loginMethod, setLoginMethod] = useState<LoginMethod>('username');
+    const [isLoading, setIsLoading] = useState(false);
+    const [showForgotPassword, setShowForgotPassword] = useState(false);
+
+    // MFA 관련 상태
+    const [showMfaForm, setShowMfaForm] = useState(false);
+    const [mfaToken, setMfaToken] = useState('');
+    const [mfaUserId, setMfaUserId] = useState('');
+    const [mfaUserEmail, setMfaUserEmail] = useState('');
+    const [mfaCountdown, setMfaCountdown] = useState(0);
+
+    // 일반 로그인 폼 데이터
+    const [username, setUsername] = useState('');
+    const [password, setPassword] = useState('');
+
+    // S-Gips 로그인 폼 데이터  
+    const [sgipsUsername, setSgipsUsername] = useState('');
+    const [sgipsPassword, setSgipsPassword] = useState('');
+
+    // 서버 액션 상태
+    const [passwordResetState, passwordResetAction] = useFormState(requestPasswordResetAction, {
+        success: false,
+        error: undefined,
+        message: undefined,
+    });
+
     const handleChangeLanguage = (lang: string) => {
         const segments = pathname.split('/');
         segments[1] = lang;
@@ -48,50 +71,66 @@ export function LoginForm({
 
     const currentLanguageText = i18n.language === 'ko' ? t('languages.korean') : t('languages.english');
 
-    const [email, setEmail] = useState('');
-    const [otpSent, setOtpSent] = useState(false);
-    const [isLoading, setIsLoading] = useState(false);
-    const [otp, setOtp] = useState('');
-    const [username, setUsername] = useState('');
-    const [password, setPassword] = useState('');
-
     const goToVendorRegistration = () => {
         router.push(`/${lng}/partners/repository`);
     };
 
-    const handleSubmit = async (e: React.FormEvent) => {
-        e.preventDefault();
+    // MFA 카운트다운 효과
+    useEffect(() => {
+        if (mfaCountdown > 0) {
+            const timer = setTimeout(() => setMfaCountdown(mfaCountdown - 1), 1000);
+            return () => clearTimeout(timer);
+        }
+    }, [mfaCountdown]);
+
+    // 서버 액션 결과 처리
+    useEffect(() => {
+        if (passwordResetState.success && passwordResetState.message) {
+            toast({
+                title: '재설정 링크 전송',
+                description: passwordResetState.message,
+            });
+            setShowForgotPassword(false);
+        } else if (passwordResetState.error) {
+            toast({
+                title: t('errorTitle'),
+                description: passwordResetState.error,
+                variant: 'destructive',
+            });
+        }
+    }, [passwordResetState, toast, t]);
+
+    // SMS 토큰 전송
+    const handleSendSms = async () => {
+        if (!mfaUserId || mfaCountdown > 0) return;
+
         setIsLoading(true);
         try {
-            const result = await sendOtpAction(email, lng);
+            // SMS 전송 API 호출 (실제 구현 필요)
+            const response = await fetch('/api/auth/send-sms', {
+                method: 'POST',
+                headers: { 'Content-Type': 'application/json' },
+                body: JSON.stringify({ userId: mfaUserId }),
+            });
 
-            if (result.success) {
-                setOtpSent(true);
+            if (response.ok) {
+                setMfaCountdown(60); // 60초 카운트다운
                 toast({
-                    title: t('otpSentTitle'),
-                    description: t('otpSentMessage'),
+                    title: 'SMS 전송 완료',
+                    description: '인증번호를 전송했습니다.',
                 });
             } else {
-                // Handle specific error types
-                let errorMessage = t('defaultErrorMessage');
-
-                // You can handle different error types differently
-                if (result.error === 'userNotFound') {
-                    errorMessage = t('userNotFoundMessage');
-                }
-
                 toast({
                     title: t('errorTitle'),
-                    description: result.message || errorMessage,
+                    description: 'SMS 전송에 실패했습니다.',
                     variant: 'destructive',
                 });
             }
         } catch (error) {
-            // This will catch network errors or other unexpected issues
-            console.error(error);
+            console.error('SMS send error:', error);
             toast({
                 title: t('errorTitle'),
-                description: t('networkErrorMessage'),
+                description: 'SMS 전송 중 오류가 발생했습니다.',
                 variant: 'destructive',
             });
         } finally {
@@ -99,65 +138,75 @@ export function LoginForm({
         }
     };
 
-    async function handleOtpSubmit(e: React.FormEvent) {
+    // MFA 토큰 검증
+    const handleMfaSubmit = async (e: React.FormEvent) => {
         e.preventDefault();
+
+        if (!mfaToken || mfaToken.length !== 6) {
+            toast({
+                title: t('errorTitle'),
+                description: '6자리 인증번호를 입력해주세요.',
+                variant: 'destructive',
+            });
+            return;
+        }
+
         setIsLoading(true);
 
         try {
-            // next-auth의 Credentials Provider로 로그인 시도
-            const result = await signIn('credentials', {
-                email,
-                code: otp,
-                redirect: false, // 커스텀 처리 위해 redirect: false
+            // MFA 토큰 검증 API 호출
+            const response = await fetch('/api/auth/verify-mfa', {
+                method: 'POST',
+                headers: { 'Content-Type': 'application/json' },
+                body: JSON.stringify({
+                    userId: mfaUserId,
+                    token: mfaToken
+                }),
             });
 
-            if (result?.ok) {
-                // 토스트 메시지 표시
+            if (response.ok) {
                 toast({
-                    title: t('loginSuccess'),
-                    description: t('youAreLoggedIn'),
+                    title: '인증 완료',
+                    description: '로그인이 완료되었습니다.',
                 });
 
+                // callbackUrl 처리
                 const callbackUrlParam = searchParams?.get('callbackUrl');
-  
                 if (callbackUrlParam) {
-                  try {
-                    // URL 객체로 파싱
-                    const callbackUrl = new URL(callbackUrlParam);
-                    
-                    // pathname + search만 사용 (호스트 제거)
-                    const relativeUrl = callbackUrl.pathname + callbackUrl.search;
-                    router.push(relativeUrl);
-                  } catch (e) {
-                    // 유효하지 않은 URL이면 그대로 사용 (이미 상대 경로일 수 있음)
-                    router.push(callbackUrlParam);
-                  }
+                    try {
+                        const callbackUrl = new URL(callbackUrlParam);
+                        const relativeUrl = callbackUrl.pathname + callbackUrl.search;
+                        router.push(relativeUrl);
+                    } catch (e) {
+                        router.push(callbackUrlParam);
+                    }
                 } else {
-                  // callbackUrl이 없으면 기본 대시보드로 리다이렉트
-                  router.push(`/${lng}/partners/dashboard`);
+                    router.push(`/${lng}/partners/dashboard`);
                 }
-
             } else {
+                const errorData = await response.json();
                 toast({
                     title: t('errorTitle'),
-                    description: t('defaultErrorMessage'),
+                    description: errorData.message || '인증번호가 올바르지 않습니다.',
                     variant: 'destructive',
                 });
             }
         } catch (error) {
-            console.error('Login error:', error);
+            console.error('MFA verification error:', error);
             toast({
                 title: t('errorTitle'),
-                description: t('defaultErrorMessage'),
+                description: 'MFA 인증 중 오류가 발생했습니다.',
                 variant: 'destructive',
             });
         } finally {
             setIsLoading(false);
         }
-    }
+    };
+
+    // 일반 사용자명/패스워드 로그인 처리 (간소화된 버전)
+    const handleUsernameLogin = async (e: React.FormEvent) => {
+        e.preventDefault();
 
-    // 새로운 로그인 처리 함수 추가
-    const handleCredentialsLogin = async () => {
         if (!username || !password) {
             toast({
                 title: t('errorTitle'),
@@ -170,24 +219,55 @@ export function LoginForm({
         setIsLoading(true);
 
         try {
-            // next-auth의 다른 credentials provider로 로그인 시도
+            // NextAuth credentials-password provider로 로그인
             const result = await signIn('credentials-password', {
-                username,
-                password,
+                username: username,
+                password: password,
                 redirect: false,
             });
 
             if (result?.ok) {
+                // 로그인 1차 성공 - 바로 MFA 화면으로 전환
                 toast({
                     title: t('loginSuccess'),
-                    description: t('youAreLoggedIn'),
+                    description: '1차 인증이 완료되었습니다.',
+                });
+
+                // 모든 사용자는 MFA 필수이므로 바로 MFA 폼으로 전환
+                setMfaUserId(username); // 입력받은 username 사용
+                setMfaUserEmail(username); // 입력받은 username 사용 (보통 이메일)
+                setShowMfaForm(true);
+
+                // 자동으로 SMS 전송
+                setTimeout(() => {
+                    handleSendSms();
+                }, 500);
+
+                toast({
+                    title: 'SMS 인증 필요',
+                    description: '등록된 전화번호로 인증번호를 전송합니다.',
                 });
 
-                router.push(`/${lng}/partners/dashboard`);
             } else {
+                // 로그인 실패 처리
+                let errorMessage = t('invalidCredentials');
+
+                if (result?.error) {
+                    switch (result.error) {
+                        case 'CredentialsSignin':
+                            errorMessage = t('invalidCredentials');
+                            break;
+                        case 'AccessDenied':
+                            errorMessage = t('accessDenied');
+                            break;
+                        default:
+                            errorMessage = t('defaultErrorMessage');
+                    }
+                }
+
                 toast({
                     title: t('errorTitle'),
-                    description: t('invalidCredentials'),
+                    description: errorMessage,
                     variant: 'destructive',
                 });
             }
@@ -203,36 +283,87 @@ export function LoginForm({
         }
     };
 
-    useEffect(() => {
-        const verifyToken = async () => {
-            if (!token) return;
-            setIsLoading(true);
 
-            try {
-                const data = await verifyTokenAction(token);
+    // S-Gips 로그인 처리
+    // S-Gips 로그인 처리 (간소화된 버전)
+    const handleSgipsLogin = async (e: React.FormEvent) => {
+        e.preventDefault();
 
-                if (data.valid) {
-                    setOtpSent(true);
-                    setEmail(data.email ?? '');
-                } else {
-                    toast({
-                        title: t('errorTitle'),
-                        description: t('invalidToken'),
-                        variant: 'destructive',
-                    });
+        if (!sgipsUsername || !sgipsPassword) {
+            toast({
+                title: t('errorTitle'),
+                description: t('credentialsRequired'),
+                variant: 'destructive',
+            });
+            return;
+        }
+
+        setIsLoading(true);
+
+        try {
+            // NextAuth credentials-password provider로 로그인 (S-Gips 구분)
+            const result = await signIn('credentials-password', {
+                username: sgipsUsername,
+                password: sgipsPassword,
+                provider: 'sgips', // S-Gips 구분을 위한 추가 파라미터
+                redirect: false,
+            });
+
+            if (result?.ok) {
+                // S-Gips 1차 인증 성공 - 바로 MFA 화면으로 전환
+                toast({
+                    title: t('loginSuccess'),
+                    description: 'S-Gips 인증이 완료되었습니다.',
+                });
+
+                // S-Gips도 MFA 필수이므로 바로 MFA 폼으로 전환
+                setMfaUserId(sgipsUsername);
+                setMfaUserEmail(sgipsUsername);
+                setShowMfaForm(true);
+
+                // 자동으로 SMS 전송
+                setTimeout(() => {
+                    handleSendSms();
+                }, 500);
+
+                toast({
+                    title: 'SMS 인증 시작',
+                    description: 'S-Gips 등록 전화번호로 인증번호를 전송합니다.',
+                });
+
+            } else {
+                let errorMessage = t('sgipsLoginFailed');
+
+                if (result?.error) {
+                    switch (result.error) {
+                        case 'CredentialsSignin':
+                            errorMessage = t('invalidSgipsCredentials');
+                            break;
+                        case 'AccessDenied':
+                            errorMessage = t('sgipsAccessDenied');
+                            break;
+                        default:
+                            errorMessage = t('sgipsSystemError');
+                    }
                 }
-            } catch (error) {
+
                 toast({
                     title: t('errorTitle'),
-                    description: t('defaultErrorMessage'),
+                    description: errorMessage,
                     variant: 'destructive',
                 });
-            } finally {
-                setIsLoading(false);
             }
-        };
-        verifyToken();
-    }, [token, toast, t]);
+        } catch (error) {
+            console.error('S-Gips login error:', error);
+            toast({
+                title: t('errorTitle'),
+                description: t('sgipsSystemError'),
+                variant: 'destructive',
+            });
+        } finally {
+            setIsLoading(false);
+        }
+    };
 
     return (
         <div className="container relative flex h-screen flex-col items-center justify-center md:grid lg:max-w-none lg:grid-cols-2 lg:px-0">
@@ -241,11 +372,6 @@ export function LoginForm({
                 {/* Top bar with Logo + eVCP (left) and "Request Vendor Repository" (right) */}
                 <div className="flex items-center justify-between">
                     <div className="flex items-center space-x-2">
-                        {/* <img
-              src="/images/logo.png"
-              alt="logo"
-              className="h-8 w-auto"
-            /> */}
                         <Ship className="w-4 h-4" />
                         <span className="text-md font-bold">eVCP</span>
                     </div>
@@ -253,178 +379,350 @@ export function LoginForm({
                         href="/partners/repository"
                         className={cn(buttonVariants({ variant: "ghost" }))}
                     >
-                      <InfoIcon className="w-4 h-4 mr-1" />
-                      {'업체 등록 신청'}
+                        <InfoIcon className="w-4 h-4 mr-1" />
+                        {'업체 등록 신청'}
                     </Link>
                 </div>
 
                 {/* Content section that occupies remaining space, centered vertically */}
                 <div className="flex-1 flex items-center justify-center">
-                    {/* Your form container */}
                     <div className="mx-auto w-full flex flex-col space-y-6 sm:w-[350px]">
-
-                        {/* Here's your existing login/OTP forms: */}
-                        {!otpSent ? (
-
-                            <form onSubmit={handleSubmit} className="p-6 md:p-8"> 
-                            {/* <form onSubmit={handleOtpSubmit} className="p-6 md:p-8"> */}
-                                <div className="flex flex-col gap-6">
+                        <div className="p-6 md:p-8">
+                            <div className="flex flex-col gap-6">
+                                {/* Header */}
                                 <div className="flex flex-col items-center text-center">
-                                    <h1 className="text-2xl font-bold">{t('loginMessage')}</h1>
-                                    
-                                    {/* 설명 텍스트 추가 - 업체 등록 관련 안내 */}
-                                    <p className="text-xs text-muted-foreground mt-2">
-                                        {'등록된 업체만 로그인하실 수 있습니다. 아직도 등록되지 않은 업체라면 상단의 업체 등록 신청 버튼을 이용해주세요.'}
-                                    </p>
-                                </div>
-
-                                    {/* S-Gips 로그인 폼이 표시되지 않을 때만 이메일 입력 필드 표시 */}
-                                    {!showCredentialsForm && (
+                                    {!showMfaForm ? (
                                         <>
-                                            <div className="grid gap-2">
-                                                <Input
-                                                    id="email"
-                                                    type="email"
-                                                    placeholder={t('email')}
-                                                    required
-                                                    className="h-10"
-                                                    value={email}
-                                                    onChange={(e) => setEmail(e.target.value)}
-                                                />
+                                            <h1 className="text-2xl font-bold">{t('loginMessage')}</h1>
+                                            <p className="text-xs text-muted-foreground mt-2">
+                                                {'등록된 업체만 로그인하실 수 있습니다. 아직 등록되지 않은 업체라면 상단의 업체 등록 신청 버튼을 이용해주세요.'}
+                                            </p>
+                                        </>
+                                    ) : (
+                                        <>
+                                            <div className="flex items-center justify-center w-12 h-12 rounded-full bg-blue-100 mb-4">
+                                                🔐
                                             </div>
-                                            <Button type="submit" className="w-full" variant="samsung" disabled={isLoading}>
-                                                {isLoading ? t('sending') : t('ContinueWithEmail')}
-                                            </Button>
+                                            <h1 className="text-2xl font-bold">SMS 인증</h1>
+                                            <p className="text-sm text-muted-foreground mt-2">
+                                                {mfaUserEmail}로 로그인하셨습니다
+                                            </p>
+                                            <p className="text-xs text-muted-foreground mt-1">
+                                                등록된 전화번호로 전송된 6자리 인증번호를 입력해주세요
+                                            </p>
+                                        </>
+                                    )}
+                                </div>
 
-                                            {/* 구분선과 "Or continue with" 섹션 추가 */}
-                                            <div className="relative">
-                                                <div className="absolute inset-0 flex items-center">
-                                                    <span className="w-full border-t"></span>
+                                {/* 로그인 폼 또는 MFA 폼 */}
+                                {!showMfaForm ? (
+                                    <>
+                                        {/* Login Method Tabs */}
+                                        <div className="flex rounded-lg bg-muted p-1">
+                                            <button
+                                                type="button"
+                                                onClick={() => setLoginMethod('username')}
+                                                className={cn(
+                                                    "flex-1 rounded-md px-3 py-2 text-sm font-medium transition-all",
+                                                    loginMethod === 'username'
+                                                        ? "bg-background text-foreground shadow-sm"
+                                                        : "text-muted-foreground hover:text-foreground"
+                                                )}
+                                            >
+                                                일반 로그인
+                                            </button>
+                                            <button
+                                                type="button"
+                                                onClick={() => setLoginMethod('sgips')}
+                                                className={cn(
+                                                    "flex-1 rounded-md px-3 py-2 text-sm font-medium transition-all",
+                                                    loginMethod === 'sgips'
+                                                        ? "bg-background text-foreground shadow-sm"
+                                                        : "text-muted-foreground hover:text-foreground"
+                                                )}
+                                            >
+                                                S-Gips 로그인
+                                            </button>
+                                        </div>
+
+                                        {/* Username Login Form */}
+                                        {loginMethod === 'username' && (
+                                            <form onSubmit={handleUsernameLogin} className="grid gap-4">
+                                                <div className="grid gap-2">
+                                                    <Input
+                                                        id="username"
+                                                        type="text"
+                                                        placeholder="이메일을 넣으세요"
+                                                        required
+                                                        className="h-10"
+                                                        value={username}
+                                                        onChange={(e) => setUsername(e.target.value)}
+                                                        disabled={isLoading}
+                                                    />
                                                 </div>
-                                                <div className="relative flex justify-center text-xs uppercase">
-                                                    <span className="bg-background px-2 text-muted-foreground">
-                                                        {t('orContinueWith')}
-                                                    </span>
+                                                <div className="grid gap-2">
+                                                    <Input
+                                                        id="password"
+                                                        type="password"
+                                                        placeholder={t('password')}
+                                                        required
+                                                        className="h-10"
+                                                        value={password}
+                                                        onChange={(e) => setPassword(e.target.value)}
+                                                        disabled={isLoading}
+                                                    />
                                                 </div>
-                                            </div>
-
-                                            {/* S-Gips 로그인 버튼 */}
+                                                <Button
+                                                    type="submit"
+                                                    className="w-full"
+                                                    variant="samsung"
+                                                    disabled={isLoading || !username || !password}
+                                                >
+                                                    {isLoading ? '로그인 중...' : t('login')}
+                                                </Button>
+                                            </form>
+                                        )}
+
+                                        {/* S-Gips Login Form */}
+                                        {loginMethod === 'sgips' && (
+                                            <form onSubmit={handleSgipsLogin} className="grid gap-4">
+                                                <div className="grid gap-2">
+                                                    <Input
+                                                        id="sgipsUsername"
+                                                        type="text"
+                                                        placeholder="S-Gips ID"
+                                                        required
+                                                        className="h-10"
+                                                        value={sgipsUsername}
+                                                        onChange={(e) => setSgipsUsername(e.target.value)}
+                                                        disabled={isLoading}
+                                                    />
+                                                </div>
+                                                <div className="grid gap-2">
+                                                    <Input
+                                                        id="sgipsPassword"
+                                                        type="password"
+                                                        placeholder="S-Gips 비밀번호"
+                                                        required
+                                                        className="h-10"
+                                                        value={sgipsPassword}
+                                                        onChange={(e) => setSgipsPassword(e.target.value)}
+                                                        disabled={isLoading}
+                                                    />
+                                                </div>
+                                                <Button
+                                                    type="submit"
+                                                    className="w-full"
+                                                    variant="default"
+                                                    disabled={isLoading || !sgipsUsername || !sgipsPassword}
+                                                >
+                                                    {isLoading ? 'S-Gips 인증 중...' : 'S-Gips 로그인'}
+                                                </Button>
+                                                <p className="text-xs text-muted-foreground text-center">
+                                                    S-Gips 계정으로 로그인하면 자동으로 SMS 인증이 진행됩니다.
+                                                </p>
+                                            </form>
+                                        )}
+
+                                        {/* Additional Links */}
+                                        <div className="flex flex-col gap-2 text-center">
                                             <Button
                                                 type="button"
-                                                className="w-full"
-                                                // variant=""
-                                                onClick={() => setShowCredentialsForm(true)}
+                                                variant="link"
+                                                className="text-blue-600 hover:text-blue-800 text-sm"
+                                                onClick={goToVendorRegistration}
                                             >
-                                                S-Gips로 로그인하기
+                                                {'신규 업체이신가요? 여기서 등록하세요'}
                                             </Button>
 
-                                        {/* 업체 등록 안내 링크 추가 */}
-                                        <Button
-                                            type="button"
-                                            variant="link"
-                                            className="text-blue-600 hover:text-blue-800"
-                                            onClick={goToVendorRegistration}
-                                        >
-                                            {'신규 업체이신가요? 여기서 등록하세요'}
-                                        </Button>
-                                        </>
-                                    )}
-
-                                    {/* ID/비밀번호 로그인 폼 - 버튼 클릭 시에만 표시 */}
-                                    {showCredentialsForm && (
-                                        <>
-                                            <div className="grid gap-4">
-                                                <Input
-                                                    id="username"
-                                                    type="text"
-                                                    placeholder="S-Gips ID"
-                                                    className="h-10"
-                                                    value={username}
-                                                    onChange={(e) => setUsername(e.target.value)}
-                                                />
-                                                <Input
-                                                    id="password"
-                                                    type="password"
-                                                    placeholder="비밀번호"
-                                                    className="h-10"
-                                                    value={password}
-                                                    onChange={(e) => setPassword(e.target.value)}
-                                                />
+                                            {loginMethod === 'username' && (
                                                 <Button
                                                     type="button"
-                                                    className="w-full"
-                                                    variant="samsung"
-                                                    onClick={handleCredentialsLogin}
-                                                    disabled={isLoading}
+                                                    variant="link"
+                                                    className="text-blue-600 hover:text-blue-800 text-sm"
+                                                    onClick={() => setShowForgotPassword(true)}
                                                 >
-                                                    {isLoading ? "로그인 중..." : "로그인"}
+                                                    비밀번호를 잊으셨나요?
                                                 </Button>
+                                            )}
 
-                                                {/* 뒤로 가기 버튼 */}
+                                            {/* 테스트용 MFA 화면 버튼 */}
+                                            {process.env.NODE_ENV === 'development' && (
                                                 <Button
                                                     type="button"
-                                                    variant="ghost"
-                                                    className="w-full text-sm"
-                                                    onClick={() => setShowCredentialsForm(false)}
+                                                    variant="link"
+                                                    className="text-green-600 hover:text-green-800 text-sm"
+                                                    onClick={() => {
+                                                        setMfaUserId('test-user');
+                                                        setMfaUserEmail('test@example.com');
+                                                        setShowMfaForm(true);
+                                                    }}
                                                 >
-                                                    이메일로 로그인하기
+                                                    [개발용] MFA 화면 테스트
                                                 </Button>
+                                            )}
+                                        </div>
+                                    </>
+                                ) : (
+                                    /* MFA 입력 폼 */
+                                    <div className="space-y-6">
+                                        {/* 뒤로 가기 버튼 */}
+                                        <div className="flex items-center justify-start">
+                                            <Button
+                                                type="button"
+                                                variant="ghost"
+                                                size="sm"
+                                                onClick={() => {
+                                                    setShowMfaForm(false);
+                                                    setMfaToken('');
+                                                    setMfaUserId('');
+                                                    setMfaUserEmail('');
+                                                    setMfaCountdown(0);
+                                                }}
+                                                className="text-blue-600 hover:text-blue-800"
+                                            >
+                                                <ArrowLeft className="w-4 h-4 mr-1" />
+                                                다시 로그인하기
+                                            </Button>
+                                        </div>
+
+                                        {/* SMS 재전송 섹션 */}
+                                        <div className="bg-gray-50 p-4 rounded-lg">
+                                            <h3 className="text-sm font-medium text-gray-900 mb-2">
+                                                인증번호 재전송
+                                            </h3>
+                                            <p className="text-xs text-gray-600 mb-3">
+                                                인증번호를 받지 못하셨나요?
+                                            </p>
+                                            <Button
+                                                onClick={handleSendSms}
+                                                disabled={isLoading || mfaCountdown > 0}
+                                                variant="outline"
+                                                size="sm"
+                                                className="w-full"
+                                            >
+                                                {isLoading ? (
+                                                    '전송 중...'
+                                                ) : mfaCountdown > 0 ? (
+                                                    `재전송 가능 (${mfaCountdown}초)`
+                                                ) : (
+                                                    '인증번호 재전송'
+                                                )}
+                                            </Button>
+                                        </div>
+
+                                        {/* SMS 토큰 입력 폼 */}
+                                        <form onSubmit={handleMfaSubmit} className="space-y-6">
+                                            <div className="space-y-4">
+                                                <div className="text-center">
+                                                    <label className="block text-sm font-medium text-gray-700 mb-3">
+                                                        6자리 인증번호를 입력해주세요
+                                                    </label>
+                                                    <div className="flex justify-center">
+                                                        <InputOTP
+                                                            maxLength={6}
+                                                            value={mfaToken}
+                                                            onChange={(value) => setMfaToken(value)}
+                                                        >
+                                                            <InputOTPGroup>
+                                                                <InputOTPSlot index={0} />
+                                                                <InputOTPSlot index={1} />
+                                                                <InputOTPSlot index={2} />
+                                                                <InputOTPSlot index={3} />
+                                                                <InputOTPSlot index={4} />
+                                                                <InputOTPSlot index={5} />
+                                                            </InputOTPGroup>
+                                                        </InputOTP>
+                                                    </div>
+                                                </div>
                                             </div>
-                                        </>
-                                    )}
 
-                                    <div className="text-center text-sm mx-auto">
-                                        <DropdownMenu>
-                                            <DropdownMenuTrigger asChild>
-                                                <Button variant="ghost" className="flex items-center gap-2">
-                                                    <GlobeIcon className="h-4 w-4" />
-                                                    <span>{currentLanguageText}</span>
-                                                    <ChevronDownIcon className="h-4 w-4" />
-                                                </Button>
-                                            </DropdownMenuTrigger>
-                                            <DropdownMenuContent align="end">
-                                                <DropdownMenuRadioGroup
-                                                    value={i18n.language}
-                                                    onValueChange={(value) => handleChangeLanguage(value)}
-                                                >
-                                                    <DropdownMenuRadioItem value="en">
-                                                        {t('languages.english')}
-                                                    </DropdownMenuRadioItem>
-                                                    <DropdownMenuRadioItem value="ko">
-                                                        {t('languages.korean')}
-                                                    </DropdownMenuRadioItem>
-                                                </DropdownMenuRadioGroup>
-                                            </DropdownMenuContent>
-                                        </DropdownMenu>
-                                    </div>
-                                </div>
-                            </form>
-                         ) : (
-                            <form onSubmit={handleOtpSubmit} className="flex flex-col gap-4 p-6 md:p-8">
-                                <div className="flex flex-col gap-6">
-                                    <div className="flex flex-col items-center text-center">
-                                        <h1 className="text-2xl font-bold">{t('loginMessage')}</h1>
+                                            <Button
+                                                type="submit"
+                                                className="w-full"
+                                                variant="samsung"
+                                                disabled={isLoading || mfaToken.length !== 6}
+                                            >
+                                                {isLoading ? '인증 중...' : '인증 완료'}
+                                            </Button>
+                                        </form>
+
+                                        {/* 도움말 */}
+                                        <div className="bg-yellow-50 p-3 rounded-lg border border-yellow-200">
+                                            <div className="flex">
+                                                <div className="flex-shrink-0">
+                                                    ⚠️
+                                                </div>
+                                                <div className="ml-2">
+                                                    <h4 className="text-xs font-medium text-yellow-800">
+                                                        인증번호를 받지 못하셨나요?
+                                                    </h4>
+                                                    <div className="mt-1 text-xs text-yellow-700">
+                                                        <ul className="list-disc list-inside space-y-1">
+                                                            <li>전화번호가 올바른지 확인해주세요</li>
+                                                            <li>스팸 메시지함을 확인해주세요</li>
+                                                            <li>잠시 후 재전송 버튼을 이용해주세요</li>
+                                                        </ul>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                        </div>
                                     </div>
-                                    <div className="grid gap-2 justify-center">
-                                        <InputOTP
-                                            maxLength={6}
-                                            value={otp}
-                                            onChange={(value) => setOtp(value)}
-                                        >
-                                            <InputOTPGroup>
-                                                <InputOTPSlot index={0} />
-                                                <InputOTPSlot index={1} />
-                                                <InputOTPSlot index={2} />
-                                                <InputOTPSlot index={3} />
-                                                <InputOTPSlot index={4} />
-                                                <InputOTPSlot index={5} />
-                                            </InputOTPGroup>
-                                        </InputOTP>
+                                )}
+
+                                {/* 비밀번호 재설정 다이얼로그 */}
+                                {showForgotPassword && !showMfaForm && (
+                                    <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
+                                        <div className="bg-white rounded-lg p-6 w-full max-w-md mx-4">
+                                            <div className="flex justify-between items-center mb-4">
+                                                <h3 className="text-lg font-semibold">비밀번호 재설정</h3>
+                                                <button
+                                                    onClick={() => {
+                                                        setShowForgotPassword(false);
+                                                    }}
+                                                    className="text-gray-400 hover:text-gray-600"
+                                                >
+                                                    ✕
+                                                </button>
+                                            </div>
+                                            <form action={passwordResetAction} className="space-y-4">
+                                                <div>
+                                                    <p className="text-sm text-gray-600 mb-3">
+                                                        가입하신 이메일 주소를 입력하시면 비밀번호 재설정 링크를 보내드립니다.
+                                                    </p>
+                                                    <Input
+                                                        name="email"
+                                                        type="email"
+                                                        placeholder="이메일 주소"
+                                                        required
+                                                    />
+                                                </div>
+                                                <div className="flex gap-2">
+                                                    <Button
+                                                        type="button"
+                                                        variant="outline"
+                                                        className="flex-1"
+                                                        onClick={() => {
+                                                            setShowForgotPassword(false);
+                                                        }}
+                                                    >
+                                                        취소
+                                                    </Button>
+                                                    <Button
+                                                        type="submit"
+                                                        className="flex-1"
+                                                    >
+                                                        재설정 링크 전송
+                                                    </Button>
+                                                </div>
+                                            </form>
+                                        </div>
                                     </div>
-                                    <Button type="submit" className="w-full" disabled={isLoading}>
-                                        {isLoading ? t('verifying') : t('verifyOtp')}
-                                    </Button>
-                                    <div className="mx-auto">
+                                )}
+
+                                {/* Language Selector - MFA 화면에서는 숨김 */}
+                                {!showMfaForm && (
+                                    <div className="text-center text-sm mx-auto">
                                         <DropdownMenu>
                                             <DropdownMenuTrigger asChild>
                                                 <Button variant="ghost" className="flex items-center gap-2">
@@ -448,21 +746,28 @@ export function LoginForm({
                                             </DropdownMenuContent>
                                         </DropdownMenu>
                                     </div>
-                                </div>
-                            </form>
-                        )}
-
-                        <div className="text-balance text-center text-xs text-muted-foreground [&_a]:underline [&_a]:underline-offset-4 hover:[&_a]:text-primary">
-                            {t('termsMessage')} <a href="#">{t('termsOfService')}</a> {t('and')}
-                            <a href="#">{t('privacyPolicy')}</a>.
+                                )}
+                            </div>
                         </div>
+
+                        {/* Terms - MFA 화면에서는 숨김 */}
+                        {!showMfaForm && (
+                            <div className="text-balance text-center text-xs text-muted-foreground [&_a]:underline [&_a]:underline-offset-4 hover:[&_a]:text-primary">
+                                {t("agreement")}{" "}
+                                <Link
+                                    href={`/${lng}/privacy`}  // 개인정보처리방침만 남김
+                                    className="underline underline-offset-4 hover:text-primary"
+                                >
+                                    {t("privacyPolicy")}
+                                </Link>
+                            </div>
+                        )}
                     </div>
                 </div>
             </div>
 
-            {/* Right BG 이미지 영역 - Image 컴포넌트로 수정 */}
+            {/* Right BG 이미지 영역 */}
             <div className="relative hidden h-full flex-col p-10 text-white dark:border-r md:flex">
-                {/* Image 컴포넌트로 대체 */}
                 <div className="absolute inset-0">
                     <Image
                         src="/images/02.jpg"
@@ -476,7 +781,6 @@ export function LoginForm({
                 <div className="relative z-10 mt-auto">
                     <blockquote className="space-y-2">
                         <p className="text-sm">&ldquo;{t("blockquote")}&rdquo;</p>
-                        {/* <footer className="text-sm">SHI</footer> */}
                     </blockquote>
                 </div>
             </div>
-- 
cgit v1.2.3

