-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: 머지 후 브랜치 삭제 github action 추가 * Initial commit from Create Next App * fix: 머지 후 브랜치 삭제 github action 수정 * env: workflows 폴더로 이동 * First commit Sprint Mission5 on React * First commit Sprint Mission5 on React (#78) * Sprint mission 6 commit. * Sprint Mission 6 Update 1 * update sprint mission 6 * Sprint mission 6 update commit. * delete .bak files * Update Comments * modify ItemComment * React 김주동 sprint7 (#97) * First commit Sprint Mission5 on React * Sprint mission 6 commit. * Sprint Mission 6 Update 1 * update sprint mission 6 * Sprint mission 6 update commit. * delete .bak files * Update Comments * modify ItemComment * refactoring to typescript * add LoginPage * First commit * REFACTOR: styled-components * Merge branch 'Next-김주동' of https://github.com/joodongkim/10-Sprint-Mission into Next-김주동 * change from React.FC<type> to ({}:type) * feat: replace interface to type * refactoring for nextjs * feat: sprint#10 first commit * review: sprint#10 --------- Co-authored-by: withyj <withyj@codeit.kr> Co-authored-by: hanseulhee <3021062@gmail.com>
- Loading branch information
1 parent
2afcec9
commit d0b2b5b
Showing
71 changed files
with
4,366 additions
and
7,577 deletions.
There are no files selected for viewing
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,50 @@ | ||
export async function getArticleDetail(articleId: number) { | ||
if (!articleId) { | ||
throw new Error("Invalid article ID"); | ||
} | ||
|
||
try { | ||
const response = await fetch( | ||
`https://panda-market-api.vercel.app/articles/${articleId}` | ||
); | ||
if (!response.ok) { | ||
throw new Error(`HTTP error: ${response.status}`); | ||
} | ||
const body = await response.json(); | ||
return body; | ||
} catch (error) { | ||
console.error("Failed to fetch article detail:", error); | ||
throw error; | ||
} | ||
} | ||
|
||
export async function getArticleComments({ | ||
articleId, | ||
limit = 10, | ||
}: { | ||
articleId: number; | ||
limit?: number; | ||
}) { | ||
if (!articleId) { | ||
throw new Error("Invalid article ID"); | ||
} | ||
|
||
const params = { | ||
limit: String(limit), | ||
}; | ||
|
||
try { | ||
const query = new URLSearchParams(params).toString(); | ||
const response = await fetch( | ||
`https://panda-market-api.vercel.app/articles/${articleId}/comments?${query}` | ||
); | ||
if (!response.ok) { | ||
throw new Error(`HTTP error: ${response.status}`); | ||
} | ||
const body = await response.json(); | ||
return body; | ||
} catch (error) { | ||
console.error("Failed to fetch article comments:", error); | ||
throw error; | ||
} | ||
} |
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,8 @@ | ||
GET https://panda-market-api.vercel.app/articles | ||
|
||
### | ||
|
||
GET https://panda-market-api.vercel.app/articles?orderBy=like&pageSize=10&page=1 | ||
|
||
### | ||
|
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,49 @@ | ||
import { ChangeEvent, useState } from "react"; | ||
import { TextArea } from "@/styles/CommonStyles"; | ||
import ArticlePageCommentThread from "@/components/board/ArticlePageCommentThread"; | ||
import { | ||
CommentInputSection, | ||
CommentSectionTitle, | ||
PostCommentButton, | ||
} from "@/styles/CommentStyles"; | ||
|
||
interface ArticleCommentSectionProps { | ||
articleId: number; | ||
} | ||
|
||
const ArticleCommentSection: React.FC<ArticleCommentSectionProps> = ({ | ||
articleId, | ||
}) => { | ||
const [comment, setComment] = useState(""); | ||
|
||
const handleInputChange = (e: ChangeEvent<HTMLTextAreaElement>) => { | ||
setComment(e.target.value); | ||
}; | ||
|
||
const handlePostComment = () => {}; | ||
|
||
return ( | ||
<> | ||
<CommentInputSection> | ||
<CommentSectionTitle>댓글 달기</CommentSectionTitle> | ||
|
||
<TextArea | ||
placeholder={"댓글을 입력해 주세요."} | ||
value={comment} | ||
onChange={handleInputChange} | ||
/> | ||
|
||
<PostCommentButton | ||
onClick={handlePostComment} | ||
disabled={!comment.trim()} | ||
> | ||
등록 | ||
</PostCommentButton> | ||
</CommentInputSection> | ||
|
||
<ArticlePageCommentThread articleId={articleId} /> | ||
</> | ||
); | ||
}; | ||
|
||
export default ArticleCommentSection; |
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,75 @@ | ||
import styled from "styled-components"; | ||
import { FlexRowCentered, LineDivider } from "@/styles/CommonStyles"; | ||
import { Article } from "@/types/articleTypes"; | ||
import SeeMoreIcon from "@/public/images/icons/ic_kebab.svg"; | ||
import ArticleInfo from "@/components/board/ArticleInfo"; | ||
import LikeCountDisplay from "@/components/ui/LikeCountDisplay"; | ||
|
||
const SectionContainer = styled.div` | ||
margin-bottom: 40px; | ||
@media ${({ theme }) => theme.mediaQuery.tablet} { | ||
margin-bottom: 64px; | ||
} | ||
`; | ||
|
||
const ArticleHeaderContainer = styled.div` | ||
position: relative; | ||
`; | ||
|
||
const SeeMoreButton = styled.button` | ||
position: absolute; | ||
top: 0; | ||
right: 0; | ||
`; | ||
|
||
const Title = styled.h1` | ||
font-size: 20px; | ||
font-weight: 700; | ||
margin-bottom: 16px; | ||
`; | ||
|
||
const ArticleInfoWrapper = styled(FlexRowCentered)` | ||
gap: 16px; | ||
`; | ||
|
||
const VerticalDivider = styled.div` | ||
border-left: 1px solid var(--gray-200); | ||
height: 24px; | ||
`; | ||
|
||
const Content = styled.p` | ||
font-size: 16px; | ||
`; | ||
|
||
interface ArticleContentSectionProps { | ||
article: Article; | ||
} | ||
|
||
const ArticleContentSection: React.FC<ArticleContentSectionProps> = ({ | ||
article, | ||
}) => { | ||
return ( | ||
<SectionContainer> | ||
<ArticleHeaderContainer> | ||
<Title>{article.title}</Title> | ||
|
||
<SeeMoreButton> | ||
<SeeMoreIcon /> | ||
</SeeMoreButton> | ||
|
||
<ArticleInfoWrapper> | ||
<ArticleInfo article={article} /> | ||
<VerticalDivider /> | ||
<LikeCountDisplay count={article.likeCount} iconWidth={24} gap={8} /> | ||
</ArticleInfoWrapper> | ||
</ArticleHeaderContainer> | ||
|
||
<LineDivider /> | ||
|
||
<Content>{article.content}</Content> | ||
</SectionContainer> | ||
); | ||
}; | ||
|
||
export default ArticleContentSection; |
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,29 @@ | ||
import styled from "styled-components"; | ||
import { FlexRowCentered } from "@/styles/CommonStyles"; | ||
import ProfilePlaceholder from "@/public/images/ui/ic_profile.svg"; | ||
import { Article } from "@/types/articleTypes"; | ||
import { formatDate } from "date-fns"; | ||
import { Timestamp } from "@/styles/BoardStyles"; | ||
|
||
const Container = styled(FlexRowCentered)` | ||
gap: 8px; | ||
color: var(--gray-600); | ||
font-size: 14px; | ||
`; | ||
|
||
interface ArticleInfoProps { | ||
article: Article; | ||
} | ||
|
||
const ArticleInfo: React.FC<ArticleInfoProps> = ({ article }) => { | ||
const dateString = formatDate(article.createdAt, "yyyy. MM. dd"); | ||
|
||
return ( | ||
<Container> | ||
<ProfilePlaceholder width={24} height={24} /> | ||
{article.writer.nickname} <Timestamp>{dateString}</Timestamp> | ||
</Container> | ||
); | ||
}; | ||
|
||
export default ArticleInfo; |
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,69 @@ | ||
import { useEffect, useState } from "react"; | ||
import styled from "styled-components"; | ||
import { Comment, CommentListResponse } from "@/types/commentTypes"; | ||
import EmptyState from "@/components/ui/EmptyState"; | ||
import CommentItem from "@/components/thread/CommentItem"; | ||
import { getArticleComments } from "@/api/articleApi"; | ||
|
||
const ThreadContainer = styled.div` | ||
margin-bottom: 40px; | ||
`; | ||
|
||
interface ArticlePageCommentThreadProps { | ||
articleId: number; | ||
} | ||
|
||
const ArticlePageCommentThread: React.FC<ArticlePageCommentThreadProps> = ({ | ||
articleId, | ||
}) => { | ||
const [comments, setComments] = useState<Comment[]>([]); | ||
const [isLoading, setIsLoading] = useState(false); | ||
const [error, setError] = useState<string | null>(null); | ||
|
||
useEffect(() => { | ||
if (!articleId) return; | ||
|
||
const fetchComments = async () => { | ||
setIsLoading(true); | ||
|
||
try { | ||
const response: CommentListResponse = await getArticleComments({ | ||
articleId, | ||
}); | ||
setComments(response.list); | ||
setError(null); | ||
} catch (error) { | ||
console.error("Error fetching comments:", error); | ||
setError("게시글의 댓글을 불러오지 못했어요."); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
}; | ||
|
||
fetchComments(); | ||
}, [articleId]); | ||
|
||
if (isLoading) { | ||
return <div>게시글 댓글 로딩중...</div>; | ||
} | ||
|
||
if (error) { | ||
return <div>오류: {error}</div>; | ||
} | ||
|
||
if (comments && !comments.length) { | ||
return ( | ||
<EmptyState text={`아직 댓글이 없어요,\n지금 댓글을 달아 보세요!`} /> | ||
); | ||
} else { | ||
return ( | ||
<ThreadContainer> | ||
{comments.map((item) => ( | ||
<CommentItem item={item} key={`comment-${item.id}`} /> | ||
))} | ||
</ThreadContainer> | ||
); | ||
} | ||
}; | ||
|
||
export default ArticlePageCommentThread; |
Oops, something went wrong.