Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: BLOG-75 게시글 렌더링방식 페이지네이션 -> 스크롤로 변경 #94

Merged
merged 1 commit into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 14 additions & 7 deletions src/app/_components/Posts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import React, { PropsWithChildren } from "react";
import React from "react";
import styles from "./index.module.scss";
import Cards from "@/app/_components/Cards";
import { Pagination } from "@/app/_components/Pagination";
// import { Pagination } from "@/app/_components/Pagination";
import { PostType } from "@/types";

interface PostsProps {
// ** pagination으로 바꿀때 주석 해제 **//

// interface PaginatedPostsProps {
// posts: PostType[];
// hasNext: boolean;
// hasPrev: boolean;
// }

interface ScrolledPostsProps {
posts: PostType[];
hasNext: boolean;
hasPrev: boolean;
}

export const Posts = ({ posts, hasNext, hasPrev }: PostsProps) => (
export const Posts = ({ posts }: ScrolledPostsProps) => (
<section className={styles["post_wrapper"]}>
<div className={styles["post_inside_wrapper"]}>
<Cards articles={posts} />
<Pagination hasNext={hasNext} hasPrev={hasPrev} />

{/* <Pagination hasNext={hasNext} hasPrev={hasPrev} /> */}
</div>
</section>
);
13 changes: 11 additions & 2 deletions src/app/_components/Sidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use client";

import {
Category,
SubCategoryList,
Expand All @@ -15,18 +16,26 @@ import styles from "./index.module.scss";
import { SidebarBtn } from "@/app/_components/Sidebar/SidebarBtn";
import { useSidebarStore } from "@/app/_components/Sidebar/index.store";
import { Menu } from "react-feather";
import { PostType } from "@/types";
import { getPublishedSubCategories } from "@/app/_components/SidebarWrapper/utils";
export interface SidebarProps {
categories: {
category: CategoryType;
subcategories: SubCategoryType[];
}[];
posts: PostType[];
}
const Sidebar = ({ categories }: SidebarProps) => {
const Sidebar = ({ categories, posts }: SidebarProps) => {
const [isSidebarOn, setIsSidebarOn] = useSidebarStore((state) => [
state.isSidebarOn,
state.setIsSidebarOn,
]);

const publishedSubCategories = getPublishedSubCategories({
posts,
categories,
});

return (
<>
<Button
Expand All @@ -48,7 +57,7 @@ const Sidebar = ({ categories }: SidebarProps) => {
<div className={styles.sidebar}>
<StorybookSidebar linkToPosts={<Link href="/">전체 보기</Link>}>
<ul>
{categories.map((el, i) => (
{publishedSubCategories.map((el, i) => (
<li key={i}>
<Category
CategoryLink={
Expand Down
7 changes: 6 additions & 1 deletion src/app/_components/SidebarWrapper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import { getCategories } from "@/app/api/dato/getCategories";

import { formatSidebarData } from "@/app/_components/SidebarWrapper/utils";
import dynamic from "next/dynamic";
import { getPosts } from "@/app/api/dato/getPosts";

const Sidebar = dynamic(() => import("@/app/_components/Sidebar"), {
ssr: false,
});

export const SidebarWrapper = async () => {
const { allArticles: articles } = await getPosts<{
allArticles: PostType[];
}>();

const { allArticles: _subCategories } = await getCategories<{
allArticles: Pick<PostType, "category" | "_createdAt">[];
}>();
Expand All @@ -23,5 +28,5 @@ export const SidebarWrapper = async () => {

const transformedCategories = formatSidebarData(subCategories);

return <Sidebar categories={transformedCategories} />;
return <Sidebar posts={articles} categories={transformedCategories} />;
};
46 changes: 1 addition & 45 deletions src/app/_components/SidebarWrapper/utils/index.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1 @@
import { devideCategoryObject } from "@/utils/getCategoryLink";
import { CategoryType, LinkType } from "junyeol-components";
import Link from "next/link";

export const formatSidebarData = (
input: {
category: Partial<Record<CategoryType, string>>;
_createdAt: string;
}[],
) => {
const result: {
[key: string]: {
category: CategoryType;
subcategories: { subCategoryLink: LinkType; createdAt: string }[];
};
} = {};
// 입력 배열을 순회하면서 카테고리와 서브카테고리를 추출하고 그룹화합니다.
input.forEach((item) => {
const createdAt = item._createdAt;
const { mainCategory, subCategory } = devideCategoryObject(item.category);
const categoryLink = `/posts/${mainCategory}/${subCategory}`;

const subCategoryLink = <Link href={categoryLink}>{subCategory}</Link>;

if (!result[mainCategory]) {
result[mainCategory] = {
category: mainCategory,
subcategories: [],
};
}
// 중복 제거
if (
!result[mainCategory].subcategories.some(
(sub) => sub.subCategoryLink.props.href === subCategoryLink.props.href,
)
) {
result[mainCategory].subcategories.push({
subCategoryLink,
createdAt,
});
}
});

return Object.values(result);
};
export * from "./sidebar";
81 changes: 81 additions & 0 deletions src/app/_components/SidebarWrapper/utils/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { PostType } from "@/types";
import { devideCategoryObject } from "@/utils/getCategoryLink";
import { CategoryType, LinkType, SubCategoryType } from "junyeol-components";
import Link from "next/link";

export const formatSidebarData = (
input: {
category: Partial<Record<CategoryType, string>>;
_createdAt: string;
}[],
) => {
const result: {
[key: string]: {
category: CategoryType;
subcategories: { subCategoryLink: LinkType; createdAt: string }[];
};
} = {};
// 입력 배열을 순회하면서 카테고리와 서브카테고리를 추출하고 그룹화합니다.
input.forEach((item) => {
const createdAt = item._createdAt;
const { mainCategory, subCategory } = devideCategoryObject(item.category);
const categoryLink = `/posts/${mainCategory}/${subCategory}`;

const subCategoryLink = <Link href={categoryLink}>{subCategory}</Link>;

if (!result[mainCategory]) {
result[mainCategory] = {
category: mainCategory,
subcategories: [],
};
}
// 중복 제거
if (
!result[mainCategory].subcategories.some(
(sub) => sub.subCategoryLink.props.href === subCategoryLink.props.href,
)
) {
result[mainCategory].subcategories.push({
subCategoryLink,
createdAt,
});
}
});

return Object.values(result);
};

/** 현재 퍼블리시 된 게시글들의 subCategory, side바에 게시글이 없는 subCategory를 보여주지 않기 위함. */
export const getPublishedSubCategories = ({
posts,
categories,
}: {
posts: PostType[];
categories: {
category: CategoryType;
subcategories: SubCategoryType[];
}[];
}) => {
const publishedSubCategories = posts
.map((post) => post.category.category)
.map((category) => Object.values(category)[0]);

const allPublishedCategories: {
category: CategoryType;
subcategories: SubCategoryType[];
}[] = categories.map(({ category, subcategories }) => {
return {
category,
subcategories: subcategories.filter((e) => {
console.log(
!!publishedSubCategories.includes(e.subCategoryLink.props.children),
);
return !!publishedSubCategories.includes(
e.subCategoryLink.props.children,
);
}),
};
});

return allPublishedCategories;
};
14 changes: 8 additions & 6 deletions src/app/posts/[category]/[subCategory]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,20 @@ export default async function PostsPageFilteredBySubCategory({
? !!article.category.category[category]?.includes(subCategory)
: false,
);
// ** pagination으로 바꿀때 주석 해제 **//

const { paginatedArticles, hasNext, hasPrev } = paginatePosts({
posts: filteredArticles,
currentPage,
pageSize,
});
// const { paginatedArticles, hasNext, hasPrev } = paginatePosts({
// posts: filteredArticles,
// currentPage,
// pageSize,
// });

return (
<>
<h2 className={styles.heading}>{`${subCategory}`}</h2>

<Posts posts={paginatedArticles} hasNext={hasNext} hasPrev={hasPrev} />
{/* <Posts posts={paginatedArticles} hasNext={hasNext} hasPrev={hasPrev} /> */}
<Posts posts={filteredArticles} />
</>
);
}
Expand Down
18 changes: 10 additions & 8 deletions src/app/posts/[category]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,29 @@ export default async function PostsPageFilteredByCategory({
searchParams,
}: PostsPageFilteredByCategory) {
const { category } = params;
const currentPage = Number(searchParams.currentPage);
const pageSize = Number(searchParams.pageSize);
// const currentPage = Number(searchParams.currentPage);
// const pageSize = Number(searchParams.pageSize);
const { allArticles: articles } = await getPosts<{
allArticles: PostType[];
}>();

const filteredArticles = articles.filter(
(article) => !!article.category.category[category],
);
// ** pagination으로 바꿀때 주석 해제 **//

const { paginatedArticles, hasNext, hasPrev } = paginatePosts({
posts: filteredArticles,
currentPage,
pageSize,
});
// const { paginatedArticles, hasNext, hasPrev } = paginatePosts({
// posts: filteredArticles,
// currentPage,
// pageSize,
// });

return (
<>
<h2 className={styles.heading}>{`${category}`}</h2>

<Posts posts={paginatedArticles} hasNext={hasNext} hasPrev={hasPrev} />
{/* <Posts posts={paginatedArticles} hasNext={hasNext} hasPrev={hasPrev} /> */}
<Posts posts={filteredArticles} />
</>
);
}
Expand Down
26 changes: 17 additions & 9 deletions src/app/posts/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,38 @@ import { Metadata } from "next";
import { PostType, SearchParamsType } from "@/types";
import { Posts } from "@/app/_components/Posts";
import styles from "./page.module.scss";
import { paginatePosts } from "@/libs/paginate";
// ** pagination으로 바꿀때 주석 해제 **//

// import { paginatePosts } from "@/libs/paginate";

export const metadata: Metadata = {
title: "류준열 기술 블로그",
description: "개발자 류준열의 기술 블로그",
};

export default async function Home({ searchParams }: SearchParamsType) {
const currentPage = Number(searchParams.currentPage);
const pageSize = Number(searchParams.pageSize);
// ** pagination으로 바꿀때 주석 해제 **//

// const currentPage = Number(searchParams.currentPage);
// const pageSize = Number(searchParams.pageSize);

const { allArticles: articles } = await getPosts<{
allArticles: PostType[];
}>();
// ** pagination으로 바꿀때 주석 해제 **//

// const { paginatedArticles, hasNext, hasPrev } = paginatePosts({
// posts: articles,
// currentPage,
// pageSize,
// });

const { paginatedArticles, hasNext, hasPrev } = paginatePosts({
posts: articles,
currentPage,
pageSize,
});
return (
<>
<h2 className={styles.heading}>{`게시글 전체 보기`}</h2>
<Posts posts={paginatedArticles} hasNext={hasNext} hasPrev={hasPrev} />

{/* <Posts posts={paginatedArticles} hasNext={hasNext} hasPrev={hasPrev} /> */}
<Posts posts={articles} />
</>
);
}
29 changes: 15 additions & 14 deletions src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,27 @@ import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(request: NextRequest) {
const PAGE_SIZE = "10";
const CURRENT_PAGE = "1";
const pageSize = request.nextUrl.searchParams.get("pageSize");
const currentPage = request.nextUrl.searchParams.get("currentPage");
// ** pagination으로 바꿀때 주석 해제 **//
// const PAGE_SIZE = "10";
// const CURRENT_PAGE = "1";
// const pageSize = request.nextUrl.searchParams.get("pageSize");
// const currentPage = request.nextUrl.searchParams.get("currentPage");

if (request.nextUrl.pathname === "/") {
if (pageSize && currentPage) return;
// if (pageSize && currentPage) return;
const url = request.nextUrl.clone();
url.pathname = "/posts";
url.searchParams.set("pageSize", PAGE_SIZE);
url.searchParams.set("currentPage", CURRENT_PAGE);
// url.searchParams.set("pageSize", PAGE_SIZE);
// url.searchParams.set("currentPage", CURRENT_PAGE);
return NextResponse.redirect(url);
}

if (request.nextUrl.pathname.startsWith("/posts")) {
if (pageSize && currentPage) return;
const url = request.nextUrl.clone();
url.searchParams.set("pageSize", PAGE_SIZE);
url.searchParams.set("currentPage", CURRENT_PAGE);
return NextResponse.redirect(url);
}
// if (request.nextUrl.pathname.startsWith("/posts")) {
// if (pageSize && currentPage) return;
// const url = request.nextUrl.clone();
// url.searchParams.set("pageSize", PAGE_SIZE);
// url.searchParams.set("currentPage", CURRENT_PAGE);
// return NextResponse.redirect(url);
// }
return;
}
Loading