From 0b8d0c6fcf08a70decfd462b944d2b8f136033e8 Mon Sep 17 00:00:00 2001 From: ddol9 Date: Sat, 20 Jul 2024 20:26:02 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EB=AF=B8=EC=85=9810=20=ED=94=BC?= =?UTF-8?q?=EB=93=9C=EB=B0=B1=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 1 + .gitignore | 2 +- app/addboard/page.tsx | 16 ++--- app/boards/[id]/page.tsx | 91 +++++++++++++--------------- components/Board/AllArticleCard.tsx | 60 +++++++++--------- components/Board/AllArticleList.tsx | 20 +++--- components/Board/BestArticleCard.tsx | 6 +- components/Board/BestArticleList.tsx | 28 ++++----- components/Button.module.css | 3 +- components/Button.tsx | 18 +++++- components/FileInput.tsx | 33 +++++----- styles/globals.css | 1 + 12 files changed, 141 insertions(+), 138 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 00000000..fcac187d --- /dev/null +++ b/.env @@ -0,0 +1 @@ +NEXT_PUBLIC_API_BASE_URL=https://panda-market-api.vercel.app \ No newline at end of file diff --git a/.gitignore b/.gitignore index 336ef6ec..b20ae2b3 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,4 @@ yarn-error.log* next-env.d.ts node_modules -.env + diff --git a/app/addboard/page.tsx b/app/addboard/page.tsx index 3514e205..1ff34907 100644 --- a/app/addboard/page.tsx +++ b/app/addboard/page.tsx @@ -1,11 +1,11 @@ "use client"; -import { ChangeEvent, FormEvent, useEffect, useState } from "react"; +import { ChangeEvent, FormEvent, useEffect, useMemo, useState } from "react"; import FileInput from "@/components/FileInput"; import { AddArticleForm } from "@/types/form"; import Button from "@/components/Button"; -const AddBoard: React.FC = () => { +const AddBoard = () => { const [values, setValues] = useState({ title: "", body: "", @@ -31,12 +31,10 @@ const AddBoard: React.FC = () => { console.log(values); }; - const [isFormValid, setIsFormValid] = useState(false); - - useEffect(() => { + const isFormValid = useMemo(() => { const { title, body } = values; - const isValid = !!title && !!body; - setIsFormValid(isValid); + + return !!title && !!body; }, [values]); return ( @@ -65,7 +63,9 @@ const AddBoard: React.FC = () => { value={values.body} onChange={handleInputChange} placeholder='내용을 입력해주세요' - className={`w-full py-4 px-6 rounded-xl bg-gray-100 h-[282px] text-gray-400 text-base font-normal resize-none ${values.body ? 'text-black' : 'text-gray-400'}`} + className={`w-full py-4 px-6 rounded-xl bg-gray-100 h-[282px] text-gray-400 text-base font-normal resize-none ${ + values.body ? "text-black" : "text-gray-400" + }`} />
diff --git a/app/boards/[id]/page.tsx b/app/boards/[id]/page.tsx index ca63caa6..71907866 100644 --- a/app/boards/[id]/page.tsx +++ b/app/boards/[id]/page.tsx @@ -1,7 +1,7 @@ "use client"; import Image from "next/image"; -import { useParams, useRouter } from "next/navigation"; +import { useParams } from "next/navigation"; import { useEffect, useState } from "react"; import { fetchArticleById, fetchArticleComments } from "@/api/articles"; import { Article, Comment } from "@/types/article"; @@ -11,10 +11,10 @@ import BackIcon from "@/assets/images/icons/ic_back.svg"; import EmptyComments from "@/assets/images/ui/empty-reply.svg"; import formatTimeDiff from "@/utils/formatTimeDiff"; import Button from "@/components/Button"; +import Link from "next/link"; export default function ArticleDetail() { const { id } = useParams(); - const router = useRouter(); const [article, setArticle] = useState
(null); const [loading, setLoading] = useState(true); const [comments, setComments] = useState([]); @@ -56,10 +56,6 @@ export default function ArticleDetail() { setNewComment(""); }; - const handleBackClick = () => { - router.push("/boards"); - }; - if (loading) { return

Loading...

; } @@ -67,7 +63,7 @@ export default function ArticleDetail() { if (!article) return null; return ( -
+

{article.title}

@@ -124,27 +120,29 @@ export default function ArticleDetail() {
{comments.length > 0 ? ( comments.map((comment) => ( -
-
- {comment.content} -
-
-
- profile +
+
+
+ {comment.content}
-
- - {comment.writer.nickname} - - - {formatTimeDiff(comment.createdAt)} - +
+
+ profile +
+
+ + {comment.writer.nickname} + + + {formatTimeDiff(comment.createdAt)} + +
@@ -157,31 +155,26 @@ export default function ArticleDetail() { width={150} height={150} /> -

- 아직 댓글이 없어요, -
- 지금 댓글을 달아보세요! -

+
+

아직 댓글이 없어요,

+

지금 댓글을 달아보세요!

+
)}
-
diff --git a/components/Board/AllArticleCard.tsx b/components/Board/AllArticleCard.tsx index 0502fe42..6a21f472 100644 --- a/components/Board/AllArticleCard.tsx +++ b/components/Board/AllArticleCard.tsx @@ -16,38 +16,40 @@ const AllArticleCard: React.FC
= ({ return ( -
-
-

{title}

-
-
- {image && ( -
-
- article-image +
+
+
+

{title}

+
+
+ {image && ( +
+
+ article-image +
-
- )} -
-
-
-
- profile - {writer.nickname} - - {new Date(createdAt).toLocaleDateString()} - + )} +
-
- heart - {likeCount} +
+
+ profile + {writer.nickname} + + {new Date(createdAt).toLocaleDateString()} + +
+
+ heart + {likeCount} +
diff --git a/components/Board/AllArticleList.tsx b/components/Board/AllArticleList.tsx index d8998a64..0f7ac6e1 100644 --- a/components/Board/AllArticleList.tsx +++ b/components/Board/AllArticleList.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect, useRef, useCallback } from "react"; +import { useState, useEffect, useRef, useCallback, useMemo } from "react"; import { Article } from "../../types/article"; import { fetchArticles } from "@/api/articles"; import searchIcon from "@/assets/images/icons/ic_search.svg"; @@ -17,7 +17,6 @@ const sortOptions = [ export default function AllArticleList() { const [articles, setArticles] = useState([]); - const [filteredArticles, setFilteredArticles] = useState([]); const [sortType, setSortType] = useState("recent"); const [searchTerm, setSearchTerm] = useState(""); const [page, setPage] = useState(1); @@ -45,16 +44,13 @@ export default function AllArticleList() { } }; - const filterArticlesByTitle = useCallback(() => { - const filtered = articles.filter((article) => - article.title.toLowerCase().includes(searchTerm.toLowerCase()), - ); - setFilteredArticles(filtered); - }, [articles, searchTerm]); - - useEffect(() => { - filterArticlesByTitle(); - }, [filterArticlesByTitle]); + const filteredArticles = useMemo( + () => + articles.filter((article) => + article.title.toLowerCase().includes(searchTerm.toLowerCase()), + ), + [articles, searchTerm], + ); const debouncedSearch = useCallback( debounce((term: string) => { diff --git a/components/Board/BestArticleCard.tsx b/components/Board/BestArticleCard.tsx index 85dfc622..1f01c8eb 100644 --- a/components/Board/BestArticleCard.tsx +++ b/components/Board/BestArticleCard.tsx @@ -18,12 +18,12 @@ const BestArticleCard: React.FC
= ({ href={`/boards/${id}`} className='lg:h-[169px] h-[167px] rounded-lg overflow-hidden bg-gray-50 flex flex-col justify-between px-6 pb-4' > -
+
best badge
-
-
+
+
{title}
{image && ( diff --git a/components/Board/BestArticleList.tsx b/components/Board/BestArticleList.tsx index 1d1752b4..660242c3 100644 --- a/components/Board/BestArticleList.tsx +++ b/components/Board/BestArticleList.tsx @@ -1,15 +1,11 @@ "use client"; - import { useState, useEffect } from "react"; import { Article } from "../../types/article"; import { fetchArticles } from "@/api/articles"; import BestArticleCard from "./BestArticleCard"; -import useResize from "@/hooks/useResize"; export default function BestArticleList() { const [posts, setPosts] = useState([]); - const windowWidth = useResize(); - const [postNum, setPostNum] = useState(3); useEffect(() => { fetchBestPosts(); @@ -24,22 +20,20 @@ export default function BestArticleList() { } }; - useEffect(() => { - if (windowWidth <= 640) { - setPostNum(1); - } else if (windowWidth <= 1024) { - setPostNum(2); - } else { - setPostNum(3); - } - }, [windowWidth]); - return (

베스트 게시글

-
- {posts.slice(0, postNum).map((article) => ( - +
+ {posts.map((article, index) => ( +
+ +
))}
diff --git a/components/Button.module.css b/components/Button.module.css index 712653a7..0398c435 100644 --- a/components/Button.module.css +++ b/components/Button.module.css @@ -10,7 +10,8 @@ cursor: pointer; } -.button:disabled { +.button:disabled, +.button:disabled:hover { background-color: #9ca3af; cursor: not-allowed; } diff --git a/components/Button.tsx b/components/Button.tsx index 392d95f3..8568680e 100644 --- a/components/Button.tsx +++ b/components/Button.tsx @@ -8,6 +8,10 @@ interface ButtonProps extends ComponentPropsWithoutRef<"button"> { size?: "large" | "small"; width?: string; icon?: React.ReactNode; + borderRadius?: string; + fontSize?: string; + fontWeight?: string; + padding?: string; } const Button: React.FC = ({ @@ -18,16 +22,28 @@ const Button: React.FC = ({ onClick, disabled = false, icon, + borderRadius, + fontSize, + fontWeight, + padding, ...props }) => { const buttonClasses = [styles.button, styles[color], styles[size]].join(" "); + const customStyles = { + width, + borderRadius, + fontSize, + fontWeight, + padding, + }; + return (
)} diff --git a/styles/globals.css b/styles/globals.css index b57bec59..92189567 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -4,6 +4,7 @@ body { @apply font-sans; + -webkit-font-smoothing: antialiased; } * {