Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[이준희] sprint10 #304

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions components/AllArticles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,27 @@ export default function AllArticles() {
const [isDropdown, setIsDropdown] = useState<boolean>(false);
const [keyword, setKeyword] = useState<string>("");

const fetchArticles = async (reset: boolean = false) => {
const fetchArticles = async (page: number = 1) => {
try {
if (isFetching) return;
setIsFetching(true);

const currentPage = reset ? 1 : page;

const data = await getArticles({
orderBy: sortOrder,
page: currentPage,
page: page,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

속성명과 값이 같은 경우 아래처럼 사용할 수 있습니다.

{
        orderBy: sortOrder,
        page,
        pageSize: 10,
        keyword
}

pageSize: 10,
keyword: keyword,
});

if (reset) {
if (page === 1) {
setArticles(data.list);
} else {
if (currentPage === page) {
const updatedArticles = [...articles, ...data.list];
setArticles(updatedArticles);
}
const updatedArticles = [...articles, ...data.list];
setArticles(updatedArticles);
Comment on lines +33 to +37
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 분기는 삼항연산자로도 표현 가능하긴 합니다. 취향에 맞게 사용하시면 될 것 같아요.

}

if (data.list.length < 10) {
setHasMore(false);
} else {
setHasMore(true);
}

setIsFetching(false);
Expand All @@ -54,12 +48,12 @@ export default function AllArticles() {
};

useEffect(() => {
fetchArticles(true);
fetchArticles(1);
}, [sortOrder]);

useEffect(() => {
if (page === 1) return;
fetchArticles();
fetchArticles(page);
}, [page]);

useEffect(() => {
Expand Down Expand Up @@ -101,7 +95,8 @@ export default function AllArticles() {

const handleSearchSubmit = () => {
setPage(1);
fetchArticles(true);
setHasMore(true);
fetchArticles(1);
};

const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
Expand All @@ -114,7 +109,9 @@ export default function AllArticles() {
<div className={styles.article_container}>
<div className={styles.article_top}>
<h2 className={styles.h2}>게시글</h2>
<button className={styles.button}>글쓰기</button>
<Link href={"/addboard"}>
<button className={styles.button}>글쓰기</button>
</Link>
</div>

<div className={styles.article_controls}>
Expand Down Expand Up @@ -148,12 +145,11 @@ export default function AllArticles() {
{articles.map((article) => (
<Link
key={article.id}
href={`/articles/${article.id}`}
href={`/boards/${article.id}`}
className={styles.article_link}
passHref
>
<div>
{" "}
<div className={styles.article_content}>
<div className={styles.article_title}>{article.title}</div>
<div className={styles.image_container}>
Expand Down
132 changes: 132 additions & 0 deletions components/AllItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { useEffect, useState } from "react";
import ItemCard from "@/components/ItemCard";
import { getProducts } from "@/lib/api";
import Pagination from "@/components/Pagination";
import { Product } from "@/types/commontypes";
import styles from "@/styles/items.module.css";
import searchIcon from "@/public/svgs/ic_search.svg";
import Image from "next/image";

const getPageSize = () => {
if (typeof window === "undefined") return 10;
const width = window.innerWidth;
if (width < 768) {
return 4;
} else if (width < 1280) {
return 6;
} else {
return 10;
}
};
Comment on lines +10 to +20
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 함수 다른 컴포넌트에서도 사용했던 것 같은데, 유틸 함수로 만들어서 꺼내쓰게 바꿔보시면 어떨까요?


function AllItems() {
const [orderBy, setOrderBy] = useState<string>("recent");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useState의 타입에 'recent' | 'like' 이런식으로 타입을 특정 값으로 강제하는 방법도 추천드립니다.

const [page, setPage] = useState<number>(1);
const [pageSize, setPageSize] = useState<number>(getPageSize());
const [items, setItems] = useState<Product[]>([]);
const [isDropdown, setIsDropdown] = useState<boolean>(false);
const [totalPageNum, setTotalPageNum] = useState<number>(0);

useEffect(() => {
const handleFixSize = () => {
setPageSize(getPageSize());
};

const fetchProducts = async ({
orderBy,
page,
pageSize,
}: {
orderBy: string;
page: number;
pageSize: number;
}) => {
const products = await getProducts({ orderBy, page, pageSize });
setItems(products.list);
setTotalPageNum(Math.ceil(products.totalCount / pageSize));
};

window.addEventListener("resize", handleFixSize);
fetchProducts({ orderBy, page, pageSize });

return () => {
window.removeEventListener("resize", handleFixSize);
};
}, [orderBy, page, pageSize]);

const handleNextPage = (newPage: number) => {
setPage(newPage);
};

const toggleDropdown = () => {
setIsDropdown(!isDropdown);
};

const handleOrderByChange = (newOrderBy: string) => {
setOrderBy(newOrderBy);
setPage(1);
setIsDropdown(false);
};

return (
<div className={styles.all_item_container}>
<div className={styles.all_item_content}>
<div className={styles.all_item_header}>
<div className={styles.all_item_header_front}>
<div className={styles.all_item_title}>전체 상품</div>
<div className={styles.all_item_search_container}>
<Image
className={styles.all_item_search_icon}
src={searchIcon}
alt="돋보기 아이콘"
width={24}
height={24}
/>
<input
className={styles.all_item_search_input}
placeholder="검색할 상품을 입력해주세요"
/>
</div>
</div>
<div className={styles.all_item_header_end}>
<div className={styles.all_item_sort}>
<a href="./additem">
<button className={styles.all_item_register_button}>
상품 등록하기
</button>
</a>
<button
className={styles.all_item_sort_button}
onClick={toggleDropdown}
>
{orderBy === "recent" ? "최신순" : "좋아요순"} ▼
</button>
{isDropdown && (
<div className={styles.all_item_sort_options}>
<div onClick={() => handleOrderByChange("recent")}>
최신순
</div>
<div onClick={() => handleOrderByChange("favorite")}>
좋아요순
</div>
</div>
)}
</div>
</div>
</div>
<div className={styles.all_item_card_container}>
{items?.map((item) => (
<ItemCard item={item} key={`all_item_${item.id}`} />
))}
</div>
<Pagination
currentPage={page}
totalPageNum={totalPageNum}
onPageChange={handleNextPage}
/>
</div>
</div>
);
}

export default AllItems;
2 changes: 1 addition & 1 deletion components/BestArticles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default function BestArticles() {
{articles.map((article) => (
<Link
key={article.id}
href={`/articles/${article.id}`}
href={`/boards/${article.id}`}
className={styles.best_article_link}
>
<div className={styles.container}>
Expand Down
74 changes: 74 additions & 0 deletions components/BestItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useEffect, useState } from "react";
import { getProducts } from "@/lib/api";
import { Product, GetProductsResponse } from "@/types/commontypes";
import styles from "@/styles/items.module.css";
import BestItemCard from "./BestItemCard";

const getPageSize = () => {
if (typeof window === "undefined") return 4;
const width = window.innerWidth;
if (width < 768) {
return 1;
} else if (width < 1280) {
return 2;
} else {
return 4;
}
};

const debounce = (func: (...args: any[]) => void, delay: number) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debounce 같은 함수도 자주 사용되기 때문에 유틸로 관리해주셔도 좋을 것 같습니다.

let timeoutId: NodeJS.Timeout;
return (...args: any[]) => {
if (timeoutId) clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func(...args);
}, delay);
};
};

function BestItem() {
const [items, setItems] = useState<Product[]>([]);
const [pageSize, setPageSize] = useState<number>(getPageSize);

const fetchProducts = async ({
orderBy,
pageSize,
}: {
orderBy: string;
pageSize: number;
}) => {
const products: GetProductsResponse = await getProducts({
orderBy,
pageSize,
});
setItems(products.list);
};

useEffect(() => {
const handleFixSize = debounce(() => {
setPageSize(getPageSize());
}, 300); // 300ms 딜레이로 debounce 적용

window.addEventListener("resize", handleFixSize);
fetchProducts({ orderBy: "favorite", pageSize });

return () => {
window.removeEventListener("resize", handleFixSize);
};
}, [pageSize]);

return (
<div className={styles.best_item_container}>
<div className={styles.best_item_content}>
<div className={styles.best_item_title}>베스트 상품</div>
<div className={styles.best_item_card_container}>
{items?.map((item) => (
<BestItemCard item={item} key={`best-item-${item.id}`} />
))}
</div>
</div>
</div>
);
}

export default BestItem;
28 changes: 28 additions & 0 deletions components/BestItemCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Link from "next/link";
import { AllItemCardProps } from "@/types/commontypes";
import styles from "@/styles/bestitem.module.css";
import heartIcon from "@/public/svgs/ic_heart (1).svg";
import Image from "next/image";

function BestItemCard({ item }: AllItemCardProps) {
return (
<div className={styles.item_card}>
<img
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기는 next/image를 사용하지 않으신 이유가 있을까요?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "**",
      },
    ],
  },
};

src={item.images[0]}
alt={item.name}
className={styles.item_card_img}
/>

<div className={styles.item_description}>
<div className={styles.item_name}>{item.name}</div>
<div className={styles.item_price}>{item.price.toLocaleString()}원</div>
<div className={styles.item_favorite_count}>
<Image src={heartIcon} alt="하트 아이콘" width={16} height={16} />
{item.favoriteCount}
</div>
</div>
</div>
);
}

export default BestItemCard;
Loading