-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
347 additions
and
19 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { useEffect, useState } from "react"; | ||
import { useNavigate } from "react-router-dom"; | ||
import axiosInstance from "services/axiosInstance"; | ||
|
||
interface Post { | ||
id: number; | ||
title: string; | ||
category: string; | ||
writer: string; | ||
content: string; | ||
like: number; | ||
scrap: number; | ||
replyCount: number; | ||
} | ||
|
||
export default function HomePage() { | ||
const [page, setPage] = useState<number>(1); | ||
const [posts, setPosts] = useState<Post[]>([]); | ||
const navigate = useNavigate(); | ||
|
||
useEffect(() => { | ||
const fetchPosts = async () => { | ||
try { | ||
const response = await axiosInstance.get(`/api/posts?page=${page}`); | ||
setPosts(response.data.data.posts); | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
}; | ||
|
||
fetchPosts(); | ||
}, [page]); | ||
|
||
const handlePageChange = (newPage: number) => { | ||
setPage(newPage); | ||
}; | ||
|
||
return ( | ||
<div> | ||
<h1>게시글 목록</h1> | ||
<div> | ||
<button | ||
onClick={() => handlePageChange(page - 1)} | ||
disabled={page === 1} | ||
> | ||
이전 페이지 | ||
</button> | ||
<span>페이지 {page}</span> | ||
<button onClick={() => handlePageChange(page + 1)}>다음 페이지</button> | ||
</div> | ||
<ul> | ||
{posts.map((post) => ( | ||
<li key={post.id} onClick={() => navigate(`/post/${post.id}`)}> | ||
<h2>{post.title}</h2> | ||
<p>{post.content}</p> | ||
<p>작성자: {post.writer}</p> | ||
<p> | ||
좋아요: {post.like} 스크랩: {post.scrap} 댓글: {post.replyCount} | ||
</p> | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { useState } from "react"; | ||
import { useNavigate } from "react-router-dom"; | ||
import axiosInstance from "services/axiosInstance"; | ||
|
||
export default function LoginPage() { | ||
const [studentId, setStudentId] = useState(""); | ||
const [password, setPassword] = useState(""); | ||
const navigate = useNavigate(); | ||
|
||
const handleLogin = async () => { | ||
try { | ||
const response = await axiosInstance.post("/api/members/login", { | ||
studentId: studentId, | ||
password: password, | ||
}); | ||
const accessToken = response.data.data.accessToken; | ||
localStorage.setItem("accessToken", accessToken); | ||
navigate("/"); | ||
} catch (error) { | ||
console.error("로그인 실패:", error); | ||
alert("로그인 실패"); | ||
} | ||
}; | ||
|
||
return ( | ||
<div> | ||
<input | ||
type="text" | ||
placeholder="학번" | ||
value={studentId} | ||
onChange={(e) => setStudentId(e.target.value)} | ||
/> | ||
<input | ||
type="password" | ||
placeholder="비밀번호" | ||
value={password} | ||
onChange={(e) => setPassword(e.target.value)} | ||
/> | ||
<button onClick={handleLogin}>로그인</button> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { useEffect, useState } from "react"; | ||
import { useParams } from "react-router-dom"; | ||
import axiosInstance from "services/axiosInstance"; | ||
|
||
interface DetailPost { | ||
id: number; | ||
title: string; | ||
category: string; | ||
writer: string; | ||
content: string; | ||
like: number; | ||
isLiked: boolean; | ||
scrap: number; | ||
replyCount: number; | ||
createDate: string; | ||
replies: Reply[]; | ||
} | ||
|
||
interface Reply { | ||
id: number; | ||
writer: string; | ||
content: string; | ||
createDate: string; | ||
} | ||
|
||
export default function PostPage() { | ||
const { postId } = useParams<{ postId: string }>(); | ||
const [post, setPost] = useState<DetailPost | null>(null); | ||
|
||
useEffect(() => { | ||
const fetchPost = async () => { | ||
try { | ||
const response = await axiosInstance.get(`/api/posts/${postId}`); | ||
setPost(response.data.data); | ||
} catch (error) { | ||
console.error("게시글 불러오기 실패", error); | ||
} | ||
}; | ||
|
||
fetchPost(); | ||
}, [postId]); | ||
|
||
// 좋아요 버튼 클릭 핸들러 | ||
const handleLike = async () => { | ||
if (!post) return; | ||
|
||
try { | ||
await axiosInstance.put(`/api/posts/${postId}/like`); | ||
setPost((prevPost) => | ||
prevPost | ||
? { | ||
...prevPost, | ||
isLiked: !prevPost.isLiked, | ||
like: prevPost.isLiked ? prevPost.like - 1 : prevPost.like + 1, | ||
} | ||
: null | ||
); | ||
} catch (error: any) { | ||
if (error.response && error.response.status === 400) { | ||
alert("자신의 게시글에는 추천을 할 수 없습니다."); | ||
} else { | ||
console.error("좋아요 요청 실패:", error); | ||
alert("좋아요 요청 실패"); | ||
} | ||
} | ||
}; | ||
|
||
if (!post) { | ||
return <p>게시글을 불러오는 중입니다...</p>; | ||
} | ||
|
||
return ( | ||
<div> | ||
<h1>{post.title}</h1> | ||
<p>카테고리: {post.category}</p> | ||
<p>작성자: {post.writer}</p> | ||
<p>작성일: {new Date(post.createDate).toLocaleDateString()}</p> | ||
<p>{post.content}</p> | ||
<p> | ||
좋아요: {post.like} | 스크랩: {post.scrap} | 댓글: {post.replyCount} | ||
</p> | ||
|
||
<button onClick={handleLike}>{post.isLiked ? "♥" : "♡"}</button> | ||
|
||
<h2>댓글</h2> | ||
<ul> | ||
{post.replies.map((reply) => ( | ||
<li key={reply.id}> | ||
<p>작성자: {reply.writer}</p> | ||
<p>{reply.content}</p> | ||
<p>작성일: {new Date(reply.createDate).toLocaleDateString()}</p> | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Link, Outlet } from "react-router-dom"; | ||
|
||
export default function RootPage() { | ||
return ( | ||
<> | ||
<header> | ||
<h1>5주차 과제: axios, router, localStorage</h1> | ||
<Link to="/">메인 페이지</Link> | ||
<Link to="/login">로그인 페이지</Link> | ||
</header> | ||
<main> | ||
<Outlet /> | ||
</main> | ||
</> | ||
); | ||
} |
Oops, something went wrong.