Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c6b9a32
Feat : initial setting
heewls Feb 28, 2025
30627cf
Feat : header component
heewls Feb 28, 2025
8f74df5
Feat : best item card
heewls Feb 28, 2025
faa11f4
Feat : get boards api
heewls Feb 28, 2025
b06fcc8
Feat : best boards component
heewls Feb 28, 2025
443ac33
Feat : formatted date
heewls Feb 28, 2025
97d05e9
Feat : all board item card
heewls Feb 28, 2025
17add08
Chore : move header component to common
heewls Mar 1, 2025
40bdab8
Feat : input common component
heewls Mar 1, 2025
2fffc17
Feat : search component
heewls Mar 2, 2025
8cd34f9
Fix :gap 0px when no label
heewls Mar 2, 2025
f4419c0
Feat : dropdown common component
heewls Mar 2, 2025
eb090ee
Feat : pagination component
heewls Mar 2, 2025
677f49d
Feat : Link
heewls Mar 2, 2025
2304bfd
Fix : edit change handler
heewls Mar 2, 2025
80e8a7d
Fix : isActive props error
heewls Mar 2, 2025
7c620e3
Feat : all boards component
heewls Mar 2, 2025
92b328a
Feat : scroll true when changing page
heewls Mar 2, 2025
98c37d2
Fix : apply pagination Link
heewls Mar 3, 2025
93d9858
Feat
heewls Mar 4, 2025
cdbd2da
Feat : useBestData custom hook
heewls Mar 4, 2025
ad4a93a
Feat : useParams custom hook
heewls Mar 4, 2025
1a9c7a8
Feat : useAllData custom hook
heewls Mar 4, 2025
7b96172
Feat : useSearch custom hook
heewls Mar 4, 2025
b17975e
Chore : next config edit
heewls Mar 4, 2025
5b35cdc
Feat : delete page params when page is 1
heewls Mar 5, 2025
d1f5b68
Feat : header component edit
heewls Mar 5, 2025
1d749f9
Feat : move getBoards data
heewls Mar 5, 2025
3c00f6a
Feat : tailwindcss setting
heewls Mar 7, 2025
371173e
Style : boards page tailwindcss
heewls Mar 7, 2025
fd9e4b9
Feat : all component useAllData & tailwind css
heewls Mar 7, 2025
bc98c38
Style : best tailwindcss
heewls Mar 7, 2025
2475e61
Style : dropdown component tailwind css
heewls Mar 7, 2025
346e271
Style : input tailwind css
heewls Mar 7, 2025
7cc5f45
Style : pagination tailwind css
heewls Mar 7, 2025
6bad784
Feat : add dependency array & textarea type
heewls Mar 7, 2025
465674b
Style : fontWeigth 700
heewls Mar 7, 2025
0fc7edf
Feat : header component tailwind css & active link
heewls Mar 7, 2025
a9749a6
Style : tailwind css edit
heewls Mar 9, 2025
46e04b2
Style : header tailwind css edit
heewls Mar 9, 2025
7efcd7f
Feat
heewls Mar 9, 2025
a19a52c
Style : all component tailwind css edit
heewls Mar 9, 2025
2f41af1
Style : tailwind screens edit
heewls Mar 9, 2025
032c967
Style : boards page tailwind css edit
heewls Mar 9, 2025
2a6bf14
Feat : metadata
heewls Mar 9, 2025
4659c8f
Style : apply global font
heewls Mar 9, 2025
b468da8
Feat : server initial data
heewls Mar 10, 2025
bf12624
Feat : error image
heewls Mar 10, 2025
6c5d9cd
Feat : Metadata type & not-found page
heewls Mar 10, 2025
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/node_modules
/.pnp
.pnp.js
.env

# testing
/coverage
Expand Down
36 changes: 36 additions & 0 deletions apis/boards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import api from "./index";

export interface BoardItem {
updatedAt: string;
createdAt: string;
likeCount: number;
writer: {
nickname: string;
id: number;
};
image: string;
content: string;
title: string;
id: number;
}

export interface Boards {
totalCount?: 0;
list: BoardItem[];
}

interface Params {
page: number;
pageSize: number;
orderBy: string;
keyword: string;
}

export async function getBoards(params: Params): Promise<Boards> {
const { page, pageSize, orderBy, keyword } = params;
const response = await api.get("/articles", {
params: { page, pageSize, orderBy, keyword },
});

return response.data;
}
12 changes: 12 additions & 0 deletions apis/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import axios from "axios";

const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL;

const api = axios.create({
baseURL: BASE_URL,
headers: {
"Content-Type": "application/json",
},
});

export default api;
23 changes: 23 additions & 0 deletions app/boards/getBoardsData.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getBoards } from "@/apis/boards";

