Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
822c4f3
Merge pull request #2 from Daewony/next-강대원-sprint9
Daewony Dec 22, 2024
f1e43cc
Merge branch 'next-강대원-sprint9' of https://github.com/Daewony/3-sprin…
Daewony Feb 3, 2025
3fc43fc
refactor: 폴더 구조 리팩토링 및 'auth', 'routes' 폴더 무시 설정
Daewony Feb 3, 2025
7baa941
chore: next-sitemap 설치
Daewony Feb 3, 2025
32dc6c6
feat: 판다마켓 랜딩 페이지 SEO 메타데이터 추가
Daewony Feb 3, 2025
5f48c3f
refactor: 로그인 및 회원가입 페이지에서 Nav와 Footer 숨김 처리를 중첩 레이아웃으로 수정
Daewony Feb 7, 2025
f8687e5
refactor: 비밀번호 보이기 버튼 tab 포커스 제외 처리
Daewony Feb 7, 2025
179eb0f
refactor: 베스트 상품 CSR -> SSR 적용
Daewony Feb 7, 2025
4d839f9
fix: 타입 정의 파일명 수정
Daewony Feb 7, 2025
0625a62
remove: 필요없는 주석 제거
Daewony Feb 9, 2025
eaffbd7
refactor: spint9 이미지 경로를 문자열 상수로 정의 적용
Daewony Feb 9, 2025
b5b9140
refactor: 전체 게시글 목록 wrappring 컴포넌트 추가
Daewony Feb 9, 2025
ae2b063
refactor(AllArticles): 쿼리 설정에 시간 단위 상수 적용
Daewony Feb 9, 2025
785ef38
fix: productId 타입을 string | number -> string으로 통일
Daewony Feb 9, 2025
9831f7e
refactor(CommentList): DropdownStates 타입 alias 도입
Daewony Feb 9, 2025
9ffca33
refactor(commentApi): getComments 함수 수정
Daewony Feb 9, 2025
a5684ff
refactor(HomeBanner): dangerouslySetInnerHTML 불필요한 속성 제거
Daewony Feb 9, 2025
788b38b
refactor(Pagination): 인라인 색상 코드 상수화 및 inline style 적용
Daewony Feb 9, 2025
06b1c08
refactor: PostAndCommentActionsDropdown -> ActionsDropdown 컴포넌트 리팩토링,…
Daewony Feb 9, 2025
c0d74db
refactor: 'max-w-container' tailwind custom class 추가 및 적용
Daewony Feb 18, 2025
b74f618
refactor: 상수들을 utils 폴더에서 최상위 constants 디렉토리로 이동
Daewony Feb 18, 2025
33421c8
refactor(CommentList): Record 타입 적용
Daewony Feb 18, 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
21 changes: 21 additions & 0 deletions app/(auth)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";

const queryClient = new QueryClient();

