Skip to content

Commit

Permalink
feat: 자유게시판 베스트 게시글 구현
Browse files Browse the repository at this point in the history
- 미디어 쿼리 적용
- api 적용
- CSS 관련 일부 적용
  • Loading branch information
jsh1147 committed Oct 26, 2024
1 parent 7dff34c commit f037188
Show file tree
Hide file tree
Showing 13 changed files with 238 additions and 12 deletions.
9 changes: 9 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
remotePatterns: [
{
protocol: "https",
hostname: "sprint-fe-project.s3.ap-northeast-2.amazonaws.com",
pathname: "/Sprint_Mission/user/**",
},
],
},
};

module.exports = nextConfig;
3 changes: 3 additions & 0 deletions public/icons/heart_inactive.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/apis/apis.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { StringObj, getArticlesRes, GetArticlesParams } from "./apis.type";
import { StringObj, GetArticlesRes, GetArticlesParams } from "./apis.type";

const BASE_URL = "https://panda-market-api.vercel.app/";

Expand All @@ -17,7 +17,7 @@ export async function getArticles({
pageSize = 10,
orderBy = "recent",
keyword,
}: GetArticlesParams): Promise<getArticlesRes> {
}: GetArticlesParams): Promise<GetArticlesRes> {
const url = new URL(PATH.ARTICLE, BASE_URL);
const paramObj: StringObj = {
page: String(page),
Expand Down
13 changes: 6 additions & 7 deletions src/apis/apis.type.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
export type StringObj = Record<string, string>;

export type OrderByType = "recent" | "favorite";

interface GetListParams {
interface GetListParams<ItemOrder> {
page: number;
pageSize: number;
orderBy: OrderByType;
orderBy: ItemOrder;
keyword?: string;
}
interface GetListRes<ItemProps> {
totalCount: number;
list: ItemProps[];
}

interface ArticleProps {
export type ArticleOrderType = "recent" | "like";
export interface ArticleProps {
id: number;
title: string;
content: string;
Expand All @@ -26,5 +25,5 @@ interface ArticleProps {
nickname: string;
};
}
export type GetArticlesParams = GetListParams;
export type getArticlesRes = GetListRes<ArticleProps>;
export type GetArticlesParams = GetListParams<ArticleOrderType>;
export type GetArticlesRes = GetListRes<ArticleProps>;
34 changes: 34 additions & 0 deletions src/components/pages/boards/BestItems.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.section {
width: 1200px;
}
@media (max-width: 1199px) {
.section {
width: 100%;
}
}

.head {
margin-bottom: 16px;
}

.title {
font-size: var(--size-xl);
font-weight: bold;
}

.body {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
@media (max-width: 1199px) {
.body {
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
}
@media (max-width: 767px) {
.body {
grid-template-columns: repeat(1, 1fr);
}
}
44 changes: 44 additions & 0 deletions src/components/pages/boards/BestItems.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useState, useEffect } from "react";
import { useMediaQuery } from "@/hooks/useMediaQuery";
import { getArticles } from "@/apis/apis";
import { GetArticlesParams, GetArticlesRes } from "@/apis/apis.type";
import { useQuery } from "@/hooks/useQuery";
import BestItem from "./componnets/BestItem";
import styles from "./BestItems.module.css";

const pageSizeTable = { PC: 3, TABLET: 2, MOBILE: 1 };

export default function BestItems() {
const media = useMediaQuery();
const [paramObj, setParamObj] = useState<GetArticlesParams>({
page: 1,
pageSize: pageSizeTable[media],
orderBy: "like",
});
const { isLoading, error, data } = useQuery<
GetArticlesParams,
GetArticlesRes
>(getArticles, paramObj);

useEffect(() => {
setParamObj((prevObj) => ({
...prevObj,
pageSize: pageSizeTable[media],
}));
}, [media]);

return (
<section className={styles.section}>
<div className={styles.head}>
<h2 className={styles.title}>베스트 게시글</h2>
</div>
{!isLoading && !error && data && (
<div className={styles.body}>
{data.list.map((item) => (
<BestItem key={item.id} data={item} />
))}
</div>
)}
</section>
);
}
44 changes: 44 additions & 0 deletions src/components/pages/boards/componnets/BestItem.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
.item {
display: flex;
flex-direction: column;
gap: 16px;
}

.imageWrapper {
position: relative;
width: 72px;
height: 72px;
border-radius: 8px;
border: 1px solid var(--gray-200);
}

.image {
object-fit: contain;
}

.content {
display: flex;
flex-direction: column;
gap: 6px;
}

.title {
font-size: var(--size-md);
}

.price {
font-size: var(--size-lg);
font-weight: bold;
}

.like {
display: flex;
align-items: center;
gap: 4px;
font-size: var(--size-xs);
}

.likeIcon {
width: 16px;
height: 16px;
}
40 changes: 40 additions & 0 deletions src/components/pages/boards/componnets/BestItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Link from "next/link";
import Image from "next/image";
import heartIcon from "#/icons/heart_inactive.svg";
import styles from "./BestItem.module.css";
import { ArticleProps } from "@/apis/apis.type";

interface ItemProps {
data: ArticleProps;
}

export default function BestItem({ data }: ItemProps) {
const {
id,
title,
writer: { nickname },
updatedAt,
image,
likeCount,
} = data;
return (
<Link className={styles.item} href={`/board/${id}`}>
<div className={styles.imageWrapper}>
<Image
className={styles.image}
src={image ? image : ""}
alt={"이미지"}
fill
/>
</div>
<div className={styles.content}>
<span className={styles.title}>{title}</span>
<span className={styles.price}>{updatedAt}</span>
<div className={styles.like}>
<Image className={styles.likeIcon} src={heartIcon} alt="좋아요 수" />
<span>{likeCount}</span>
</div>
</div>
</Link>
);
}
28 changes: 28 additions & 0 deletions src/hooks/useMediaQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useState, useEffect } from "react";

export type MediaType = "PC" | "TABLET" | "MOBILE";

function checkMedia(width: number): MediaType {
if (width >= 1200) return "PC";
if (width >= 768) return "TABLET";
return "MOBILE";
}

export function useMediaQuery() {
const [media, setMedia] = useState<MediaType>("PC");

useEffect(() => {
setMedia(checkMedia(window.innerWidth));

const handleWindowResize = () => {
setMedia(checkMedia(window.innerWidth));
};

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

return media;
}
2 changes: 1 addition & 1 deletion src/hooks/useQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function useQuery<Params extends object, Response extends object>(
[fetchFunc]
);

const update = wrappedFunc(paramObj);
const update = () => wrappedFunc(paramObj);

useEffect(() => {
wrappedFunc(paramObj);
Expand Down
2 changes: 1 addition & 1 deletion src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { AppProps } from "next/app";
import localFont from "next/font/local";
import Head from "next/head";
import Layout from "@/components/layout/Layout";
import "@/styles/reset.css";
import "@/styles/variable.css";
import "@/styles/global.css";
import Layout from "@/components/layout/Layout";

export const pretendard = localFont({
src: "../../public/fonts/PretendardVariable.woff2",
Expand Down
21 changes: 21 additions & 0 deletions src/pages/boards.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.main {
display: flex;
flex-direction: column;
gap: 40px;
align-items: center;
margin-top: 70px;
padding: 24px 0 48px;
color: var(--gray-800);
}
@media (max-width: 1199px) {
.main {
gap: 32px;
padding: 24px 24px 48px;
}
}
@media (max-width: 767px) {
.main {
gap: 24px;
padding: 16px 16px 48px;
}
}
6 changes: 5 additions & 1 deletion src/pages/boards.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import Head from "next/head";
import BestItems from "@/components/pages/boards/BestItems";
import styles from "./boards.module.css";

export default function Boards() {
return (
<>
<Head>
<title>자유게시판 - 판다마켓</title>
</Head>
<main>자유게시판</main>
<main className={styles.main}>
<BestItems />
</main>
</>
);
}

0 comments on commit f037188

Please sign in to comment.