Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
0013f79
Refactor : best item useMemo
heewls Mar 11, 2025
c9fe8c7
Refactor : pagination magic number
heewls Mar 11, 2025
5907f13
Refactor : rename useBoardsParams
heewls Mar 11, 2025
c4f88cc
Feat : all boards suspens
heewls Mar 11, 2025
ab814f7
Feat : best boards suspense
heewls Mar 14, 2025
deb00ab
Feat : root layout edit
heewls Mar 14, 2025
3f45d17
Chore : setting
heewls Apr 4, 2025
9f3753f
Fix : input
heewls Apr 4, 2025
55ab7c8
Feat : auth footer
heewls Apr 4, 2025
ceddc83
Feat : auth layout & login page
heewls Apr 4, 2025
7f21155
Style : add semibold, medium
heewls Apr 4, 2025
49f69c2
Feat : common button component
heewls Apr 4, 2025
6fd45f5
Feat : login UI
heewls Apr 5, 2025
7addbf6
Feat : formField
heewls Apr 5, 2025
00cce3c
Feat : auth layout
heewls Apr 5, 2025
eae642e
Feat : signup page UI
heewls Apr 5, 2025
a79cde9
Feat : errormessage & isValid
heewls Apr 5, 2025
9079ee4
Feat : button disabeld css
heewls Apr 5, 2025
c95088c
Feat : api
heewls Apr 5, 2025
98c9838
Feat : fetch api
heewls Apr 7, 2025
4c6791c
Feat: button type extend
heewls Apr 7, 2025
ffd0849
Feat : authValidate
heewls Apr 7, 2025
783cfcf
Feat : check all form complete
heewls Apr 7, 2025
6f029ec
Feat : signup server action
heewls Apr 7, 2025
47de8ec
Feat : signup form logic
heewls Apr 7, 2025
3a4c6b0
Feat : router push login
heewls Apr 7, 2025
a0088b4
Feat : separeate validate & 400 nickname error
heewls Apr 7, 2025
0bcffdf
Feat : apiClient & apiServer
heewls Apr 7, 2025
bfab735
Refactor : apply apiClient
heewls Apr 7, 2025
68151e1
Feat : apply apiServer
heewls Apr 7, 2025
3db3bec
Refactor : edit css
heewls Apr 7, 2025
d1738f6
Feat : status -> success
heewls Apr 7, 2025
b4d3167
Chore : rename
heewls Apr 7, 2025
0ebee32
Chore : export default
heewls Apr 7, 2025
eed3e72
Feat : login logic
heewls Apr 7, 2025
476eacb
Feat : login accessToken
heewls Apr 9, 2025
6c71c6f
Fix : response data
heewls Apr 9, 2025
d5c2062
Fix : get boards return
heewls Apr 9, 2025
5bf643e
Feat : label required
heewls Apr 9, 2025
bf4c2d0
Style : prettier
heewls Apr 9, 2025
d15f466
Style : textarea minHeight
heewls Apr 9, 2025
8b6911c
Style : header
heewls Apr 9, 2025
2ab2b9d
Feat : file input
heewls Apr 9, 2025
6ac4116
Feat : add board UI
heewls Apr 9, 2025
b0d94d3
Fix : input required
heewls Apr 10, 2025
3a41084
Fix : edit isJson
heewls Apr 10, 2025
0ec3fa0
Fix : localstoarge & createFeachOptions url
heewls Apr 10, 2025
e38706d
Feat : add board route handler
heewls Apr 10, 2025
d986163
Feat : add board logic
heewls Apr 10, 2025
3367d23
Feat : file logic
heewls Apr 10, 2025
1a26da7
Feat : upload file
heewls Apr 10, 2025
28e1910
Feat : refresh accessToken
heewls Apr 11, 2025
6705809
Style : board layout
heewls Apr 11, 2025
af892a5
Fix : edit pathname
heewls Apr 11, 2025
6c50e81
Style : bestItem width
heewls Apr 11, 2025
90db46e
Feat : detail board
heewls Apr 12, 2025
0421468
Feat: board comment input
heewls Apr 12, 2025
d043787
Feat : get comments
heewls Apr 12, 2025
77c1df6
Feat : boardId page
heewls Apr 12, 2025
d13316b
Feat : zustand userId
heewls Apr 12, 2025
5c3dc9c
Feat : post comment
heewls Apr 12, 2025
929721b
Feat : action.ts
heewls Apr 13, 2025
a57870b
Style : bold32
heewls Apr 14, 2025
23e1283
Feat : home page footer
heewls Apr 14, 2025
cde26c1
Feat : home page footer
heewls Apr 14, 2025
8f5595d
Feat : home page
heewls Apr 14, 2025
744dd07
Feat : link items
heewls Apr 14, 2025
9b54049
Feat : edit active nav
heewls Apr 16, 2025
71b0f08
Feat : default image invisible
heewls Apr 16, 2025
d741066
Feat : header user(using userId)
heewls Apr 16, 2025
30eb49d
Fix : userId zustand -> localstorage
heewls Apr 16, 2025
e164756
Fix : delete layout user zustand
heewls Apr 16, 2025
5270194
Feat : logout
heewls Apr 16, 2025
71baddd
Feat : has accessToken redirect /
heewls Apr 16, 2025
5c35e75
Feat : edit userId
heewls Apr 17, 2025
223cb00
Feat : refresh accessToken
heewls Apr 17, 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
3 changes: 0 additions & 3 deletions .eslintrc.json