export default function AuthLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<QueryClientProvider client={queryClient}>
<div className="flex min-h-screen flex-col pt-[75px]">
<main className="flex-grow">{children}</main>
</div>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion app/articles/page.tsx → app/(routes)/articles/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import BestArticles from "@/components/articles/BestArticles";
const ArticlePage = () => {
return (
<article className="p-4 md:p-6">
<div className="mx-auto min-w-[325px] max-w-[1200px]">
<div className="max-w-container mx-auto min-w-[325px]">
<BestArticles />
<AllArticles />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const ProductUpdatePage = ({ params }: { params: { id: string } }) => {
};

return (
<section className="mx-auto box-border max-w-[1200px] px-6 pb-40 pt-6">
<section className="max-w-container mx-auto box-border px-6 pb-40 pt-6">
<ProductForm
defaultValues={productData}
productId={productId}
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ProductForm from "@/components/items/ProductForm";

const ProductCreatePage = () => {
return (
<section className="mx-auto box-border max-w-[1200px] px-6 pb-40 pt-6">
<section className="max-w-container mx-auto box-border px-6 pb-40 pt-6">
<ProductForm />
</section>
);
Expand Down
38 changes: 38 additions & 0 deletions app/(routes)/items/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import AllProducts from "@/components/items/AllProducts";
import BestProducts from "@/components/items/BestProducts";
import { BASE_URL } from "@/lib/axios";

const ItemsPage = async () => {
// User Agent를 활용한 pageSize 결정은 app 디렉토리에서는 어렵기 때문에 기본값 사용
const pageSize = 4;
let bestProducts = null;
try {
bestProducts = await getBestProducts(pageSize);
} catch (error) {
console.error("Error fetching best products:", error);
}

return (
<article className="px-6 py-7">
<section className="max-w-container mx-auto flex flex-col gap-10">
<BestProducts items={bestProducts} />
<AllProducts />
</section>
</article>
);
};

// SSR을 사용하면 대신 fetch API를 직접 사용합니다.
async function getBestProducts(pageSize: number) {
console.log(BASE_URL);
const res = await fetch(
`${BASE_URL}/products?page=1&pageSize=${pageSize}&orderBy=favorite`,
{ cache: "no-store" },
);
if (!res.ok) {
throw new Error("Failed to fetch");
}
return res.json();
}

export default ItemsPage;
21 changes: 5 additions & 16 deletions app/ClientLayout.tsx → app/(routes)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,23 @@
"use client";

import { usePathname } from "next/navigation";
import Nav from "@/components/common/nav/Nav";
import Footer from "@/components/common/footer/Footer";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";

// 숨길 페이지를 객체로 관리
const hiddenRoutes = {
login: "/login",
signup: "/signin",
};
import Nav from "@/components/common/nav/Nav";
import Footer from "@/components/common/footer/Footer";

const queryClient = new QueryClient();

export default function ClientLayout({
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const pathname = usePathname();
// 현재 경로가 숨길 페이지에 포함되는지 확인
const hideNavAndFooter = Object.values(hiddenRoutes).includes(pathname);

return (
<QueryClientProvider client={queryClient}>
<div className="flex min-h-screen flex-col pt-[75px]">
{!hideNavAndFooter && <Nav />}
<Nav />
<main className="flex-grow">{children}</main>
{!hideNavAndFooter && <Footer />}
<Footer />
</div>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
Expand Down
16 changes: 13 additions & 3 deletions app/page.tsx → app/(routes)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,30 @@ import HomeBanner from "@/components/home/HomeBanner";
import topBannerImage from "@/public/images/home/hero-image.png";
import bottomBannerImage from "@/public/images/home/bottom-banner-image.png";

// SSG
export default function HomePage() {
return (
<>
<main>
<h1 className="sr-only">판다마켓 - 안전한 중고거래 플랫폼</h1>
<section aria-label="메인 배너">
<HomeBanner
title="일상의 모든 물건을 거래해 보세요"
buttonText="구경하러 가기"
buttonLink="/login"
imageSrc={topBannerImage}
/>
</section>
<article className="features">
<h2 className="sr-only">판다마켓 주요 기능</h2>
{/* 기능 소개 섹션들 */}
</article>
<section aria-label="신뢰성 배너">
<HomeBanner
title="믿을 수 있는 <br /> 판다마켓 중고 거래"
title="믿을 수 있는 판다마켓 중고 거래"
imageSrc={bottomBannerImage}
isFooter
/>
</>
</section>
</main>
);
}
File renamed without changes.
2 changes: 1 addition & 1 deletion app/post/[id]/page.tsx → app/(routes)/post/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const PostDetailPage = ({ params }: { params: { id: string } }) => {
const { id: productId } = params;

return (
<article className="mx-auto max-w-[1200px]">
<article className="max-w-container mx-auto">
{/* 게시글 내용 */}
<PostDetailContent />

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion app/post/page.tsx → app/(routes)/post/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PostList from "@/components/post/PostList/PostList";
const PostPage = () => {
return (
<article className="p-4 md:p-6">
<div className="mx-auto min-w-[325px] max-w-[1200px]">
<div className="max-w-container mx-auto min-w-[325px]">
<BestPost />
<PostList />
</div>
Expand Down
16 changes: 0 additions & 16 deletions app/items/page.tsx

This file was deleted.

44 changes: 38 additions & 6 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";
import ClientLayout from "./ClientLayout";

const pretendard = localFont({
src: "./fonts/PretendardVariable.woff2",
Expand All @@ -11,11 +10,46 @@ const pretendard = localFont({
});

export const metadata: Metadata = {
title: "판다 마켓",
description: "Generated by 대원",
title: "판다마켓 | 안전한 중고거래 플랫폼",
description:
"일상의 모든 물건을 거래하는 안전한 중고거래 플랫폼. 패션, 전자기기, 가전 등 다양한 카테고리의 상품을 만나보세요. 판다마켓에서 믿을 수 있는 거래를 시작하세요.",
keywords:
"판다마켓, 중고거래, 중고마켓, 중고물품, 중고판매, 중고구매, 안전거래",
metadataBase: new URL("https://panda-marketplace.vercel.app"),
alternates: {
canonical: "/",
},

icons: {
icon: "/icons/favicon/favicon.ico",
},
openGraph: {
title: "판다마켓 | 안전한 중고거래 플랫폼",
description: "일상의 모든 물건을 거래하는 안전한 중고거래 플랫폼",
url: "https://panda-marketplace.vercel.app",
siteName: "판다마켓",
images: [
{
url: "/public/images/logo/logo.svg",
width: 1200,
height: 630,
alt: "판다마켓 대표 이미지",
},
],
locale: "ko_KR",
type: "website",
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
"max-video-preview": -1,
"max-image-preview": "large",
"max-snippet": -1,
},
},
};

export default function RootLayout({
Expand All @@ -27,9 +61,7 @@ export default function RootLayout({
<>
<html lang="ko" className={`${pretendard.variable} antialiased`}>
<body className={pretendard.className}>
<div className="flex min-h-screen flex-col">
<ClientLayout>{children}</ClientLayout>
</div>
<div className="flex min-h-screen flex-col">{children}</div>
</body>
</html>
</>
Expand Down
4 changes: 2 additions & 2 deletions components/articles/AllArticleCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Link from "next/link";
import { formattedDate } from "@/utils/formattedDate";
import HeartIcon from "@/components/SVG/HeartIcon";
import profileIcon from "@/public/icons/ic_profile.png";
import { DEFAULT_IMAGE } from "@/utils/defaultImage";
import { DEFAULT_IMAGE_PATH } from "@/utils/defaultImage";

type AllArticleCardProps = {
article: ArticleCreateResponse;
Expand All @@ -24,7 +24,7 @@ const AllArticleCard = ({
<p className="grow text-xl font-semibold text-black">{title}</p>
<div className="h-[72px] w-[72px] shrink-0 rounded-lg border border-gray-light bg-white p-3">
<Image
src={image ?? DEFAULT_IMAGE}
src={image ?? DEFAULT_IMAGE_PATH}
alt="post thumbnail image"
height={48}
width={48}
Expand Down
20 changes: 12 additions & 8 deletions components/articles/AllArticles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@ import searchIcon from "@/public/icons/ic_search.svg";
import sortButton from "@/public/images/btn_sort.png";
import { getArticleList } from "@/services/articleApi";
import { ArticleListResponse } from "@/types/articles";
import ArticleListWrapper from "./ArticleListWrapper";
import { MINUTES } from "@/constants";

const AllArticles = () => {
const [sortOrder, setSortOrder] = useState<"recent" | "like">("recent");

const { data: articles, isLoading } = useQuery<ArticleListResponse>({
queryKey: ["AllArticles"],
queryFn: () => getArticleList(1, 10, sortOrder, ""),
staleTime: 1000 * 60 * 5,
gcTime: 1000 * 60 * 30,
staleTime: 5 * MINUTES,
gcTime: 30 * MINUTES,
refetchOnWindowFocus: false,
refetchInterval: 1000 * 60 * 10,
refetchInterval: 10 * MINUTES,
Comment on lines +24 to +27
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

상수 대신 함수를 만들어서 사용하는 방식도 괜찮을 것 같아요.

});

if (isLoading) {
Expand Down Expand Up @@ -73,11 +75,13 @@ const AllArticles = () => {
</div>

{/* 게시글 리스트 */}
<ul>
{articles?.list?.map((article) => (
<AllArticleCard key={article.id} article={article} />
))}
</ul>
<ArticleListWrapper>
<ul>
{articles?.list?.map((article) => (
<AllArticleCard key={article.id} article={article} />
))}
</ul>
</ArticleListWrapper>
</section>
);
};
Expand Down
13 changes: 13 additions & 0 deletions components/articles/ArticleListWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use client";

import React from "react";

type ArticleListWrapperProps = {
children: React.ReactNode;
};

const ArticleListWrapper = ({ children }: ArticleListWrapperProps) => {
return <div className="article-list-wrapper">{children}</div>;
};

export default ArticleListWrapper;
2 changes: 1 addition & 1 deletion components/common/comment/CommentInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
type CommentInputProps = {
title: string;
placeholder: string;
productId: string | number;
productId: string;
};

const CommentInput = ({ title, placeholder, productId }: CommentInputProps) => {
Expand Down
Loading