[common/features] feat: 콘텐츠 페이지 생성

This commit is contained in:
2025-07-03 15:17:56 +09:00
parent 1555c60341
commit 5376d21901
8 changed files with 78 additions and 35 deletions
@@ -1,30 +0,0 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import { MenuApi } from "@/entities/menu";
import { ENDPOINT } from "@/shared/config";
import { getCookie, useMenuStore } from "@/shared/lib";
import { PageLayout } from "@/shared/ui/page-layout";
export default function PostLayout({
children,
}: {
children: React.ReactNode;
}) {
const menuCd = getCookie("menu-code-key");
const bbsInfo = useMenuStore((state) => state.bbsInfo);
const { data } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.MENUS, menuCd],
queryFn: () => MenuApi.getMenuInfo(menuCd!),
enabled: !!menuCd,
});
const menuPaths = data?.menuPath?.split(">").map((path) => path.trim());
return (
<PageLayout title={bbsInfo?.bbsNm ?? ""} menuPaths={menuPaths ?? []}>
{children}
</PageLayout>
);
}
@@ -0,0 +1,10 @@
import { ContentsPage as VContentsPage } from "@/pages/contents";
export default async function ContentsPage({
params,
}: {
params: Promise<{ contsSn: string }>;
}) {
const { contsSn } = await params;
return <VContentsPage contsSn={parseInt(contsSn)} />;
}
@@ -1,10 +1,12 @@
"use client";
import { usePathname, useRouter } from "next/navigation";
import { useQueryClient } from "@tanstack/react-query";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { BaseLayout } from "@common/components";
import type { MenuRole } from "@/entities/menu";
import { useMenuStore } from "@/shared/lib";
import { MenuApi, type MenuRole } from "@/entities/menu";
import { ENDPOINT } from "@/shared/config";
import { getCookie, useMenuStore } from "@/shared/lib";
import { PageLayout } from "@/shared/ui/page-layout";
export default function WithBaseLayout({
children,
@@ -14,6 +16,16 @@ export default function WithBaseLayout({
const router = useRouter();
const pathname = usePathname();
const queryClient = useQueryClient();
const bbsInfo = useMenuStore((state) => state.bbsInfo);
const menuCd = getCookie("menu-code-key");
const { data } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.MENUS, menuCd],
queryFn: () => MenuApi.getMenuInfo(menuCd!),
enabled: !!menuCd,
});
const menuPaths = data?.menuPath?.split(">").map((path) => path.trim());
const setCurrentMenuInfo = useMenuStore((state) => state.setCurrentMenuInfo);
@@ -28,7 +40,9 @@ export default function WithBaseLayout({
currentPath={pathname ?? ""}
handleMenuClick={handleMenuClick}
>
{children}
<PageLayout title={bbsInfo?.bbsNm ?? ""} menuPaths={menuPaths ?? []}>
{children}
</PageLayout>
</BaseLayout>
);
}
@@ -19,6 +19,15 @@ export class ContentsApiService implements ContentsService {
return response.data;
}
public async getLatestApprovedContentsInfo(
contsSn: number,
): Promise<ContentsDetail> {
const response = await client.get<ContentsDetail>(
`${ENDPOINT.CMS_SERVICE.CONTENTS}/${contsSn}`,
);
return response.data;
}
public async getContentsVersionList(
params: ContentsVersionParams,
): Promise<ContentsVersionList> {
@@ -81,6 +81,7 @@ export type ContentsVersionList = PageableList<ContentsVersion>;
export interface ContentsService {
getContentsList(params: ContentsParams): Promise<ContentsList>;
getLatestApprovedContentsInfo(contsSn: number): Promise<ContentsDetail>;
getContentsVersionList(
params: ContentsVersionParams,
): Promise<ContentsVersionList>;
@@ -45,7 +45,7 @@ const MenuWrapper = ({ children }: { children: React.ReactNode }) => {
if (pageMenuAuthority?.length)
setPageMenuAuthority(pageMenuAuthority[0]!);
})();
}, []);
}, [pathname]);
useEffect(() => {
if (!pageMenuAuthority) return;
@@ -0,0 +1 @@
export { ContentsPage } from "./ui/contents-page";
@@ -0,0 +1,38 @@
"use client";
import { useEffect, useRef } from "react";
import { useQuery } from "@tanstack/react-query";
import { ContentsApi } from "@/entities/content";
import { ENDPOINT } from "@/shared/config";
function ContentsPage({ contsSn }: { contsSn: number }) {
const shadowRootRef = useRef<HTMLDivElement>(null);
const { data: contentsDetail } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS, contsSn],
queryFn: () => ContentsApi.getLatestApprovedContentsInfo(contsSn),
enabled: !!contsSn,
});
useEffect(() => {
if (!shadowRootRef.current || !contentsDetail?.contsCn) return;
const shadowRoot = shadowRootRef.current.attachShadow({ mode: "open" });
const styleElement = document.createElement("style");
styleElement.textContent = `div { font-size: 16px; line-height: 1.5; }`;
shadowRoot.appendChild(styleElement);
const contentElement = document.createElement("div");
contentElement.innerHTML = contentsDetail.contsCn;
shadowRoot.appendChild(contentElement);
}, [contentsDetail?.contsCn]);
return (
<div className="card card-border !mt-6 !p-6">
<div ref={shadowRootRef} />
</div>
);
}
export { ContentsPage };