fix: 로그인 중복 요청 방지 및 Strict Mode 활성화

- 로그인 진행 중 상태 관리 추가 (isLoggingIn)
- 중복 요청 차단 로직 구현
- 로그인 버튼 비활성화 및 로딩 표시
- next.config.ts reactStrictMode 활성화

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
byeongcheolryu
2025-11-24 18:57:35 +09:00
parent df3db155dd
commit 5b2f8adc87
2 changed files with 25 additions and 3 deletions

View File

@@ -4,6 +4,7 @@ import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts');
const nextConfig: NextConfig = {
reactStrictMode: true, // 🧪 TEST: Strict Mode 비활성화로 중복 요청 테스트
turbopack: {}, // ✅ CRITICAL: Next.js 15 + next-intl compatibility
typescript: {
// ⚠️ WARNING: This allows production builds to complete even with TypeScript errors

View File

@@ -28,6 +28,7 @@ export function LoginPage() {
const [rememberMe, setRememberMe] = useState(false);
const [error, setError] = useState("");
const [isChecking, setIsChecking] = useState(true);
const [isLoggingIn, setIsLoggingIn] = useState(false); // ✅ 로그인 진행 중 상태
// 이미 로그인된 상태인지 확인 (페이지 로드 시, 뒤로가기 시)
useEffect(() => {
@@ -53,6 +54,12 @@ export function LoginPage() {
}, [router]);
const handleLogin = async () => {
// ✅ 중복 요청 방지
if (isLoggingIn) {
console.warn('⚠️ 로그인 진행 중 - 중복 요청 차단');
return;
}
setError("");
// Validation
@@ -61,6 +68,8 @@ export function LoginPage() {
return;
}
setIsLoggingIn(true); // ✅ 로그인 시작
try {
// 🔵 Next.js 프록시 → PHP /api/v1/login (토큰을 HttpOnly 쿠키로 저장)
const response = await fetch('/api/auth/login', {
@@ -122,6 +131,8 @@ export function LoginPage() {
} else {
setError(error.message || t('invalidCredentials'));
}
} finally {
setIsLoggingIn(false); // ✅ 로그인 종료 (성공/실패 상관없이)
}
};
@@ -249,10 +260,20 @@ export function LoginPage() {
<Button
type="submit"
className="w-full rounded-xl bg-primary hover:bg-primary/90"
disabled={isLoggingIn} // ✅ 로그인 중 버튼 비활성화
className="w-full rounded-xl bg-primary hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed"
>
{t('login')}
<ArrowRight className="ml-2 w-4 h-4" />
{isLoggingIn ? (
<>
<div className="inline-block h-4 w-4 animate-spin rounded-full border-2 border-solid border-current border-r-transparent mr-2"></div>
{t('loggingIn') || '로그인 중...'}
</>
) : (
<>
{t('login')}
<ArrowRight className="ml-2 w-4 h-4" />
</>
)}
</Button>
</form>