Skip to content

Commit

Permalink
Merge pull request #736 from Bersk3r/Next.js-이종욱-sprint12
Browse files Browse the repository at this point in the history
[이종욱] Sprint12
  • Loading branch information
jyh0521 authored Jul 22, 2024
2 parents f7f5756 + 16bb9d4 commit 6df57fc
Show file tree
Hide file tree
Showing 23 changed files with 785 additions and 78 deletions.
25 changes: 25 additions & 0 deletions api/getProduct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import axios from "./axios";

interface GetProductsQueries {
page?: number;
pageSize?: number;
orderBy?: "recent" | "favorite";
keyword?: string;
}

export const getProducts = async ({
page = 1,
pageSize = 3,
orderBy = "recent",
keyword,
}: GetProductsQueries) => {
try {
const response = await axios.get("/products", {
params: { page, pageSize, orderBy, keyword },
});
return response.data;
} catch (error) {
console.error(`Failed to fetch Data: ${error}`);
throw error;
}
};
62 changes: 0 additions & 62 deletions api/itemApi.js

This file was deleted.

93 changes: 93 additions & 0 deletions components/ItemPage/AllItems.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
@import "/styles/index.scss";

.title {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
padding-block: 24px 12px;

.content {
@include font-base(get_color(black), 700, 20px, 28px);
max-width: 600px;
flex-grow: 3;
}

.search {
height: 42px;
display: flex;
align-items: center;
gap: 3px;
background-color: get_color(gray_100);
border-radius: 12px;
padding-block: 9px;
padding-inline: 20px 16px;

.search_image {
width: 16px;
height: 16px;
background-size: 16px;
background-repeat: no-repeat;
background-image: url("../../src/assets/images/icons/ic_search.svg");
}

.search_input {
@include font-base(get_color(black), 400, 16px, 24px);
background-color: get_color(gray_100);
border: none;
}
}

.add_item {
@include font-base(get_color(white), 600, 16px, 19.09px);
text-align: center;
width: 133px;
height: 42px;
border-radius: 8px;
padding: 12px 10px;
background-color: get_color(blue_primary);
text-decoration: none;
flex-shrink: 0;
}
.select_box_area {
position: relative;
max-width: 64px;
background-color: get_color(white);
padding: 3px;
border-radius: 3px;
right: 0;
}
}

@media screen and (min-width: 768px) and (max-width: 1199px) {
.search {
width: 242px;
}
}

@media screen and (min-width: 375px) and (max-width: 767px) {
.title {
display: grid;
grid-template: repeat(2, auto) / 300px auto;

.content {
width: fit-content;
grid-column: 1 / span 1;
grid-row: 1 / span 1;
}

.search {
grid-column: 1 / span 1;
grid-row: 2 / span 1;
}
.add_item {
grid-column: 2 / span 1;
grid-row: 1 / span 1;
}
}

.select_box_area {
grid-column: 2 / span 1;
grid-row: 2 / span 1;
}
}
139 changes: 139 additions & 0 deletions components/ItemPage/AllItems.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { useEffect, useState } from "react";
import { sortItemsByOrder } from "../../lib/sort";
import { AllProducts } from "./Products";
import styles from "./AllItems.module.scss";
import SelectMenu from "./SelectMenu";
import Link from "next/link";
import { ProductSortOption } from "../../types/productTypes";
import useWindowSize from "../../src/hooks/useWindowSize";
import { FieldValues, SubmitHandler, useForm } from "react-hook-form";
import { getProducts } from "../../api/getProduct";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";

function AllItems() {
const [order, setOrder] = useState<ProductSortOption>("recent");
const queryClient = useQueryClient();
const windowWidth = useWindowSize();
const { register, watch, handleSubmit, setValue, getValues } = useForm();
const [pageSize, setPageSize] = useState<number>(10);
const [keyword, setKeyword] = useState<string>("");

const {
data: itemsData,
isPending,
isError,
} = useQuery({
queryKey: ["allitems"],
queryFn: () => getProducts({ pageSize, orderBy: order }),
retry: 0,
});

const items = itemsData?.list ?? [];

const addKeywordMutation = useMutation({
mutationFn: (keyword: string) =>
getProducts({ pageSize, orderBy: order, keyword }),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["allitems"],
});
},
});

