summaryrefslogtreecommitdiff
path: root/components/login/login-form.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'components/login/login-form.tsx')
-rw-r--r--components/login/login-form.tsx201
1 files changed, 162 insertions, 39 deletions
diff --git a/components/login/login-form.tsx b/components/login/login-form.tsx
index 41d232f8..92fa6e2c 100644
--- a/components/login/login-form.tsx
+++ b/components/login/login-form.tsx
@@ -32,7 +32,8 @@ export function LoginForm({
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');
@@ -51,6 +52,8 @@ export function LoginForm({
const [otpSent, setOtpSent] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [otp, setOtp] = useState('');
+ const [username, setUsername] = useState('');
+ const [password, setPassword] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
@@ -58,17 +61,33 @@ export function LoginForm({
try {
const result = await sendOtpAction(email, lng);
- if (result?.success) {
+ if (result.success) {
setOtpSent(true);
toast({
title: t('otpSentTitle'),
description: t('otpSentMessage'),
});
+ } 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,
+ variant: 'destructive',
+ });
}
} catch (error) {
+ // This will catch network errors or other unexpected issues
+ console.error(error);
toast({
title: t('errorTitle'),
- description: t('defaultErrorMessage'),
+ description: t('networkErrorMessage'),
variant: 'destructive',
});
} finally {
@@ -76,11 +95,10 @@ export function LoginForm({
}
};
-
async function handleOtpSubmit(e: React.FormEvent) {
e.preventDefault();
setIsLoading(true);
-
+
try {
// next-auth의 Credentials Provider로 로그인 시도
const result = await signIn('credentials', {
@@ -88,30 +106,16 @@ export function LoginForm({
code: otp,
redirect: false, // 커스텀 처리 위해 redirect: false
});
-
+
if (result?.ok) {
// 토스트 메시지 표시
toast({
title: t('loginSuccess'),
description: t('youAreLoggedIn'),
});
-
- // NextAuth에서 유저 정보 API 호출 (최신 상태 보장)
- const response = await fetch('/api/auth/session');
- const session = await response.json();
-
- // domain 값에 따라 동적으로 리다이렉션
- const userDomain = session?.user?.domain;
- console.log(session)
-
- if (userDomain === 'evcp') {
- router.push(`/${lng}/evcp/report`);
- } else if (userDomain === 'partners') {
- router.push(`/${lng}/partners/dashboard`);
- } else {
- // 기본 리다이렉션 경로
- router.push(`/${lng}/dashboard`);
- }
+
+ router.push(`/${lng}/partners/dashboard`);
+
} else {
toast({
title: t('errorTitle'),
@@ -131,6 +135,53 @@ export function LoginForm({
}
}
+ // 새로운 로그인 처리 함수 추가
+ const handleCredentialsLogin = async () => {
+ if (!username || !password) {
+ toast({
+ title: t('errorTitle'),
+ description: t('credentialsRequired'),
+ variant: 'destructive',
+ });
+ return;
+ }
+
+ setIsLoading(true);
+
+ try {
+ // next-auth의 다른 credentials provider로 로그인 시도
+ const result = await signIn('credentials-password', {
+ username,
+ password,
+ redirect: false,
+ });
+
+ if (result?.ok) {
+ toast({
+ title: t('loginSuccess'),
+ description: t('youAreLoggedIn'),
+ });
+
+ router.push(`/${lng}/partners/dashboard`);
+ } else {
+ toast({
+ title: t('errorTitle'),
+ description: t('invalidCredentials'),
+ variant: 'destructive',
+ });
+ }
+ } catch (error) {
+ console.error('Login error:', error);
+ toast({
+ title: t('errorTitle'),
+ description: t('defaultErrorMessage'),
+ variant: 'destructive',
+ });
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
useEffect(() => {
const verifyToken = async () => {
if (!token) return;
@@ -197,20 +248,92 @@ export function LoginForm({
<div className="flex flex-col items-center text-center">
<h1 className="text-2xl font-bold">{t('loginMessage')}</h1>
</div>
- <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)}
- />
- </div>
- <Button type="submit" className="w-full" variant="samsung" disabled={isLoading}>
- {isLoading ? t('sending') : t('ContinueWithEmail')}
- </Button>
+
+ {/* S-chips 로그인 폼이 표시되지 않을 때만 이메일 입력 필드 표시 */}
+ {!showCredentialsForm && (
+ <>
+ <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)}
+ />
+ </div>
+ <Button type="submit" className="w-full" variant="samsung" disabled={isLoading}>
+ {isLoading ? t('sending') : t('ContinueWithEmail')}
+ </Button>
+
+ {/* 구분선과 "Or continue with" 섹션 추가 */}
+ <div className="relative">
+ <div className="absolute inset-0 flex items-center">
+ <span className="w-full border-t"></span>
+ </div>
+ <div className="relative flex justify-center text-xs uppercase">
+ <span className="bg-background px-2 text-muted-foreground">
+ {t('orContinueWith')}
+ </span>
+ </div>
+ </div>
+
+ {/* S-chips 로그인 버튼 */}
+ <Button
+ type="button"
+ className="w-full"
+ // variant=""
+ onClick={() => setShowCredentialsForm(true)}
+ >
+ S-chips로 로그인하기
+ </Button>
+ </>
+ )}
+
+ {/* ID/비밀번호 로그인 폼 - 버튼 클릭 시에만 표시 */}
+ {showCredentialsForm && (
+ <>
+ <div className="grid gap-4">
+ <Input
+ id="username"
+ type="text"
+ placeholder="S-chips 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)}
+ />
+ <Button
+ type="button"
+ className="w-full"
+ variant="samsung"
+ onClick={handleCredentialsLogin}
+ disabled={isLoading}
+ >
+ {isLoading ? "로그인 중..." : "로그인"}
+ </Button>
+
+ {/* 뒤로 가기 버튼 */}
+ <Button
+ type="button"
+ variant="ghost"
+ className="w-full text-sm"
+ onClick={() => setShowCredentialsForm(false)}
+ >
+ 이메일로 로그인하기
+ </Button>
+ </div>
+ </>
+ )}
+
<div className="text-center text-sm mx-auto">
<DropdownMenu>
<DropdownMenuTrigger asChild>
@@ -302,8 +425,8 @@ export function LoginForm({
<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"
+ <Image
+ src="/images/02.jpg"
alt="Background image"
fill
priority