generated from pricelees/issue-pr-template
<!-- 제목 양식 --> <!-- [이슈번호] 작업 요약 (예시: [#10] Gitea 템플릿 생성) --> ## 📝 관련 이슈 및 PR **PR과 관련된 이슈 번호** - #22 ## ✨ 작업 내용 <!-- 어떤 작업을 했는지 알려주세요! --> - 기존 Thymeleaf 기반의 프론트엔드 코드를 React + Typescript 기반으로 마이그레이션 - 프론트엔드 분리에 따른 인증 API 수정 및 회원가입 API 추가 ## 🧪 테스트 <!-- 어떤 테스트를 생각했고 진행했는지 알려주세요! --> - 새로 추가된 API, 변경된 API 테스트 반영 ## 📚 참고 자료 및 기타 <!-- 참고한 자료, 또는 논의할 사항이 있다면 알려주세요! --> 프론트엔드 코드는 Gemini CLI가 구현하였고, API 관련 코드(ee21782ef9, frontend/src/api/**) 만 직접 구성 Reviewed-on: #23 Co-authored-by: pricelees <priceelees@gmail.com> Co-committed-by: pricelees <priceelees@gmail.com>
48 lines
1.8 KiB
TypeScript
48 lines
1.8 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { useLocation, useNavigate } from 'react-router-dom';
|
|
import type { LoginRequest } from '@_api/auth/authTypes';
|
|
import { useAuth } from '../context/AuthContext';
|
|
|
|
const LoginPage: React.FC = () => {
|
|
const [email, setEmail] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const { login } = useAuth();
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
|
|
const from = location.state?.from?.pathname || '/';
|
|
|
|
const handleLogin = async () => {
|
|
try {
|
|
const request: LoginRequest = { email, password };
|
|
await login(request);
|
|
|
|
alert('로그인에 성공했어요!');
|
|
navigate(from, { replace: true });
|
|
} catch (error: any) {
|
|
const message = error.response?.data?.message || '로그인에 실패했어요. 이메일과 비밀번호를 확인해주세요.';
|
|
alert(message);
|
|
console.error('로그인 실패:', error);
|
|
setEmail('');
|
|
setPassword('');
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="content-container" style={{ width: '300px' }}>
|
|
<h2 className="content-container-title">Login</h2>
|
|
<div className="form-group">
|
|
<input type="email" className="form-control" placeholder="Email" value={email} onChange={e => setEmail(e.target.value)} />
|
|
</div>
|
|
<div className="form-group">
|
|
<input type="password" className="form-control" placeholder="Password" value={password} onChange={e => setPassword(e.target.value)} />
|
|
</div>
|
|
<div className="d-flex justify-content-between">
|
|
<button className="btn btn-outline-custom" onClick={() => navigate('/signup')}>Sign Up</button>
|
|
<button className="btn btn-custom" onClick={handleLogin}>Login</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default LoginPage; |