This file was deleted.

3 changes: 3 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": ["prettier-plugin-tailwindcss"]
}
36 changes: 0 additions & 36 deletions apis/boards.tsx

This file was deleted.

12 changes: 0 additions & 12 deletions apis/index.tsx

This file was deleted.

34 changes: 34 additions & 0 deletions app/(auth)/_components/AuthFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Image from "next/image";
import Link from "next/link";
import google from "@/public/icons/google.svg";
import kakao from "@/public/icons/kakao.svg";

interface FooterProps {
title: string;
href: string;
hrefMessage: string;
}

export default function AuthFooter({ title, href, hrefMessage }: FooterProps) {
return (
<>
<div className="flex w-full items-center justify-between rounded-lg bg-[#e6f2ff] px-[23px] py-4">
<p className="text-gray800 text-Regular16">간편 로그인하기</p>
<div className="flex gap-4">
<Link href="https://www.google.com">
<Image src={google} width={42} height={42} alt="google" />
</Link>
<Link href="https://www.kakaocorp.com/page">
<Image src={kakao} width={42} height={42} alt="kakao" />
</Link>
</div>
</div>
<div className="text-Regular14 text-gray800 flex items-center justify-center">
{title}
<Link className="text-blue ml-1 underline" href={href}>
{hrefMessage}
</Link>
</div>
</>
);
}
37 changes: 37 additions & 0 deletions app/(auth)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Image from "next/image";
import Link from "next/link";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

export default async function AuthLayout({
children,
}: {
children: React.ReactNode;
}) {
const cookie = await cookies();
const accessToken = cookie.get("accessToken")?.value;
Copy link
Collaborator

Choose a reason for hiding this comment

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

오호 쿠키를 서버 사이드에서 읽고 대처하셨군요 ? 👍👍

굿굿. NextJS에서 서버사이드의 활용 방법을 잘 이해하신 것으로 보여요 👍

Copy link
Collaborator

Choose a reason for hiding this comment

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

layout.tsx에 설정하신 점도 인상깊네요.

레이아웃의 nested 특징을 잘 살리셨네요. 이렇게 된다면 auth 그룹 라우팅에 해당하는 곳들은 해당 레이아웃으로 인해 인가 된 유저들을 효과적으로 구별할 수 있겠어요 👍


if (accessToken) {
redirect("/");
}

return (
<div className="flex h-screen items-center justify-center">
<div className="flex w-[640px] flex-col items-center justify-center gap-10 px-4 sm:px-6">
<Link className="flex items-center gap-5" href="/">
<Image
src="/icons/panda.svg"
width={103}
height={103}
alt="logo"
className="hidden sm:block"
/>
<h1 className="font-rokaf text-blue text-[66px] font-bold">
판다마켓
</h1>
</Link>
{children}
</div>
</div>
);
}
15 changes: 15 additions & 0 deletions app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import AuthFooter from "../_components/AuthFooter";
import LoginForm from "@/components/Login/LoginForm";

export default function Login() {
return (
<div className="flex w-full flex-col gap-6">
<LoginForm />
<AuthFooter
href="/signup"
title="판다마켓이 처음이신가요?"
hrefMessage="회원가입"
/>
</div>
);
}
15 changes: 15 additions & 0 deletions app/(auth)/signup/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import SignupForm from "@/components/Signup/SignupForm";
import AuthFooter from "../_components/AuthFooter";

export default function Signup() {
return (
<div className="flex w-full flex-col gap-6">
<SignupForm />
<AuthFooter
href="/login"
title="이미 회원이신가요?"
hrefMessage="로그인"
/>
</div>
);
}
9 changes: 9 additions & 0 deletions app/(pages)/addboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import AddBoardForm from "@/components/AddBoard/AddBoardForm";

export default function AddBoard() {
return (
<div className="mt-6 flex h-full items-start justify-center px-4 sm:px-6">
<AddBoardForm />
</div>
);
}
37 changes: 37 additions & 0 deletions app/(pages)/board/[id]/page.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

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