export default async function getBoardsData() {
const allData = await getBoards({
page: 1,
pageSize: 10,
orderBy: "recent",
keyword: "",
});

const initialAllData = allData.list;

const bestData = await getBoards({
page: 1,
pageSize: 3,
orderBy: "like",
keyword: "",
});

const initialBestData = bestData?.list ?? [];

return { initialAllData, initialBestData };
}
23 changes: 23 additions & 0 deletions app/boards/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Best from "@/components/BestBoards/Best";
import All from "@/components/AllBoards/All";
import getBoardsData from "./getBoardsData";
import { Metadata } from "next";

export const metadata: Metadata = {
title: "판다마켓 | 자유게시판",
};

export const revalidate = 60;

export default async function Boards() {
const { initialAllData, initialBestData } = await getBoardsData();
Copy link
Collaborator

Choose a reason for hiding this comment

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

각기 다른 예외 처리를 하기에 어려울 것 같아요.

서로 다른 쿼리로 통신 하고 있기에 다른 에러가 발생할 여지가 있으나(물론 해당 코드에는 예외처리가 없긴 하지만), 이렇게 처리하면 특정 API의 예외처리를 하기 어려울 것 같군요 !

Copy link
Collaborator

Choose a reason for hiding this comment

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

또한, 현재 직렬처리로 되어있는데 병렬로 처리하시면 성능에 도움이 됩니다 !

Suggested change
const { initialAllData, initialBestData } = await getBoardsData();
const allData = await getBoards({
page: 1,
pageSize: 10,
orderBy: "recent",
keyword: "",
});
const bestData = await getBoards({
page: 1,
pageSize: 3,
orderBy: "like",
keyword: "",
});
// ..........
const [ allData, bestData ] = await Promise.all([
getBoards({
page: 1,
pageSize: 10,
orderBy: "recent",
keyword: "",
}),
getBoards({
page: 1,
pageSize: 3,
orderBy: "like",
keyword: "",
})
])


return (
<div className="flex justify-center items-center my-10 lg:my-0">
<div className="max-w-[1200px] min-w-[343px] px-6 lg:p-4 md:p-6 flex flex-col gap-10">
<Best initialData={initialBestData} />
<All initialData={initialAllData} />
</div>
Comment on lines +13 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.

오호.. 초기 데이터를 받아와서 TTV를 빠르게 하셨군요 ..? 🫢🫢

훌륭합니다. ㄷㄷㄷ 첫 코드부터 기대되는데요 ?

TTV: 사용자가 웹브라우저에서 내용을 볼 수 있는 시점

</div>
);
}
83 changes: 83 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
* {
box-sizing: border-box;
text-decoration: none;
list-style: none;
}

body {
font-family: "Pretendard", sans-serif;
}

body,
p,
h2 {
margin: 0;
}

ul,
li {
margin: 0;
padding: 0;
}

button,
input,
textarea {
border: none;
}
}

@layer utilities {
.line-break {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-align: left;
overflow: hidden;
}
}

@font-face {
font-family: "ROKAF Sans";
src: url("/font/ROKAF.ttf");
font-weight: 700;
font-style: normal;
}

@font-face {
font-family: "Pretendard";
src: url("https://fastly.jsdelivr.net/gh/Project-Noonnu/[email protected]/Pretendard-Regular.woff2")
format("woff2");
src: url("https://fastly.jsdelivr.net/gh/Project-Noonnu/[email protected]/Pretendard-Regular.woff")
format("woff");
font-display: swap;
font-weight: 400;
font-style: normal;
}

@font-face {
font-family: "Pretendard";
src: url("https://fastly.jsdelivr.net/gh/Project-Noonnu/[email protected]/Pretendard-SemiBold.woff2")
format("woff2");
src: url("https://fastly.jsdelivr.net/gh/Project-Noonnu/[email protected]/Pretendard-SemiBold.woff")
format("woff");
font-display: swap;
font-weight: 600;
font-style: normal;
}

@font-face {
font-family: "Pretendard";
src: url("https://fastly.jsdelivr.net/gh/Project-Noonnu/[email protected]/Pretendard-Bold.woff2")
format("woff2");
src: url("https://fastly.jsdelivr.net/gh/Project-Noonnu/[email protected]/Pretendard-Bold.woff")
format("woff");
font-display: swap;
font-weight: 700;
font-style: normal;
}
9 changes: 9 additions & 0 deletions app/items/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Metadata } from "next";

export const metadata: Metadata = {
title: "판다마켓 | 중고마켓",
};

export default function Home() {
return <>items page</>;
}
22 changes: 22 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Header from "@/components/common/Header/Header";
import "./globals.css";
import { Metadata } from "next";

