Skip to content

Commit

Permalink
feat: add BoardDetailArticle
Browse files Browse the repository at this point in the history
  • Loading branch information
myong39 committed Jul 21, 2024
1 parent 57f2e9f commit deb85c1
Show file tree
Hide file tree
Showing 11 changed files with 213 additions and 14 deletions.
100 changes: 100 additions & 0 deletions components/board/BoardDetailArticle.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
@mixin font-style($size, $weight, $lineHeight, $color) {
font-size: $size;
font-weight: $weight;
color: $color;
line-height: $lineHeight;
}

.freeboard-detail-main {
width: 1200px;
margin: 0 auto;
padding: 32px 0;
}

.board-detail-article-section {
display: flex;
flex-direction: column;
justify-content: center;
margin-bottom: 32px;
}

.title-wrapper {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;

h1 {
@include font-style(20px, 700, 32px, var(--gray800));
}

img {
width: 24px;
height: 24px;
}
}

.content-wrapper {
display: flex;
align-items: center;
}

.user-wrapper {
display: flex;
align-items: center;

img {
width: 40px;
height: 40px;
margin-right: 16px;
}

h3 {
@include font-style(14px, 500, 24px, var(--gray600));
margin-right: 8px;
}

span {
@include font-style(14px, 400, 24px, var(--gray400));
}
}

.favorite-wrapper {
display: flex;
align-items: center;
padding: 4px 12px;
border: 1px solid var(--gray200);
border-radius: 35px;
gap: 3px;

img {
width: 32px;
height: 32px;
}

span {
@include font-style(16px, 500, 26px, var(--gray500));
}
}

.vertical-divider {
border-left: 1px solid var(--gray200);
width: 0;
height: 40px;
margin: 0 32px;
}

.horizontal-divider {
border-top: 1px solid var(--gray200);
width: 100%;
height: 0px;
margin: 16px 0 24px;
}

.content {
@include font-style(18px, 400, 26px, var(--gray800));
}

.comment {
margin-top: 40px;
}
41 changes: 41 additions & 0 deletions components/board/BoardDetailArticle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Article } from "@/types/articleTypes";
import styles from "./BoardDetailArticle.module.scss";
import defalutProfleImg from "@/public/images/icons/ic_user.svg";
import kebabImg from "@/public/images/icons/ic_kebab.svg";
import favoriteImg from "@/public/images/icons/ic_heart.svg";
import { getFormatTime } from "@/utils/Utils";

