diff options
| author | joonhoekim <26rote@gmail.com> | 2025-11-03 10:39:51 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-11-03 10:39:51 +0900 |
| commit | 1c5dd9c10ce4264ab157f4a2479e2055a3487de4 (patch) | |
| tree | e05cefb406b87d6152a7c08a5b96057528c796b5 /components/login | |
| parent | 98d178c8fe20a61a87e5d8f20e7d310ff6fefd6b (diff) | |
(김준회) 벤더 로그인화면 영상 더 크게 변경
Diffstat (limited to 'components/login')
| -rw-r--r-- | components/login/login-form.tsx | 187 |
1 files changed, 75 insertions, 112 deletions
diff --git a/components/login/login-form.tsx b/components/login/login-form.tsx index 51d54531..fae5b8c9 100644 --- a/components/login/login-form.tsx +++ b/components/login/login-form.tsx @@ -4,7 +4,7 @@ import { useState, useEffect } from "react"; import { cn } from "@/lib/utils" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" -import { Ship, InfoIcon, GlobeIcon, ChevronDownIcon, ArrowLeft } from "lucide-react"; +import { 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' @@ -21,6 +21,7 @@ import { import { requestPasswordResetAction } from "@/lib/users/auth/partners-auth"; import { checkEmailAndStartAuth, resendEmailOtp } from "@/lib/users/auth/email-auth"; import Loading from "../common/loading/loading"; +import { VideoBackground } from "@/components/common/video-background"; // 배경 영상 목록 const BACKGROUND_VIDEOS = [ @@ -44,9 +45,6 @@ export function LoginForm() { const { toast } = useToast(); const { data: session, status } = useSession(); - // 배경 영상 상태 - const [currentVideoIndex, setCurrentVideoIndex] = useState(0); - // 상태 관리 const [isFirstAuthLoading, setIsFirstAuthLoading] = useState(false); const [showForgotPassword, setShowForgotPassword] = useState(false); @@ -83,14 +81,11 @@ export function LoginForm() { // 호스트명 확인 상태 추가 const [isDataRoomHost, setIsDataRoomHost] = useState(false); - // 컴포넌트 마운트 시 호스트명 확인 및 랜덤 비디오 선택 + // 컴포넌트 마운트 시 호스트명 확인 useEffect(() => { if (typeof window !== 'undefined') { const hostname = window.location.hostname; setIsDataRoomHost(hostname.includes('shidataroom')); - - // 랜덤한 비디오 인덱스 선택 - setCurrentVideoIndex(Math.floor(Math.random() * BACKGROUND_VIDEOS.length)); } }, []); @@ -168,11 +163,6 @@ export function LoginForm() { router.push(`/${lng}/partners/repository`); }; - // 비디오 종료 시 다음 비디오로 전환 - const handleVideoEnd = () => { - setCurrentVideoIndex((prevIndex) => (prevIndex + 1) % BACKGROUND_VIDEOS.length); - }; - // MFA 카운트다운 효과 useEffect(() => { if (mfaCountdown > 0) { @@ -576,47 +566,59 @@ export function LoginForm() { } 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"> - {/* Left Content */} - <div className="flex flex-col w-full h-screen lg:p-2"> - {/* 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"> - <Ship className="w-4 h-4" /> - <span className="text-md font-bold">{isDataRoomHost ? "Data Room" : "eVCP"}</span> + <div className="relative flex h-screen w-full items-center justify-start overflow-hidden"> + {/* 전체 화면 배경 영상 */} + <VideoBackground + videos={BACKGROUND_VIDEOS} + overlayClassName="bg-black/50" + showCacheStatus={process.env.NODE_ENV === 'development'} + /> + + {/* 로그인 카드 */} + <div className="relative z-20 w-full max-w-md ml-8 md:ml-16 lg:ml-24"> + {/* 불투명한 카드 배경 */} + <div className="bg-card rounded-lg shadow-2xl overflow-hidden border border-border"> + {/* 헤더 */} + <div className="px-6 py-4 border-b bg-gradient-to-r from-blue-600 to-blue-700"> + <div className="flex items-center justify-between text-white"> + <div className="flex items-center space-x-2"> + {/* <Ship className="w-5 h-5" /> */} + <span className="text-lg font-bold">{isDataRoomHost ? "Data Room" : "eVCP"}</span> + </div> + {!isDataRoomHost && ( + <Link + href="/partners/repository" + className={cn( + buttonVariants({ variant: "ghost" }), + "text-white hover:bg-white/20 hover:text-white" + )} + > + <InfoIcon className="w-4 h-4 mr-1" /> + {t('registerVendor')} + </Link> + )} + </div> </div> - {!isDataRoomHost && ( - <Link - href="/partners/repository" - className={cn(buttonVariants({ variant: "ghost" }))} - > - <InfoIcon className="w-4 h-4 mr-1" /> - {t('registerVendor')} - </Link> - )} - </div> - {/* Content section that occupies remaining space, centered vertically */} - <div className="flex-1 flex items-center justify-center"> - <div className="mx-auto w-full flex flex-col space-y-6 sm:w-[350px]"> - <div className="p-6 md:p-8"> - <div className="flex flex-col gap-6"> - {/* Header */} - <div className="flex flex-col items-center text-center"> + {/* 로그인 폼 컨텐츠 */} + <div className="p-8"> + <div className="flex flex-col gap-6"> + {/* Header */} + <div className="flex flex-col items-center text-center"> {!showMfaForm ? ( <> - <h1 className="text-2xl font-bold">{isDataRoomHost ? t('loginMessageDataRoom') :t('loginMessage')}</h1> + <h1 className="text-2xl font-bold text-foreground">{isDataRoomHost ? t('loginMessageDataRoom') :t('loginMessage')}</h1> <p className="text-xs text-muted-foreground mt-2"> {isDataRoomHost?t('loginDescriptionDataRoom') :t('loginDescription')} </p> </> ) : ( <> - <div className="flex items-center justify-center w-12 h-12 rounded-full bg-blue-100 mb-4"> + <div className="flex items-center justify-center w-12 h-12 rounded-full bg-blue-100 dark:bg-blue-900/30 mb-4"> {mfaType === 'email' ? '📧' : '🔐'} </div> - <h1 className="text-2xl font-bold"> + <h1 className="text-2xl font-bold text-foreground"> {mfaType === 'email' ? t('emailVerification') : t('smsVerification')} </h1> <p className="text-sm text-muted-foreground mt-2"> @@ -674,7 +676,7 @@ export function LoginForm() { variant="ghost" size="sm" onClick={handleBackToLogin} - className="text-blue-600 hover:text-blue-800" + className="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300" > <ArrowLeft className="w-4 h-4 mr-1" /> {t('backToLogin')} @@ -682,9 +684,9 @@ export function LoginForm() { </div> {/* 이메일 표시 */} - <div className="bg-gray-50 p-3 rounded-lg"> - <p className="text-sm text-gray-600 mb-1">{t('loginEmail')}</p> - <p className="text-sm font-medium text-gray-900">{emailInput}</p> + <div className="bg-muted p-3 rounded-lg"> + <p className="text-sm text-muted-foreground mb-1">{t('loginEmail')}</p> + <p className="text-sm font-medium text-foreground">{emailInput}</p> </div> {/* 패스워드 입력 폼 */} @@ -722,7 +724,7 @@ export function LoginForm() { <Button type="button" variant="link" - className="text-blue-600 hover:text-blue-800 text-sm" + className="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 text-sm" onClick={goToVendorRegistration} > {t('newVendor')} @@ -734,7 +736,7 @@ export function LoginForm() { <Button type="button" variant="link" - className="text-blue-600 hover:text-blue-800 text-sm" + className="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 text-sm" onClick={() => setShowForgotPassword(true)} > {t('forgotPassword')} @@ -752,7 +754,7 @@ export function LoginForm() { variant="ghost" size="sm" onClick={handleBackToLogin} - className="text-blue-600 hover:text-blue-800" + className="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300" > <ArrowLeft className="w-4 h-4 mr-1" /> {t('backToLogin')} @@ -760,11 +762,11 @@ export function LoginForm() { </div> {/* OTP 재전송 섹션 (SMS/Email) */} - <div className="bg-gray-50 p-4 rounded-lg"> - <h3 className="text-sm font-medium text-gray-900 mb-2"> + <div className="bg-muted p-4 rounded-lg"> + <h3 className="text-sm font-medium text-foreground mb-2"> {t('resendCode')} </h3> - <p className="text-xs text-gray-600 mb-3"> + <p className="text-xs text-muted-foreground mb-3"> {mfaType === 'email' ? t('didNotReceiveEmail') : t('didNotReceiveCode')} @@ -797,7 +799,7 @@ export function LoginForm() { <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"> + <label className="block text-sm font-medium text-foreground mb-3"> {t('enterSixDigitCode')} </label> <div className="flex justify-center"> @@ -830,16 +832,16 @@ export function LoginForm() { </form> {/* 도움말 */} - <div className="bg-yellow-50 p-3 rounded-lg border border-yellow-200"> + <div className="bg-yellow-50 dark:bg-yellow-900/20 p-3 rounded-lg border border-yellow-200 dark:border-yellow-800"> <div className="flex"> <div className="flex-shrink-0"> ⚠️ </div> <div className="ml-2"> - <h4 className="text-xs font-medium text-yellow-800"> + <h4 className="text-xs font-medium text-yellow-800 dark:text-yellow-300"> {t('didNotReceiveCode')} </h4> - <div className="mt-1 text-xs text-yellow-700"> + <div className="mt-1 text-xs text-yellow-700 dark:text-yellow-400"> <ul className="list-disc list-inside space-y-1"> <li>{t('checkPhoneNumber')}</li> <li>{t('checkSpamFolder')}</li> @@ -854,22 +856,22 @@ export function LoginForm() { {/* 비밀번호 재설정 다이얼로그 */} {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="fixed inset-0 bg-black/50 dark:bg-black/70 flex items-center justify-center z-50"> + <div className="bg-card rounded-lg p-6 w-full max-w-md mx-4 border border-border"> <div className="flex justify-between items-center mb-4"> - <h3 className="text-lg font-semibold">{t('resetPassword')}</h3> + <h3 className="text-lg font-semibold text-foreground">{t('resetPassword')}</h3> <button onClick={() => { setShowForgotPassword(false); }} - className="text-gray-400 hover:text-gray-600" + className="text-muted-foreground hover:text-foreground" > ✕ </button> </div> <form action={passwordResetAction} className="space-y-4"> <div> - <p className="text-sm text-gray-600 mb-3"> + <p className="text-sm text-muted-foreground mb-3"> {t('resetDescription')} </p> <Input @@ -929,60 +931,21 @@ export function LoginForm() { </DropdownMenu> </div> )} - </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 영상 영역 */} - <div className="relative hidden h-full flex-col p-10 text-white dark:border-r md:flex overflow-hidden"> - <div className="absolute inset-0"> - <video - key={currentVideoIndex} - autoPlay - muted - onEnded={handleVideoEnd} - className="w-full h-full object-cover" - playsInline - > - <source src={BACKGROUND_VIDEOS[currentVideoIndex]} type="video/mp4" /> - </video> - {/* 어두운 오버레이 */} - <div className="absolute inset-0 bg-black/30"></div> - </div> - <div className="relative z-10 mt-auto"> - <blockquote className="space-y-2 backdrop-blur-sm bg-black/20 p-4 rounded-lg"> - <p className="text-sm font-medium drop-shadow-lg">“{t("blockquote")}”</p> - </blockquote> - </div> - {/* 비디오 인디케이터 */} - <div className="relative z-10 flex justify-center space-x-2 mb-4"> - {BACKGROUND_VIDEOS.map((_, index) => ( - <div - key={index} - className={cn( - "w-2 h-2 rounded-full transition-all duration-300", - index === currentVideoIndex - ? "bg-white w-8" - : "bg-white/50 hover:bg-white/75 cursor-pointer" + {/* Terms - MFA 화면에서는 숨김 */} + {!showMfaForm && ( + <div className="text-balance text-center text-xs text-muted-foreground [&_a]:underline [&_a]:underline-offset-4 hover:[&_a]:text-primary mt-4"> + {t("agreement")}{" "} + <Link + href={`/${lng}/privacy`} + className="underline underline-offset-4 hover:text-primary" + > + {t("privacyPolicy")} + </Link> + </div> )} - onClick={() => setCurrentVideoIndex(index)} - /> - ))} + </div> + </div> </div> </div> </div> |