export const metadata: Metadata = {
title: "판다마켓",
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ko">
<body>
<Header />
{children}
</body>
</html>
);
}
16 changes: 16 additions & 0 deletions app/not-found.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

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

크으 ~ not found까지 꼼꼼하네요 👍👍👍

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Metadata } from "next";
import Image from "next/image";
import panda from "@/public/icons/panda.svg";

export const metadata: Metadata = {
title: "판다마켓 | not found",
};

export default function NotFound() {
return (
<div className="w-screen min-h-[calc(100vh-70px)] flex flex-col justify-center items-center gap-10">
<Image width={280} height={280} src={panda} alt="panda" />
<p className="text-7xl text-blue font-bold">404 | NOT FOUND</p>
</div>
);
}
3 changes: 3 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Home() {
return <>home page</>;
}
54 changes: 54 additions & 0 deletions components/AllBoards/All.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"use client";

import AllItem from "./AllItem";
import Dropdown from "../common/Dropdown/Dropdown";
import Search from "../Search/Search";
import Pagination from "../Pagination/Pagination";
import useParams from "@/hooks/useParams";
import useAllData from "./useAllData";
import { BoardItem } from "@/apis/boards";

const FilterList = ["recent", "like"];
const PAGE_SIZE = 10;

interface AllProps {
initialData: BoardItem[];
}

export default function All({ initialData }: AllProps) {
const { page, orderBy, keyword, handleParamsUpdate } = useParams();
const { all, totalBoards } = useAllData({ initialData, PAGE_SIZE });

return (
<div className="w-full flex flex-col gap-6">
<div className="flex justify-between items-center">
<h2 className="text-gray900 text-Bold20 font-bold">게시글</h2>
<button className="py-2 px-6 bg-blue text-white text-Bold16 rounded-lg cursor-pointer">
글쓰기
</button>
</div>
<div className="w-full flex flex-col gap-6">
<div className="flex justify-center items-center gap-3">
<Search />
<Dropdown
list={FilterList}
orderBy={orderBy}
onChange={(filter) => handleParamsUpdate({ orderBy: filter })}
/>
</div>
<div className="w-full flex flex-col gap-6">
{all.map((item) => (
<AllItem key={item.id} all={item} />
))}
</div>
{!keyword && (
<Pagination
totalBoards={totalBoards ?? 0}
currentPage={page}
pageSize={PAGE_SIZE}
/>
)}
</div>
</div>
);
}
42 changes: 42 additions & 0 deletions components/AllBoards/AllItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Image from "next/image";
import user from "@/public/icons/user.svg";
import heart from "@/public/icons/emptyHeart.svg";
import formattedDate from "@/utils/formattedDate";
import { BoardItem } from "@/apis/boards";
import Link from "next/link";
import BoardImage from "../BoardImage/BoardImage";

interface AllItemProps {
all: BoardItem;
}

export default function AllItem({ all }: AllItemProps) {
return (
<Link
className="w-full h-[138px] flex flex-col gap-4 pb-6 bg-bg border-b border-gray200 cursor-pointer"
href="/"
>
<div className="w-full flex justify-between items-start">
<p className="flex-1 h-[60px] break-words text-gray800 text-Bold20">
{all.content}
</p>
<BoardImage image={all.image} />
</div>
<div className="w-full flex justify-between items-center">
<div className=" flex justify-center items-center gap-2">
<Image src={user} width={24} height={24} alt="user" />
<span className="text-gray600 text-Regular14">
{all.writer.nickname}
</span>
<span className="text-gray400 text-Regular14">
{formattedDate(all.createdAt)}
</span>
</div>
<div className="flex justify-center items-center gap-1">
<Image src={heart} width={16} height={16} alt="like" />
<span className="text-gray500 text-Regular14">{all.likeCount}</span>
</div>
</div>
</Link>
);
}
33 changes: 33 additions & 0 deletions components/AllBoards/useAllData.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { BoardItem, getBoards } from "@/apis/boards";
import { useEffect, useState } from "react";
import useParams from "@/hooks/useParams";

interface AllDataProps {
initialData: BoardItem[];
PAGE_SIZE: number;
}

export default function useAllData({ initialData, PAGE_SIZE }: AllDataProps) {
const [all, setAll] = useState<BoardItem[]>(initialData);
const [totalBoards, setTotalBoards] = useState<number>(0);
const { page, orderBy, keyword } = useParams();

useEffect(() => {
getBoards({
page,
pageSize: keyword ? 1000 : PAGE_SIZE,
orderBy,
keyword,
})
.then((result) => {
if (!result) return;
setAll(result.list);
if (result.totalCount) {
setTotalBoards(result.totalCount);
}
})
.catch((error) => console.error(error));
}, [page, orderBy, keyword, PAGE_SIZE]);

return { all, totalBoards };
}
Loading
Loading