Skip to content
Merged
Binary file added public/icons/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/app/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ const myFont = localFont({
src: "../shared/fonts/PretendardVariable.woff2",
});

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
export const metadata = {
title: "찰딱",
description: "중고거래 플랫폼 찰딱",
};

export default function RootLayout({
Expand Down
2 changes: 1 addition & 1 deletion src/entities/post/model/constants/api.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const POST_PAGE_SIZE = 10;
export const POST_PAGE_SIZE = 12;
32 changes: 18 additions & 14 deletions src/entities/post/ui/list/PostList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,24 @@ export default function PostList({
/>
</div>

<div className="grid grid-cols-2 gap-[15px] xl:grid-cols-3">
{posts.map((post, i) =>
i === posts.length - 1 ? (
<div ref={lastRef} key={post.postingId}>
<PostCard {...post} />
</div>
) : (
<PostCard key={post.postingId} {...post} />
),
)}
</div>

{isFetchingNextPage && (
<p className="mt-4 text-center text-gray-400">불러오는 중...</p>
{posts.length === 0 && !isFetchingNextPage ? (
<div className="flex flex-col items-center justify-center py-20 text-gray-400">
<span className="text-[16px]">
해당 카테고리에 등록된 게시물이 없어요.
</span>
</div>
) : (
<div className="grid grid-cols-2 gap-[15px] xl:grid-cols-3">
{posts.map((post, i) =>
i === posts.length - 1 ? (
<div ref={lastRef} key={post.postingId}>
<PostCard {...post} />
</div>
) : (
<PostCard key={post.postingId} {...post} />
),
)}
</div>
)}
</section>
);
Expand Down
58 changes: 34 additions & 24 deletions src/entities/user/ui/card/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,32 @@ const Profile = ({
const { logout } = useAuthStore();
const { openModal, closeModal } = useModalStore();

const handleLogout = async () => {
const res = await fetch("/api/auth/logout", {
method: "POST",
credentials: "include",
});

if (res.ok) {
router.push("/login");
router.refresh();
logout();
openModal("normal", {
message: "로그아웃이 완료되었습니다.",
onClick: () => {
closeModal();
},
});
} else {
openModal("normal", {
message: "로그아웃에 실패했습니다.",
onClick: () => {
closeModal();
},
});
}
};

return (
<article className="flex h-[556px] w-[335px] shrink-0 items-center justify-center rounded-lg border border-[#353542] bg-[#252530] px-5 py-7 md:h-[601px] md:w-[509px] md:px-7 xl:h-[753px] xl:w-[340px] xl:px-5 xl:pt-10">
<div className="flex h-full w-full flex-col items-center justify-between">
Expand Down Expand Up @@ -75,7 +101,9 @@ const Profile = ({
</div>

<div className="w-full text-center">
<dd className="text-lg font-semibold text-[#F1F1F5]">{category}</dd>
<dd className="text-lg font-semibold text-[#F1F1F5]">
{category || "—"}
</dd>
<dt className="mt-1 text-sm text-[#9FA6B2]">관심 카테고리</dt>
</div>

Expand All @@ -87,30 +115,12 @@ const Profile = ({
<Button
variant="tertiary"
className="w-full!"
onClick={async () => {
const res = await fetch("/api/auth/logout", {
method: "POST",
credentials: "include",
onClick={() => {
openModal("confirm", {
message: "정말 로그아웃하시겠습니까?",
onConfirm: handleLogout,
onCancel: closeModal,
});

if (res.ok) {
openModal("normal", {
message: "로그아웃이 완료되었습니다.",
onClick: () => {
closeModal();
logout();
router.push("/login");
router.refresh();
},
});
} else {
openModal("normal", {
message: "로그아웃에 실패했습니다.",
onClick: () => {
closeModal();
},
});
}
}}
>
로그아웃
Expand Down
3 changes: 1 addition & 2 deletions src/features/auth/ui/LoginForm/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ export const LoginForm = ({ onSuccess, onError }: LoginFormProps) => {
setAccessToken(res.accessToken);
onSuccess?.();
} catch (error) {
onError?.("로그인에 실패하였습니다.\n이메일과 비밀번호를 확인해주세요.");
} finally {
setIsLoading(false);
onError?.("로그인에 실패하였습니다.\n이메일과 비밀번호를 확인해주세요.");
}
};

Expand Down
4 changes: 3 additions & 1 deletion src/widgets/header/ui/HeaderDesktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ const HeaderDesktop = ({
return (
<div className="hidden w-full items-center justify-between md:flex">
<div className="text-white">
<Link href="/">찰딱</Link>
<Link href="/">
<img src="/icons/logo.png" className="h-15 w-15" />
</Link>
</div>

<div className="flex items-center">
Expand Down
12 changes: 6 additions & 6 deletions src/widgets/header/ui/HeaderMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,24 @@ interface HeaderMobileProps {

const HeaderMobile = ({ setShowSearch, onOpenMenu }: HeaderMobileProps) => {
return (
<div className="flex w-full items-center justify-between md:hidden">
<div className="relative flex w-full items-center justify-between md:hidden">
<button
aria-label="menu"
type="button"
className="cursor-pointer"
className="z-10 cursor-pointer"
onClick={onOpenMenu}
>
<img src="/icons/menu.svg" alt="menu" className="h-[24px] w-[24px]" />
</button>

<div className="flex-1 text-center text-white">
<Link href="/">찰딱</Link>
</div>
<Link href="/" className="absolute left-1/2 -translate-x-1/2 text-white">
<img src="/icons/logo.png" className="h-10 w-10" />
</Link>

<button
aria-label="search-button"
type="button"
className="cursor-pointer"
className="z-10 cursor-pointer"
onClick={() => setShowSearch(true)}
>
<img
Expand Down
59 changes: 36 additions & 23 deletions src/widgets/header/ui/MobileSideMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,33 @@ export default function MobileSideMenu({
handleClose();
};

const handleLogout = async () => {
const res = await fetch("/api/auth/logout", {
method: "POST",
credentials: "include",
});

if (res.ok) {
handleClose();
router.push("/login");
router.refresh();
logout();
openModal("normal", {
message: "로그아웃이 완료되었습니다.",
onClick: () => {
closeModal();
},
});
} else {
openModal("normal", {
message: "로그아웃에 실패했습니다.",
onClick: () => {
closeModal();
},
});
}
};

return (
<div>
<div
Expand Down Expand Up @@ -119,30 +146,16 @@ export default function MobileSideMenu({
<li>
<button
type="button"
onClick={async () => {
const res = await fetch("/api/auth/logout", {
method: "POST",
credentials: "include",
onClick={() => {
openModal("confirm", {
message: "정말 로그아웃하시겠습니까?",
onConfirm: async () => {
await handleLogout();
},
onCancel: () => {
closeModal();
},
});
handleClose();
if (res.ok) {
openModal("normal", {
message: "로그아웃이 완료되었습니다.",
onClick: () => {
closeModal();
logout();
router.push("/login");
router.refresh();
},
});
} else {
openModal("normal", {
message: "로그아웃에 실패했습니다.",
onClick: () => {
closeModal();
},
});
}
}}
className="w-full px-4 py-3 text-left text-red-400 hover:bg-white/10"
>
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/mypage/ui/Client/MyPage.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export default function MyPageClient({ defaultTab }: { defaultTab: string }) {
<Profile {...userProfile!} onEdit={openEditProfileModal} />
)}

<section className="flex flex-col gap-[30px]">
<section className="flex w-full flex-col gap-[30px]">
<Tab
options={options}
selected={selectedTab}
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/postDetail/ui/PostDetailSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export function PostDetailSection({ post }: { post: PostDetail }) {
{seller?.nickname || "판매자"}
</span>
</div>
<div className="mx-4 h-px bg-gray-600 xl:hidden" />
<div className="h-px bg-gray-600 xl:hidden" />
</div>

<div className="flex flex-col justify-between gap-5 py-6 md:pt-8 xl:w-1/2 xl:pt-0 xl:pb-[88px]">
Expand Down
41 changes: 26 additions & 15 deletions src/widgets/postDetail/ui/SellerPostsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function SellerPostsSection({
fetchNextPage,
hasNextPage,
isFetchingNextPage,
isLoading,
} = useInfiniteQuery({
queryKey: ["sellerPosts", sellerId, postingId],
queryFn: ({ pageParam = 1 }) =>
Expand All @@ -33,6 +34,8 @@ export function SellerPostsSection({
initialPageParam: 1,
});

const sellerPosts = sellerPostsData?.pages.flatMap((p) => p.data) ?? [];

const lastPostRef = useInfiniteScroll(
() => {
if (hasNextPage && !isFetchingNextPage) fetchNextPage();
Expand All @@ -41,24 +44,32 @@ export function SellerPostsSection({
!!hasNextPage,
);

const sellerPosts = sellerPostsData?.pages.flatMap((p) => p.data) ?? [];

return (
<section className="mx-4 my-2 md:mx-10 xl:mx-16 xl:my-10">
<div className="mx-4 h-px bg-gray-600" />
<section className="mx-4 mb-2 md:mx-10 xl:mx-16 xl:mb-10">
<div className="h-px bg-gray-600" />
<h1 className="my-6 text-2xl font-bold xl:text-3xl">판매한 상품</h1>

<div className="grid w-full grid-cols-2 gap-x-4 gap-y-8 md:grid-cols-4 xl:grid-cols-5">
{sellerPosts.map((item, idx) =>
idx === sellerPosts.length - 1 ? (
<div ref={lastPostRef} key={item.postingId}>
<PostCard {...item} />
</div>
) : (
<PostCard key={item.postingId} {...item} />
),
)}
</div>
{isLoading ? (
<div className="flex w-full flex-col items-center justify-center py-10 text-gray-400">
<p className="text-base md:text-lg">로딩 중...</p>
</div>
) : sellerPosts.length === 0 ? (
<div className="flex w-full flex-col items-center justify-center py-10 text-gray-400">
<p className="text-base md:text-lg">판매한 상품이 없습니다.</p>
</div>
) : (
<div className="grid w-full grid-cols-2 gap-x-4 gap-y-8 md:grid-cols-4 xl:grid-cols-5">
{sellerPosts.map((item, idx) =>
idx === sellerPosts.length - 1 ? (
<div ref={lastPostRef} key={item.postingId}>
<PostCard {...item} />
</div>
) : (
<PostCard key={item.postingId} {...item} />
),
)}
</div>
)}
</section>
);
}