굿굿 적절한 동적 라우팅이예요 👍👍

NextJs 라우팅을 잘 활용하고 계신데요? 😊😊

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Image from "next/image";
import Link from "next/link";
import Comment from "@/components/Comment/Comment";
import Button from "@/components/common/Button/Button";
import DetailBoard from "@/components/DetailBoard/DetailBoard";
import CommentList from "@/components/Comment/CommentList";

export default async function DetailBoardPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const articleId = Number(id);

return (
<>
<div className="flex flex-col gap-8">
<DetailBoard articleId={articleId} />
<Comment articleId={articleId} />
<CommentList articleId={articleId} />
</div>
<Link href="/board">
<Button paddingX={64} paddingY={12} className="m-auto">
목록으로 돌아가기
<Image
src="/icons/return.svg"
alt="return"
width={24}
height={24}
className="ml-1"
/>
</Button>
</Link>
</>
);
}
55 changes: 55 additions & 0 deletions app/(pages)/board/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { apiClient } from "@/lib/apiClient";

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 const INITIAL_BOARDS_VALUE = {
id: 0,
title: "",
content: "",
image: "",
likeCount: 0,
createdAt: "",
updatedAt: "",
writer: {
id: 0,
nickname: "",
},
};

export async function getBoards(params: Params) {
const { page, pageSize, orderBy, keyword } = params;
const query = new URLSearchParams({
page: String(page),
pageSize: String(pageSize),
orderBy,
keyword,
});

const response = await apiClient.get<Boards>(`/articles?${query}`);

return response.data;
}
13 changes: 13 additions & 0 deletions app/(pages)/board/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default function PagesLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex items-center justify-center">
<div className="flex w-full max-w-[1200px] min-w-[343px] flex-col gap-10 px-4 py-5 md:p-6">
{children}
</div>
</div>
);
}
25 changes: 25 additions & 0 deletions app/(pages)/board/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Metadata } from "next";
import { Suspense } from "react";
import Best from "@/components/BestBoards/Best";
import All from "@/components/AllBoards/All";
import AllLoading from "@/components/AllBoards/Loading/AllLoading";
import BestLoading from "@/components/BestBoards/Loading/BestLoading";

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

export const revalidate = 60;

export default async function Board() {
return (
<>
<Suspense fallback={<BestLoading />}>
<Best />
</Suspense>
<Suspense fallback={<AllLoading />}>
<All />
</Suspense>
</>
);
}
File renamed without changes.
14 changes: 14 additions & 0 deletions app/(pages)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Header from "@/components/common/Header/Header";

export default async function PagesLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex h-screen flex-col">
<Header />
{children}
</div>
);
}
60 changes: 60 additions & 0 deletions app/(pages)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Image from "next/image";
import Link from "next/link";
import Button from "@/components/common/Button/Button";
import HomeCardSection from "@/components/HomePage/HomeCardSection";
import HomeFooter from "@/components/HomePage/HomeFooter";

export default function HomePage() {
return (
<div className="bg-white">
<div className="mb-24">
<div className="flex w-full items-end justify-center bg-[#CFE5FF] lg:h-[540px]">
<div className="flex w-full flex-col items-center justify-center gap-20 overflow-x-hidden lg:flex-row lg:gap-0 lg:pl-2">
<div className="mt-12 flex w-full shrink-0 flex-col items-center gap-6 lg:w-[357px] lg:items-start">
<h1 className="text-bold32 text-gray700 md:text-bold40 text-center lg:text-left">
일상의 모든 물건을
<br />
거래해 보세요
</h1>
<Link href="/items">
<Button paddingX={110} paddingY={16}>
<p className="text-semi18 sm:text-semi20 shrink-0">
구경하러가기
</p>
</Button>
</Link>
</div>
<Image
src="/icons/hiPanda.svg"
alt="hi-panda"
width={730}
height={340}
className="h-auto w-full max-w-[730px] min-w-[448px]"
/>
</div>
</div>

<HomeCardSection />
</div>

<div className="flex items-end justify-center bg-[#CFE5FF] lg:h-[540px]">
<div className="mt-28 flex w-full max-w-300 flex-col items-center justify-between gap-40 px-5 lg:flex-row lg:gap-0">
<p className="text-gray700 text-bold32 sm:text-bold40 shrink-0 text-center lg:text-left">
믿을 수 있는
<br />
판다마켓 중고 거래
</p>
<Image
src="/icons/twoPandas.svg"
alt="two-pandas"
width={746}
height={397}
className="h-auto w-full max-w-[746px] min-w-[375px]"
/>
</div>
</div>

<HomeFooter />
</div>
);
}
Loading
Loading