diff --git a/api/api.tsx b/api/api.tsx index f0423b6ce..1afb9936f 100644 --- a/api/api.tsx +++ b/api/api.tsx @@ -21,7 +21,7 @@ export async function getProducts({ } } -export async function getDetailComments(productId: string) { +export async function getDetailComments(productId: number) { if (!productId) { throw new Error("Invalid product ID"); } @@ -52,10 +52,15 @@ export async function getProductComments({ throw new Error("Invalid product ID"); } + const params = { + limit: String(limit), + }; + try { // 올바르게 URLSearchParams 생성 // const query = new URLSearchParams().toString(); // 빈 쿼리 문자열을 생성 - const query = `limit=${limit}`; + // const query = `limit=${limit}`; + const query = new URLSearchParams(params).toString(); const response = await fetch( `https://panda-market-api.vercel.app/products/${productId}/comments?${query}` ); // api 호출 diff --git a/components/board/AllArticle.tsx b/components/board/AllArticle.tsx index b64586295..e6325da31 100644 --- a/components/board/AllArticle.tsx +++ b/components/board/AllArticle.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from "react"; import ArticleItem from "./ArticleItem"; import Search from "@/components/ui/Search"; import Dropdown from "@/components/ui/Dropdown"; +import Link from "next/link"; interface AllArticlesProps { initialArticles: Article[]; @@ -52,7 +53,7 @@ const AllArticle = ({ initialArticles }: AllArticlesProps) => {

게시글

- + 글쓰기
diff --git a/components/board/ArticleContent.tsx b/components/board/ArticleContent.tsx index 518164934..4e7f99f44 100644 --- a/components/board/ArticleContent.tsx +++ b/components/board/ArticleContent.tsx @@ -1,6 +1,7 @@ import { Article } from "@/types/Types"; import Kebob from "@/public/images/ic_kebab.svg"; import ArticleInfo from "./ArticleInfo"; +import Image from "next/image"; interface ArticleContentProps { article: Article; @@ -13,7 +14,7 @@ const ArticleContent = ({ article }: ArticleContentProps) => {

{article.title}

diff --git a/components/board/ArticleInfo.tsx b/components/board/ArticleInfo.tsx index a8095690d..0581ee1d2 100644 --- a/components/board/ArticleInfo.tsx +++ b/components/board/ArticleInfo.tsx @@ -1,6 +1,7 @@ import Profile from "@/public/images/profile.svg"; import { Article } from "@/types/Types"; import { formatDate } from "date-fns"; +import Image from "next/image"; interface ArticleInfoProps { article: Article; @@ -11,7 +12,7 @@ const ArticleInfo = ({ article }: ArticleInfoProps) => { return (
- + 프로필 {article.writer.nickname} {formetDate}
); diff --git a/components/board/ArticleItem.tsx b/components/board/ArticleItem.tsx index 4a12ae4d9..3d5ec8a58 100644 --- a/components/board/ArticleItem.tsx +++ b/components/board/ArticleItem.tsx @@ -17,10 +17,12 @@ const ArticleItem = ({ article }: ArticleItemProps) => {
{`${article.id}번
diff --git a/components/board/BestArticle.tsx b/components/board/BestArticle.tsx index cabd720f0..e21ac1554 100644 --- a/components/board/BestArticle.tsx +++ b/components/board/BestArticle.tsx @@ -12,7 +12,7 @@ const BestArticleCard = ({ article }: { article: Article }) => { <>
- + 베스트 게시글 Best
@@ -22,10 +22,11 @@ const BestArticleCard = ({ article }: { article: Article }) => { {article.image && (
{`${article.id}번
)} diff --git a/components/market/AllProduct.tsx b/components/market/AllProduct.tsx index aac27c26f..258978da0 100644 --- a/components/market/AllProduct.tsx +++ b/components/market/AllProduct.tsx @@ -4,13 +4,14 @@ import Link from "next/link"; import SearchIcon from "@/public/images/ic_search.svg"; // import Image from "next/image"; import Dropdown from "@/components/ui/Dropdown"; -import "@/styles/AllProduct.module.css"; +// import styles from "@/styles/AllProduct.module.css"; import { useEffect, useState } from "react"; import ItemCard from "@/components/market/ItemCard"; import { getProducts } from "@/api/api"; import Pagination from "@/components/ui/Pagination"; import { Product, ProductListResponse, ProductSortOption } from "@/types/Types"; import { useRouter } from "next/router"; +import Image from "next/image"; // 화면 사이즈 const getPageSize = (width: number) => { @@ -152,7 +153,7 @@ const AllProduct = () => { width={24} height={24} /> */} - + Search Icon { src={item.images[0]} alt={`${item.name} 상품 썸네일`} className="itemCardImg" + layout="responsive" + width={1} // 비율 유지 (가로 1) + height={1} // 비율 유지 (세로 1) />

{item.name}

{item.price.toLocaleString()}원

- + 좋아요 {/* Heart Icon { // DetailComment 컴포넌트 type DetailCommentProps = { - productId: string; + productId: number; }; interface ProductCommentList { @@ -126,9 +114,9 @@ function DetailComment({ productId }: DetailCommentProps) { setIsLoading(true); try { - const response: ProductCommentList = await getProductComments( - productId - ); + const response: ProductCommentList = await getProductComments({ + productId, + }); setComments(response.list); setError(null); } catch (error) { diff --git a/components/productdetail/DetailInput.tsx b/components/productdetail/DetailInput.tsx index c54292622..128d19424 100644 --- a/components/productdetail/DetailInput.tsx +++ b/components/productdetail/DetailInput.tsx @@ -1,10 +1,14 @@ -import React, { useState } from "react"; +import React, { ChangeEvent, useState } from "react"; import DetailComment from "./DetailComment"; -function DetailInput({ productId }) { +interface DetailInputProps { + productId: number; +} + +function DetailInput({ productId }: DetailInputProps) { const [inputValue, setInputValue] = useState(""); - const handleInputChange = (e) => { + const handleInputChange = (e: ChangeEvent) => { setInputValue(e.target.value); }; diff --git a/components/productdetail/ItemContent.tsx b/components/productdetail/ItemContent.tsx index 54f2ceb2c..03b8c6778 100644 --- a/components/productdetail/ItemContent.tsx +++ b/components/productdetail/ItemContent.tsx @@ -1,18 +1,9 @@ import React from "react"; import TagList from "./TagList"; import LikeButton from "./LikeButton"; -import { ReactComponent as Kebab } from "../../../images/ic_kebab.svg"; - -interface Product { - id: string; - name: string; - description: string; - price: number; - tags: string[]; - images: string[]; - isFavorite: boolean; - favoriteCount: number; -} +import Kebab from "@/public/images/ic_kebab.svg"; +import { Product } from "@/types/Types"; +import Image from "next/image"; interface ItemContentProps { product: Product; @@ -30,7 +21,13 @@ function ItemContent({ product }: ItemContentProps) {
{/* 더보기 버튼 */}
diff --git a/components/productdetail/LikeButton.tsx b/components/productdetail/LikeButton.tsx index 17187f24d..22bc6f007 100644 --- a/components/productdetail/LikeButton.tsx +++ b/components/productdetail/LikeButton.tsx @@ -1,8 +1,8 @@ import React, { useState } from "react"; -import { ReactComponent as Heart } from "../../../image/ic_heart.svg"; +import Heart from "@/public/images/ic_heart.svg"; interface LikeButtonProps { - productId: string; + productId: number; isFavorite: boolean; favoriteCount: number; } diff --git a/components/ui/DeleteButton.tsx b/components/ui/DeleteButton.tsx index 8693e93f1..19618dba3 100644 --- a/components/ui/DeleteButton.tsx +++ b/components/ui/DeleteButton.tsx @@ -1,5 +1,6 @@ import React from "react"; -import CloseIcon from "../public/images/ic_close.svg"; +import CloseIcon from "@/public/images/ic_close.svg"; +import Image from "next/image"; interface DeleteButtonProps { onClick: () => void; @@ -9,7 +10,7 @@ interface DeleteButtonProps { function DeleteButton({ onClick, label }: DeleteButtonProps) { return ( ); } diff --git a/components/ui/Dropdown.tsx b/components/ui/Dropdown.tsx index a3b2ff9e9..e618f54f6 100644 --- a/components/ui/Dropdown.tsx +++ b/components/ui/Dropdown.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; // import "./Dropdown.css"; -// import SortIcon from "../../public/images/ic_sort.svg"; +import SortIcon from "../../public/images/ic_sort.svg"; import Image from "next/image"; interface DropdownProps { @@ -18,12 +18,7 @@ function Dropdown({ onSortSelection, sortOptions }: DropdownProps) { return (
{isDropdownView && ( diff --git a/components/ui/ImageUpload.tsx b/components/ui/ImageUpload.tsx index 3d9e3ecc4..59ea4853d 100644 --- a/components/ui/ImageUpload.tsx +++ b/components/ui/ImageUpload.tsx @@ -1,6 +1,6 @@ import React, { useRef, useState } from "react"; // import { useEffect } from "react"; -import PlusIcon from "../public/images/ic_plus.svg"; +import PlusIcon from "@/public/images/ic_plus.svg"; import DeleteButton from "./DeleteButton"; import Image from "next/image"; @@ -60,7 +60,7 @@ const ImageUpload = ({ title }: ImageUploadProps) => { >

- + Plus
이미지 등록

diff --git a/components/ui/Pagination.tsx b/components/ui/Pagination.tsx index 762df54d4..cd305195e 100644 --- a/components/ui/Pagination.tsx +++ b/components/ui/Pagination.tsx @@ -2,7 +2,7 @@ import React from "react"; import Left from "@/public/images/left.svg"; import Right from "@/public/images/right.svg"; import "../../styles/Pagination.module.css"; -// import Image from "next/image"; +import Image from "next/image"; interface PaginationProps { totalPageNum: number; @@ -37,7 +37,7 @@ export default function Pagination({ disabled={activePageNum === 1} onClick={() => onPageChange(activePageNum - 1)} > - + Previous {/* Previous */} {pages.map((page) => ( @@ -56,7 +56,7 @@ export default function Pagination({ disabled={activePageNum === totalPageNum} onClick={() => onPageChange(activePageNum + 1)} > - + Next {/* Next */}
diff --git a/components/ui/Search.tsx b/components/ui/Search.tsx index 11e35f55c..1b8e35d75 100644 --- a/components/ui/Search.tsx +++ b/components/ui/Search.tsx @@ -1,6 +1,7 @@ import SearchIcon from "@/public/images/ic_search.svg"; import { useEffect, useState } from "react"; import { useRouter } from "next/router"; +import Image from "next/image"; interface SearchProps { onSearch: (keyword: string) => void; @@ -31,7 +32,7 @@ const Search = ({ return (
- + 검색 아이콘 { + const [product, setProduct] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); - const { productId } = useParams(); + const router = useRouter(); + const { id } = router.query; + + const productId = Number(id); useEffect(() => { async function fetchProduct() { @@ -24,12 +28,12 @@ export default function ProductDetail() { setIsLoading(true); try { - const data = await getDetailComments(productId); + const data: Product = await getDetailComments(productId); if (!data) { throw new Error("해당 상품의 데이터를 찾을 수 없습니다."); } setProduct(data); - } catch (error) { + } catch (error: any) { setError(error.message); } finally { setIsLoading(false); @@ -63,9 +67,17 @@ export default function ProductDetail() { {/* 목록으로 돌아가기 버튼 */} 목록으로 돌아가기 - + 돌아가기
); -} +}; + +export default ItemPage; diff --git a/pages/addboard/index.tsx b/pages/addboard/index.tsx new file mode 100644 index 000000000..18e93fdef --- /dev/null +++ b/pages/addboard/index.tsx @@ -0,0 +1,49 @@ +import ImageUpload from "@/components/ui/ImageUpload"; +import InputItem from "@/components/ui/InputItem"; +import { FormEvent, useState } from "react"; + +const AddBoard = () => { + const [title, setTitle] = useState(""); + const [content, setContent] = useState(""); + + // 이미지 제외 모든 input에 값이 입력 + const isSubmit = !title.trim() || !content.trim(); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + }; + + return ( +
+
+
+

게시글 쓰기

+ +
+ +
+ setTitle(e.target.value)} + placeholder="제목을 입력해 주세요" + /> + setContent(e.target.value)} + placeholder="내용을 입력해 주세요" + isTextArea + /> + +
+
+
+ ); +}; + +export default AddBoard; diff --git a/pages/board/index.tsx b/pages/board/index.tsx index 42b5d5ea7..276604b38 100644 --- a/pages/board/index.tsx +++ b/pages/board/index.tsx @@ -1,30 +1,65 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import BestArticle from "@/components/board/BestArticle"; import AllArticle from "@/components/board/AllArticle"; import { Article, ArticleList } from "@/types/Types"; -export async function getServerSideProps() { - const response = await fetch( - `https://panda-market-api.vercel.app/articles?orderBy=recent` - ); - const data: ArticleList = await response.json(); +// export async function getStaticProps() { +// const response = await fetch( +// `https://panda-market-api.vercel.app/articles?orderBy=recent` +// ); +// const data: ArticleList = await response.json(); - return { - props: { - initialArticles: data.list, - }, - }; -} +// return { +// props: { +// initialArticles: data.list, +// }, +// }; +// } -interface BoardsPageProps { - initialArticles: Article[]; -} +// interface BoardsPageProps { +// initialArticles: Article[]; +// } + +// export default function BoardsPage({ initialArticles }: BoardsPageProps) { +// return ( +//
+// +// +//
+// ); +// } + +export default function BoardsPage() { + const [articles, setArticles] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchArticles = async () => { + setLoading(true); // 로딩 시작 + try { + const response = await fetch( + `https://panda-market-api.vercel.app/articles?orderBy=recent` + ); + const data = await response.json(); + setArticles(data.list); + } catch (error) { + console.error("오류: ", error); + } finally { + setLoading(false); // 로딩 종료 + } + }; + + fetchArticles(); + }, []); + + if (loading) { + return
Loading...
; + } -export default function BoardsPage({ initialArticles }: BoardsPageProps) { return (
- +
); } diff --git a/types/Types.tsx b/types/Types.tsx index fa93e692c..4bf33494d 100644 --- a/types/Types.tsx +++ b/types/Types.tsx @@ -57,3 +57,20 @@ export interface ArticleList { } export type ArticleSortOption = "recent" | "like"; + +export interface Comment { + writer: { + image: string; + nickname: string; + id: number; + }; + updatedAt: Date; + createdAt: Date; + content: string; + id: number; +} + +export interface CommentList { + nextCursor: number; + list: Comment[]; +}