Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 46 additions & 5 deletions src/components/LoginPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,62 @@ import { useNavigate } from "react-router-dom";
import "../styles/LoginPage.css";

function LoginForm() {

const [email,setEmail]=useState("");
const [password,setPassword]=useState("");
const [message,setMessage]=useState(""); // 사용자 입력을 저장할 상태 설정
const navigate = useNavigate(); //페이지 이동을 위한 navigate 설정


const postUser = async () => {
try {
const res = await axios.post("https://reqres.in/api/login", {
email : email,
password : password,
}, {
headers: {
"x-api-key": "reqres-free-v1"} // 인증용 API 키
});

localStorage.setItem("token", res.data.token);
localStorage.setItem("email", email); // 응답에 성공했을 시, token과 email을 localstorage에 저장
navigate("/userlist"); // userlist로 이동

} catch (error) { // 실패했을 시에
const errMsg = error.response?.data?.error || "User not found";
setMessage(errMsg); // 응답 객체 안의 data.error 에 접근하여 그 내용을 에러 메시지로 표시
}
};



const handleLogin = async (e) => {
e.preventDefault();

if (!email || !password) { // 만약 이메일과 비밀 번호가 입력되지 않았다면
setMessage("이메일과 비밀번호를 모두 입력해주세요."); // 이 메시지가 뜨도록 함
return;
}


await postUser(); // postuser 함수가 끝날 때까지 기다리고 실행
};



const handleEmail = async(e) => {
setEmail(e.target.value)
};

const handlePW = async(e) => {
setPassword(e.target.value)
};

return (
<form onSubmit={handleLogin} className="login-container">
<h2>🔐 로그인</h2>
<input/>
<input/>
<button type="submit">로그인</button>
<input required value ={email} onChange={handleEmail} placeholder="이메일 입력"/>
<input required value={password} onChange={handlePW} placeholder="비밀번호 입력" type="password"/>
<button type="submit" onClick={handleLogin}>로그인</button>
{message && <p className="message">{message}</p>}
</form>
);
}
Expand Down
58 changes: 52 additions & 6 deletions src/components/UserList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,72 @@ import React, { useEffect, useState } from "react";
import axios from "axios";
import "../styles/UserList.css";


function UserCard({ user }) {
return (
<div className="user-card" key={user.id}>
<img className="user-avatar" src={user.avatar} alt="avatar" />
<h4>{user.first_name} {user.last_name}</h4>
<p className="user-email">{user.email}</p>
</div>
); // 개별로 받은 유저를 카드 형태로 보여줌 (사진, 성과 이름, 이메일 주소)
}

function UserList() {
const [users, setUsers] = useState([]);
const [search, setSearch] = useState("");

const email = localStorage.getItem("email");
const token = localStorage.getItem("token");

useEffect(() => {
axios.get("https://reqres.in/api/users", {
headers: {
"x-api-key": "reqres-free-v1"
}
})
.then((res) => {
setUsers(res.data.data);
})
.catch((err) => {
console.error("error : 유저 가져오기 실패", err);
});
}, []);


const filteredUsers = users.filter((user) =>
user.first_name.toLowerCase().includes(search.toLowerCase()) ||
user.email.toLowerCase().includes(search.toLowerCase())
);


return (
<div className="user-container">
<div className="user-info-box">
<p><strong>이메일:</strong> { }</p>
<p><strong>토큰:</strong> { }</p>
<p><strong>이메일:</strong> {email}</p>
<p><strong>토큰:</strong> {token}</p>
</div>


<h2 className="user-title">👥 유저 목록</h2>

<input
className="user-search"
/>
placeholder="이름 또는 이메일로 검색하세요"
value={search}
onChange={(e) => setSearch(e.target.value)
}/>

<div className="user-list">

</div>

<div className="userlist">
{filteredUsers.map((user) => (
<UserCard key={user.id} user={user} />
))}
</div>
</div>
);
}



export default UserList;
3 changes: 2 additions & 1 deletion src/styles/UserList.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
.user-list {
display: flex;
flex-wrap: wrap;
justify-content: center;
flex-direction : row;
justify-content: flex-start;
gap: 30px;
max-width: 960px;
margin: 0 auto;
Expand Down