"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { LanguageSelect } from "@/components/LanguageSelect"; import { ThemeSelect } from "@/components/ThemeSelect"; import { User, Lock, Eye, EyeOff, ArrowRight } from "lucide-react"; export function LoginPage() { const router = useRouter(); const t = useTranslations('auth'); const tCommon = useTranslations('common'); const tValidation = useTranslations('validation'); const [userId, setUserId] = useState(""); const [password, setPassword] = useState(""); const [showPassword, setShowPassword] = useState(false); const [rememberMe, setRememberMe] = useState(false); const [error, setError] = useState(""); const handleLogin = async () => { setError(""); // Validation if (!userId || !password) { setError(tValidation('required')); return; } try { // ✅ HttpOnly Cookie 방식: Next.js API Route로 프록시 // 토큰은 JavaScript에서 접근 불가능한 HttpOnly 쿠키로 저장됨 const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ user_id: userId, user_pwd: password, }), }); const data = await response.json(); if (!response.ok) { throw { status: response.status, message: data.error || 'Login failed', }; } console.log('✅ 로그인 성공:', data.message); console.log('📦 사용자 정보:', data.user); console.log('🔐 토큰은 안전한 HttpOnly 쿠키에 저장됨 (JavaScript 접근 불가)'); // 대시보드로 이동 router.push("/dashboard"); } catch (err: any) { console.error('❌ 로그인 실패:', err); if (err.status === 422) { setError(t('invalidCredentials')); } else if (err.status === 429) { setError('너무 많은 로그인 시도가 있었습니다. 잠시 후 다시 시도해주세요.'); } else { setError(err.message || t('invalidCredentials')); } } }; return (
{tCommon('welcome')} SAM MES
{error}
{t('noAccount')}{" "}