const addOrderMutation = useMutation({
mutationFn: (order: ProductSortOption) =>
getProducts({ pageSize, orderBy: order, keyword }),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["allitems"],
});
},
});

const handleKeyword = (keyword: string) => {
addKeywordMutation.mutate(keyword);
};

const handleOrder = (order: ProductSortOption) => {
addKeywordMutation.mutate(order);
setOrder(order);
};

const sortedItems = sortItemsByOrder(items, order);

const onSubmit: SubmitHandler<FieldValues> = async (data) => {
if (data.keyword) {
setKeyword(data.keyword);
}
handleKeyword(keyword);
};

useEffect(() => {
if (windowWidth < 768) {
setPageSize(4);
} else if (windowWidth < 1199) {
setPageSize(6);
} else {
setPageSize(10);
}
}, [windowWidth]);

// useEffect(() => {
// async ({
// pageSize,
// order,
// keyword,
// }: {
// pageSize: number;
// order: ProductSortOption;
// keyword: string;
// }) => {
// let result = await getProducts({ pageSize, orderBy: order, keyword });
// const { list } = result;
// setAllItems(list);
// };
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [pageSize, order, keyword]);

return (
<>
<div className={styles.container}>
<div className={styles.title}>
<h2 className={styles.content}>
{windowWidth < 1199 ? "판매 중인 상품" : "전체 상품"}
</h2>
<div className={styles.search}>
<span className={styles.search_image} />
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register("keyword")}
type="search"
placeholder="검색할 상품을 입력해주세요"
className={styles.search_input}
/>
</form>
</div>
<Link href="/additem" className={styles.add_item}>
상품 등록하기
</Link>
<span className={styles.select_box_area}>
<SelectMenu order={order} setOrder={handleOrder} />
</span>
</div>
<div>
<AllProducts items={sortedItems} counts={pageSize} />
</div>
{/* {isError && <span>{loadingError.message}</span>} */}
</div>
{/* <Paging
itemsCount={1}
totalPageCount={totalPage}
displayCount={pageSize}
order={order}
onClick={handleLoad}
/> */}
</>
);
}

export default AllItems;
10 changes: 10 additions & 0 deletions components/ItemPage/BestItems.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@import "/styles/index.scss";

.container {
.title {
padding-block: 24px 12px;
.content {
@include font-base(get_color(gray_800), 700, 20px, 28px);
}
}
}
49 changes: 49 additions & 0 deletions components/ItemPage/BestItems.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useEffect, useState } from "react";
import { BestProducts } from "./Products";
import { sortItemsByOrder } from "../../lib/sort";
import styles from "./BestItems.module.scss";
import useWindowSize from "../../src/hooks/useWindowSize";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { getProducts } from "../../api/getProduct";

function BestItems() {
const windowWidth = useWindowSize();
const [pageSize, setPageSize] = useState(4);

const {
data: itemsData,
isPending,
isError,
} = useQuery({
queryKey: ["bestitems"],
queryFn: () => getProducts({ pageSize, orderBy: "favorite" }),
retry: 0,
});

// const items = itemsData?.results ?? [];
const items = itemsData?.list ?? [];

const sortedItems = sortItemsByOrder(items, "favorite");

useEffect(() => {
if (windowWidth < 768) {
setPageSize(1);
} else if (windowWidth < 1199) {
setPageSize(2);
} else {
setPageSize(4);
}
}, [windowWidth]);

return (
<div className={styles.container}>
<div className={styles.title}>
<h2 className={styles.content}>베스트 상품</h2>
</div>
<BestProducts items={sortedItems} counts={pageSize} />
{/* {loadingError?.message && <span>{loadingError.message}</span>} */}
</div>
);
}

export default BestItems;
Loading

0 comments on commit 6df57fc

Please sign in to comment.