export default function BoardDetailArticle({
article: {
title,
content,
writer: { nickname },
likeCount,
createdAt,
},
}: {
article: Article;
}) {
return (
<section className={styles["board-detail-article-section"]}>
<div className={styles["title-wrapper"]}>
<h1>{title}</h1>
<img src={kebabImg.src} />
</div>
<div className={styles["content-wrapper"]}>
<div className={styles["user-wrapper"]}>
<img src={defalutProfleImg.src} />
<h3>{nickname}</h3>
<span>{getFormatTime(createdAt, false)}</span>
</div>
<span className={styles["vertical-divider"]}></span>
<div className={styles["favorite-wrapper"]}>
<img src={favoriteImg.src} />
<span>{likeCount}</span>
</div>
</div>
<span className={styles["horizontal-divider"]}></span>
<span className={styles.content}>{content}</span>
</section>
);
}
8 changes: 8 additions & 0 deletions components/layout/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ export default function Button({
children,
disabled = false,
}: ButtonProps) {
if (!href) {
return (
<button className={styles.button} disabled={disabled}>
{children}
</button>
);
}

return (
<Link href={href}>
<button className={styles.button} disabled={disabled}>
Expand Down
5 changes: 3 additions & 2 deletions components/layout/Comment.tsx/CommentsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ export default function CommentsSection({
imgUrl: { src, alt },
content,
},
className,
}: CommentsSectionProp) {
const isCommentEmpty = !comments.length;

return (
<div className={styles["comments-section"]}>
<section className={`${styles["comments-section"]} ${className}`}>
{isCommentEmpty && (
<div className={styles["empty-comment"]}>
<img src={src} alt={alt} />
Expand All @@ -23,6 +24,6 @@ export default function CommentsSection({
{comments.map((comment) => (
<Comment key={comment.id} comment={comment} />
))}
</div>
</section>
);
}
1 change: 1 addition & 0 deletions components/layout/RegisterForm/RegisterForm.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

&.bottom-button {
gap: 0;
padding: 0;

.bottom-button {
margin-top: 16px;
Expand Down
5 changes: 3 additions & 2 deletions components/layout/RegisterForm/RegisterForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default function RegisterForm({
buttonText = "등록",
fields,
bottomButon = false,
href = "",
}: RegisterFormProps) {
const initializeFormValues = () => {
const initialValues: FormValues = {};
Expand Down Expand Up @@ -76,7 +77,7 @@ export default function RegisterForm({
<div className={styles["title-wrapper"]}>
<h1 className={styles.title}>{titleText}</h1>
{!bottomButon && (
<Button href="/boards" disabled={!isValid}>
<Button href={href} disabled={!isValid}>
{buttonText}
</Button>
)}
Expand All @@ -93,7 +94,7 @@ export default function RegisterForm({
))}
{bottomButon && (
<div className={styles["bottom-button"]}>
<Button href="/boards" disabled={!isValid}>
<Button href="" disabled={!isValid}>
{buttonText}
</Button>
</div>
Expand Down
8 changes: 6 additions & 2 deletions lib/articleApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ const instance = axios.create({
});

export const getArticle = async ({
articleId = "",
page = 1,
pageSize = 10,
orderBy = ORDER_TYPE_ENUM.RECENT,
keyword = "",
detail = false,
}: ArticleApiData = {}) => {
try {
const response = await instance.get(`/articles`, {
params: { page, pageSize, orderBy, keyword },
const params = detail ? undefined : { page, pageSize, orderBy, keyword };

const response = await instance.get(`/articles/${articleId}`, {
params,
});

if (response.status !== 200) {
Expand Down
6 changes: 5 additions & 1 deletion pages/addboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ export default function AddBoard() {

return (
<div>
<RegisterForm fields={formFields} titleText={"게시글 쓰기"} />
<RegisterForm
fields={formFields}
titleText={"게시글 쓰기"}
href={"/boards"}
/>
</div>
);
}
49 changes: 42 additions & 7 deletions pages/board/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,49 @@ import CommentsSection from "@/components/layout/Comment.tsx/CommentsSection";
import RegisterForm from "@/components/layout/RegisterForm/RegisterForm";
import GoBackToListButton from "@/components/layout/Comment.tsx/GoBackToListButton";
import { useEffect, useState } from "react";
import { ArticleCommentApiData, CommentObject } from "@/types/articleTypes";
import {
ArticleApiData,
ArticleCommentApiData,
CommentObject,
} from "@/types/articleTypes";
import { useRouter } from "next/router";
import { commentInfo, fields } from "@/components/board/BoardDetailConfig";
import BoardDetailArticle from "@/components/board/BoardDetailArticle";

export default function FreeBoardDetail() {
const content = "";
const router = useRouter();
const { id } = router.query;
const [comments, setComments] = useState<CommentObject>(commentInfo);
const formFields = fields;
const [article, setArticle] = useState({
id: 0,
title: "",
content: "",
image: null,
createdAt: "",
updatedAt: "",
isLiked: false,
likeCount: 0,
writer: {
id: 0,
nickname: "",
},
});

const fetchData = async ({ articleId }: ArticleCommentApiData) => {
const fetchDataArticle = async ({ articleId }: ArticleApiData) => {
try {
const result = await getArticle({
articleId,
detail: true,
});

setArticle(() => result);
} catch (error) {
console.log(error);
}
};

const fetchDataComment = async ({ articleId }: ArticleCommentApiData) => {
try {
const result = await getArticleComment({ articleId });

Expand All @@ -29,13 +60,17 @@ export default function FreeBoardDetail() {
};

useEffect(() => {
fetchData({ articleId: id });
}, []);
if (id) {
fetchDataArticle({ articleId: id });
fetchDataComment({ articleId: id });
}
}, [id]);

return (
<div className={styles.main}>
<div className={styles["freeboard-detail-main"]}>
<BoardDetailArticle article={article} />
<RegisterForm fields={formFields} bottomButon={true} />
<CommentsSection comments={comments} />
<CommentsSection comments={comments} className={styles["comment"]} />
<GoBackToListButton href="/boards" />
</div>
);
Expand Down
3 changes: 3 additions & 0 deletions types/articleTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ export interface Article {
}

export interface ArticleApiData {
articleId?: string | string[];
page?: number;
pageSize?: number;
orderBy?: ORDER_TYPE_ENUM.RECENT | ORDER_TYPE_ENUM.LIKE;
keyword?: string | string[] | undefined;
detail?: boolean;
}

export interface ArticleProps {
Expand Down Expand Up @@ -56,4 +58,5 @@ export interface CommentObject {

export interface CommentsSectionProp {
comments: CommentObject;
className?: string;
}
1 change: 1 addition & 0 deletions types/registerTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface RegisterFormProps {
titleText?: string;
buttonText?: string;
bottomButon?: boolean;
href?: string;
}

export interface InputFieldProps {
Expand Down

0 comments on commit deb85c1

Please sign in to comment.