@@ -111,7 +171,7 @@ const ThumbImage = ({ atflCd, pstNo, thumbRefs }: ThumbImageProps) => {
);
return (
-
{isFetched ? (
- bbsType === "BBSIMAGE" ? (
-
- ) : (
-
- )
+
) : (
)}
diff --git a/apps/common/features/src/widgets/post/ui/post.tsx b/apps/common/features/src/widgets/post/ui/post.tsx
index 379bcdd38..44e549a70 100644
--- a/apps/common/features/src/widgets/post/ui/post.tsx
+++ b/apps/common/features/src/widgets/post/ui/post.tsx
@@ -29,14 +29,17 @@ function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
const { data: postData } = useQuery({
queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, pstNo],
- queryFn: () => PostApi.getPostInfo(bbsId, pstNo),
+ queryFn: () => PostApi.getPostInfo(parseInt(bbsId), parseInt(pstNo)),
});
const { data: downloadResponse, isFetching } = useQuery({
queryKey: [ENDPOINT.ATTACH_SERVICE.DOWNLOAD, postData?.atflCd],
queryFn: () =>
AttachmentApi.downloadAttachmentByAtflCd(postData?.atflCd as string),
- enabled: !!postData?.atflCd && bbsInfo?.bbsTypeCd !== "BBSIMAGE",
+ enabled:
+ !!postData?.atflCd &&
+ bbsInfo?.bbsTypeCd !== "BBSIMAGE" &&
+ bbsInfo?.bbsTypeCd !== "BBSMOVIE",
});
const { data: imageUrl, isLoading } = useQuery({
@@ -46,8 +49,25 @@ function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
enabled: !!postData?.atflCd,
});
+ const { data: videoAttachment } = useQuery({
+ queryKey: [ENDPOINT.ATTACH_SERVICE.ATTACHMENTS, postData?.atflCd],
+ queryFn: () => AttachmentApi.getAttachmentsInfo(postData?.atflCd as string),
+ select: (data) => data[0],
+ enabled: !!postData?.atflCd && bbsInfo?.bbsTypeCd === "BBSMOVIE",
+ });
+
+ const { data: videoUrl } = useQuery({
+ queryKey: [ENDPOINT.ATTACH_SERVICE.STREAM_VIDEO, videoAttachment?.atflId],
+ queryFn: () =>
+ AttachmentApi.getStreamVideoUrlByAtflId(
+ videoAttachment?.atflId as string,
+ ),
+ enabled: !!videoAttachment?.atflId,
+ });
+
const { mutate: deletePost } = useMutation({
- mutationFn: (pstPswd: string) => PostApi.deletePost(bbsId, pstNo, pstPswd),
+ mutationFn: (pstPswd: string) =>
+ PostApi.deletePost(parseInt(bbsId), parseInt(pstNo), pstPswd),
onSuccess: () => {
alert("삭제되었습니다.", router.back);
},
@@ -58,7 +78,8 @@ function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
if (userInfo?.userUnqId) {
pstPswd = userInfo?.userUnqId;
} else {
- pstPswd = await prompt("비밀번호를 입력해주세요.");
+ const { resolved, value } = await prompt("비밀번호를 입력해주세요.");
+ if (resolved) pstPswd = value ?? "";
}
deletePost(pstPswd);
};
@@ -142,6 +163,11 @@ function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
)}
>
)}
+ {bbsInfo?.bbsTypeCd === "BBSMOVIE" && (
+
+
+
+ )}
{postData?.pstCn ?? ""}
diff --git a/apps/common/features/src/widgets/post/ui/with-preview-file-uploader.tsx b/apps/common/features/src/widgets/post/ui/with-preview-file-uploader.tsx
index 618108017..9496280e6 100644
--- a/apps/common/features/src/widgets/post/ui/with-preview-file-uploader.tsx
+++ b/apps/common/features/src/widgets/post/ui/with-preview-file-uploader.tsx
@@ -50,7 +50,7 @@ function WithPreviewFileUploader
({
imageUrl = await AttachmentApi.getImageUrlByAtflId(atflId);
}
if (bbsInfo?.bbsTypeCd === "BBSMOVIE") {
- imageUrl = await AttachmentApi.getMovieThumbnailUrl(atflId);
+ imageUrl = await AttachmentApi.getMovieThumbnailUrlByAtflId(atflId);
}
setThumbnailUrl(imageUrl);
}
diff --git a/apps/cs/app/(with-base-layout)/bbs/(post)/bbsfaq/[bbsId]/[pstNo]/page.tsx b/apps/cs/app/(with-base-layout)/bbs/(post)/bbsfaq/[bbsId]/[pstNo]/page.tsx
new file mode 100644
index 000000000..7c8d6ee86
--- /dev/null
+++ b/apps/cs/app/(with-base-layout)/bbs/(post)/bbsfaq/[bbsId]/[pstNo]/page.tsx
@@ -0,0 +1,10 @@
+import { ModifyPage } from "@/pages/(post)/faq";
+
+export default async function PstBbsFaqPostModifyPage({
+ params,
+}: {
+ params: Promise<{ bbsId: string; pstNo: string }>;
+}) {
+ const { bbsId, pstNo } = await params;
+ return ;
+}
diff --git a/apps/cs/app/(with-base-layout)/bbs/(post)/bbsfaq/[bbsId]/page.tsx b/apps/cs/app/(with-base-layout)/bbs/(post)/bbsfaq/[bbsId]/page.tsx
new file mode 100644
index 000000000..12fe535a5
--- /dev/null
+++ b/apps/cs/app/(with-base-layout)/bbs/(post)/bbsfaq/[bbsId]/page.tsx
@@ -0,0 +1,10 @@
+import { FaqPage } from "@/pages/(post)/faq";
+
+export default async function PstBbsFaqPage({
+ params,
+}: {
+ params: Promise<{ bbsId: string }>;
+}) {
+ const { bbsId } = await params;
+ return ;
+}
diff --git a/apps/cs/app/(with-base-layout)/bbs/(post)/bbsfaq/[bbsId]/register/page.tsx b/apps/cs/app/(with-base-layout)/bbs/(post)/bbsfaq/[bbsId]/register/page.tsx
new file mode 100644
index 000000000..e768a48db
--- /dev/null
+++ b/apps/cs/app/(with-base-layout)/bbs/(post)/bbsfaq/[bbsId]/register/page.tsx
@@ -0,0 +1,10 @@
+import { CreatePage } from "@/pages/(post)/faq";
+
+export default async function PstBbsFaqRegisterPage({
+ params,
+}: {
+ params: Promise<{ bbsId: string }>;
+}) {
+ const { bbsId } = await params;
+ return ;
+}
diff --git a/apps/cs/app/(with-base-layout)/recent/page.tsx b/apps/cs/app/(with-base-layout)/recent/page.tsx
new file mode 100644
index 000000000..02ed5aba7
--- /dev/null
+++ b/apps/cs/app/(with-base-layout)/recent/page.tsx
@@ -0,0 +1,2 @@
+import { RecentPage } from "@/pages/recent";
+export default RecentPage;
diff --git a/apps/cs/src/app/providers/app-provider.tsx b/apps/cs/src/app/providers/app-provider.tsx
index 713bc172c..7732d34ba 100644
--- a/apps/cs/src/app/providers/app-provider.tsx
+++ b/apps/cs/src/app/providers/app-provider.tsx
@@ -6,8 +6,9 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ConfirmProvider } from "@frontend-opensource/use-react-hooks";
import { AuthWrapper } from "@/entities/auth";
import { MenuWrapper } from "@/entities/menu";
-import { StoreProvider } from "@/shared/providers";
+import { PromptProvider, StoreProvider } from "@/shared/providers";
import { AlertDialog } from "@/shared/ui/alert-dialog";
+import { PromptDialog } from "@/shared/ui/prompt-dialog";
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
import { initializeNextClientConfig } from "@common/config";
@@ -19,17 +20,23 @@ const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
return (
-
-
-
-
- {children}
-
-
-
-
-
-
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+
);
diff --git a/apps/cs/src/entities/board/api/board-service.ts b/apps/cs/src/entities/board/api/board-service.ts
index 150ff677a..dc474b3ad 100644
--- a/apps/cs/src/entities/board/api/board-service.ts
+++ b/apps/cs/src/entities/board/api/board-service.ts
@@ -11,7 +11,7 @@ import type {
} from "../model/board-interface";
export class BoardApiService implements BoardService {
- public async getBoardList(params: BoardParams): Promise {
+ public async getBoardList(params?: BoardParams): Promise {
const response = await client.get(
`${ENDPOINT.BOARD_SERVICE.BBS}`,
{ params },
diff --git a/apps/cs/src/entities/post/api/post-service.ts b/apps/cs/src/entities/post/api/post-service.ts
index a07fc4d2a..471da5d81 100644
--- a/apps/cs/src/entities/post/api/post-service.ts
+++ b/apps/cs/src/entities/post/api/post-service.ts
@@ -4,29 +4,43 @@ import {
postFormSchema,
postUpdateFormSchema,
type Post,
+ type MovePost,
+ type DeletePost,
type PostInfo,
type PostList,
+ type RecentPostList,
type PostParams,
- type PostService,
+ type RecentPostParams,
type PostFormData,
type PostUpdateFormData,
+ type PostService,
} from "../model/post-interface";
export class PostApiService implements PostService {
public async getPostList(
- bbsId: string,
+ bbsId: number,
params: PostParams,
): Promise {
const response = await client.get(
- `${ENDPOINT.BOARD_SERVICE.POSTS_USER}/${bbsId}`,
+ `${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}`,
{ params },
);
return response.data;
}
- public async getPostInfo(bbsId: string, pstNo: string): Promise {
+ public async getRecentPostList(
+ params?: RecentPostParams,
+ ): Promise {
+ const response = await client.get(
+ `${ENDPOINT.BOARD_SERVICE.POSTS}/recentPosts`,
+ { params },
+ );
+ return response.data;
+ }
+
+ public async getPostInfo(bbsId: number, pstNo: number): Promise {
const response = await client.get(
- `${ENDPOINT.BOARD_SERVICE.POSTS_USER}/${bbsId}/${pstNo}`,
+ `${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`,
);
return response.data;
}
@@ -34,34 +48,49 @@ export class PostApiService implements PostService {
public async createPost(data: PostFormData): Promise {
const validatedData = postFormSchema.parse(data);
const response = await client.post(
- `${ENDPOINT.BOARD_SERVICE.POSTS_USER}`,
+ `${ENDPOINT.BOARD_SERVICE.POSTS}`,
validatedData,
);
return response.data;
}
public async updatePost(
- bbsId: string,
- pstNo: string,
+ bbsId: number,
+ pstNo: number,
data: PostUpdateFormData,
): Promise {
const validatedData = postUpdateFormSchema.parse(data);
const response = await client.put(
- `${ENDPOINT.BOARD_SERVICE.POSTS_USER}/${bbsId}/${pstNo}`,
+ `${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`,
validatedData,
);
return response.data;
}
public async deletePost(
- bbsId: string,
- pstNo: string,
- pstPswd?: string,
+ bbsId: number,
+ pstNo: number,
+ delRsn?: string,
): Promise {
- await client.delete(
- `${ENDPOINT.BOARD_SERVICE.POSTS_USER}/${bbsId}/${pstNo}`,
- { params: { pstPswd } },
- );
+ await client.delete(`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`, {
+ params: { delRsn },
+ });
+ }
+
+ public async softDeletePost(data: DeletePost[]): Promise {
+ await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/softDeleteSels`, data);
+ }
+
+ public async hardDeletePost(data: DeletePost[]): Promise {
+ await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/hardDeleteSels`, data);
+ }
+
+ public async movePost(data: MovePost[]): Promise {
+ await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/movePstByBbsId`, data);
+ }
+
+ public async restorePost(data: DeletePost[]): Promise {
+ await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/restoreSels`, data);
}
}
diff --git a/apps/cs/src/entities/post/index.ts b/apps/cs/src/entities/post/index.ts
index d2b94ba84..0e19b54e2 100644
--- a/apps/cs/src/entities/post/index.ts
+++ b/apps/cs/src/entities/post/index.ts
@@ -3,9 +3,13 @@ export {
postFormSchema,
postUpdateFormSchema,
type Post,
+ type RecentPost,
+ type MovePost,
+ type DeletePost,
type PostList,
type PostParams,
- type PostService,
+ type RecentPostParams,
type PostFormData,
type PostUpdateFormData,
+ type PostService,
} from "./model/post-interface";
diff --git a/apps/cs/src/entities/post/model/post-interface.ts b/apps/cs/src/entities/post/model/post-interface.ts
index 9cb97ef92..86e27afd5 100644
--- a/apps/cs/src/entities/post/model/post-interface.ts
+++ b/apps/cs/src/entities/post/model/post-interface.ts
@@ -8,13 +8,24 @@ export interface PostParams extends PageableParams {
upndFixYn?: string;
prdPstgYn?: string;
siteId?: string;
+ bbsTypeCd?: string;
+}
+
+export interface RecentPostParams extends PageableParams {
+ keywordType?: string;
+ keyword?: string;
+ bbsId?: number | null;
+ delYn?: string;
+ frDateYmd?: string;
+ toDateYmd?: string;
}
export interface Post {
- bbsId: number;
rowNo: number;
+ bbsId: number;
pstNo: number;
pstTtl: string;
+ pstCn: string;
inqNocs: number;
rfrncUrl: string;
popupYn: string;
@@ -31,6 +42,11 @@ export interface Post {
cmntCnt: number;
}
+export interface RecentPost extends Post {
+ bbsNm: string;
+ bbsTypeCd: string;
+}
+
export interface PostInfo extends Post {
pstCn: string;
rgtr: string;
@@ -38,6 +54,18 @@ export interface PostInfo extends Post {
mdfr: string;
}
+export interface MovePost {
+ fromBbsId: number;
+ toBbsId?: number;
+ pstNo: number;
+}
+
+export interface DeletePost {
+ bbsId: number;
+ pstNo: number;
+ delRsn?: string;
+}
+
const postEtcSchema = z.object({
bbsPstgTypeCd: z.string(),
pstgPrdSeCd: z.string(),
@@ -69,17 +97,22 @@ export const postUpdateFormSchema = postFormSchema.omit({
});
export type PostList = PageableList;
+export type RecentPostList = PageableList;
export type PostFormData = z.infer;
export type PostUpdateFormData = z.infer;
export interface PostService {
- getPostList(bbsId: string, params: PostParams): Promise;
- getPostInfo(bbsId: string, pstNo: string): Promise;
+ getPostList(bbsId: number, params: PostParams): Promise;
+ getRecentPostList(params: RecentPostParams): Promise;
+ getPostInfo(bbsId: number, pstNo: number): Promise;
createPost(data: PostFormData): Promise;
updatePost(
- bbsId: string,
- pstNo: string,
+ bbsId: number,
+ pstNo: number,
data: PostUpdateFormData,
): Promise;
- deletePost(bbsId: string, pstNo: string, pstPswd?: string): Promise;
+ deletePost(bbsId: number, pstNo: number, delRsn?: string): Promise;
+ softDeletePost(data: DeletePost[]): Promise;
+ hardDeletePost(data: DeletePost[]): Promise;
+ movePost(data: MovePost[]): Promise;
}
diff --git a/apps/cs/src/entities/posting/ui/posting-dialog.tsx b/apps/cs/src/entities/posting/ui/posting-dialog.tsx
index b742eee28..ac31ad0dc 100644
--- a/apps/cs/src/entities/posting/ui/posting-dialog.tsx
+++ b/apps/cs/src/entities/posting/ui/posting-dialog.tsx
@@ -287,7 +287,7 @@ function PostingDialog({ postingType, postingTargets }: PostingDialogProps) {
{parseInt(rememberPeriodCode[site.siteId] ?? "") ===
0 && (
+ onValueChange={(date) =>
handlePeriodDateChange(site.siteId)(
date as DateRange | undefined,
)
diff --git a/apps/cs/src/pages/(post)/faq/index.ts b/apps/cs/src/pages/(post)/faq/index.ts
new file mode 100644
index 000000000..350df198c
--- /dev/null
+++ b/apps/cs/src/pages/(post)/faq/index.ts
@@ -0,0 +1,3 @@
+export { CreatePage } from "./ui/create-page";
+export { ModifyPage } from "./ui/modify-page";
+export { FaqPage } from "./ui/faq-page";
diff --git a/apps/cs/src/pages/(post)/faq/ui/create-page.tsx b/apps/cs/src/pages/(post)/faq/ui/create-page.tsx
new file mode 100644
index 000000000..8b564cad4
--- /dev/null
+++ b/apps/cs/src/pages/(post)/faq/ui/create-page.tsx
@@ -0,0 +1,43 @@
+"use client";
+
+import { useRouter } from "next/navigation";
+import { useForm } from "react-hook-form";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { useMutation } from "@tanstack/react-query";
+import { PostForm } from "@/widgets/post";
+import { PostApi, postFormSchema, type PostFormData } from "@/entities/post";
+import { useAlertStore, useUserStore } from "@/shared/lib";
+
+function CreatePage({ bbsId }: { bbsId: string }) {
+ const router = useRouter();
+ const { userInfo } = useUserStore((state) => state);
+ const { setMessage: alert } = useAlertStore((state) => state);
+
+ const { mutateAsync: createPost } = useMutation({
+ mutationFn: (data: PostFormData) => PostApi.createPost(data),
+ onSuccess: () => {
+ alert("등록되었습니다.", router.back);
+ },
+ });
+
+ const form = useForm({
+ resolver: zodResolver(postFormSchema),
+ values: {
+ bbsId: parseInt(bbsId),
+ pstTtl: "",
+ wrtrNm: userInfo?.userName ?? "",
+ pstPswd: userInfo?.userUnqId ?? "",
+ },
+ });
+
+ return (
+
+ );
+}
+
+export { CreatePage };
diff --git a/apps/cs/src/pages/(post)/faq/ui/faq-page.tsx b/apps/cs/src/pages/(post)/faq/ui/faq-page.tsx
new file mode 100644
index 000000000..24ffada45
--- /dev/null
+++ b/apps/cs/src/pages/(post)/faq/ui/faq-page.tsx
@@ -0,0 +1,317 @@
+"use client";
+
+import dayjs from "dayjs";
+import React, { useEffect, useState } from "react";
+import { usePathname, useRouter } from "next/navigation";
+import { useMutation, useQuery } from "@tanstack/react-query";
+import {
+ Accordion,
+ AccordionContent,
+ AccordionItem,
+ AccordionTrigger,
+ Button,
+ Checkbox,
+ Input,
+ Label,
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+ Skeleton,
+} from "@common/components";
+import { AttachmentApi } from "@/entities/attachment";
+import { PostApi, type PostParams } from "@/entities/post";
+import { useAlertStore, useMenuStore, usePrompt } from "@/shared/lib";
+import { ENDPOINT } from "@/shared/config";
+
+function FaqPage({ bbsId }: { bbsId: string }) {
+ const router = useRouter();
+ const pathname = usePathname();
+ const { prompt } = usePrompt();
+ const { setMessage: alert } = useAlertStore((state) => state);
+ const { bbsInfo, pageMenuAuthority } = useMenuStore((state) => state);
+
+ const [postParams, setPostParams] = useState({
+ keywordType: "title",
+ keyword: "",
+ });
+ const [selectedPostNumbers, setSelectedPostNumbers] = useState([]);
+
+ const {
+ data: postList,
+ isFetched,
+ refetch,
+ } = useQuery({
+ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS, bbsInfo?.bbsTypeCd],
+ queryFn: () =>
+ PostApi.getPostList(parseInt(bbsId), {
+ ...postParams,
+ bbsTypeCd: bbsInfo?.bbsTypeCd,
+ }),
+ enabled: !!bbsInfo?.bbsTypeCd,
+ });
+
+ const { mutate: deletePost } = useMutation({
+ mutationFn: ({ pstNo, delRsn }: { pstNo: number; delRsn?: string }) =>
+ PostApi.deletePost(parseInt(bbsId), pstNo, delRsn),
+ onSuccess: () => {
+ alert("삭제되었습니다.");
+ refetch();
+ },
+ });
+
+ const getPromptValue = async (message: string) => {
+ const { resolved, value } = await prompt(message);
+ if (!resolved) return "";
+ return value;
+ };
+
+ const handleDeletePost = async (pstNo: number) => {
+ const delRsn = await getPromptValue("삭제 사유를 입력해주세요.");
+ deletePost({ pstNo, delRsn });
+ };
+
+ const onSelectedPostDelete = async () => {
+ const delRsn = await getPromptValue("삭제 사유를 입력해주세요.");
+ await Promise.all(
+ selectedPostNumbers.map((pstNo) =>
+ PostApi.deletePost(parseInt(bbsId), pstNo, delRsn),
+ ),
+ );
+ refetch();
+ setSelectedPostNumbers([]);
+ alert("삭제되었습니다.");
+ };
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ refetch();
+ };
+
+ const handleCheckboxChange = (pstNo: number, checked: boolean | string) => {
+ setSelectedPostNumbers(
+ checked === true
+ ? [...selectedPostNumbers, pstNo]
+ : selectedPostNumbers.filter((num) => num !== pstNo),
+ );
+ };
+
+ const handleAllCheckboxChange = (checked: boolean | string) => {
+ setSelectedPostNumbers(
+ checked === true ? postList?.content.map((item) => item.pstNo) || [] : [],
+ );
+ };
+
+ return (
+
+
+
+
+
+
+
+
콘텐츠 목록
+
+ {pageMenuAuthority?.regAuthrtYn === "Y" && (
+
+ )}
+ {pageMenuAuthority?.delAuthrtYn === "Y" && (
+
+ )}
+
+
+
+
+
+ e.stopPropagation()}
+ onCheckedChange={handleAllCheckboxChange}
+ />
+
+
+ {isFetched ? (
+
+ {postList?.content.map((item) => (
+
+
e.stopPropagation()}
+ onCheckedChange={(checked) =>
+ handleCheckboxChange(item.pstNo, checked)
+ }
+ className="mx-2 my-6"
+ />
+
+
+
+
+ Q
+ {item.pstTtl}
+
+
+ 등록일: {dayjs(item.regDt).format("YYYY-MM-DD")}
+
+
+
+
+
+
+ A
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+ ) : (
+
+ )}
+
+
+
+ );
+}
+
+function Attachment({ atflCd }: { atflCd: string }) {
+ const [filename, setFilename] = useState("");
+
+ const { data: downloadResponse, isFetching } = useQuery({
+ queryKey: [ENDPOINT.ATTACH_SERVICE.DOWNLOAD, atflCd],
+ queryFn: () => AttachmentApi.downloadAttachmentByAtflCd(atflCd),
+ enabled: !!atflCd,
+ });
+
+ const handleDownload = async () => {
+ if (!downloadResponse) return;
+ try {
+ const blob = new Blob([downloadResponse.data]);
+ const url = window.URL.createObjectURL(blob);
+ const link = document.createElement("a");
+
+ link.href = url;
+ link.download = filename || "download";
+ document.body.appendChild(link);
+ link.click();
+
+ window.URL.revokeObjectURL(url);
+ document.body.removeChild(link);
+ } catch (error) {
+ console.error(error);
+ }
+ };
+
+ useEffect(() => {
+ if (!downloadResponse) return;
+ try {
+ let filename = "";
+ const contentDisposition =
+ downloadResponse.headers["content-disposition"];
+ if (contentDisposition) {
+ const filenameMatch = contentDisposition.match(
+ /filename\*=UTF-8''([^;]+)/,
+ );
+ if (filenameMatch && filenameMatch[1]) {
+ filename = decodeURIComponent(filenameMatch[1]);
+ }
+ }
+ setFilename(filename);
+ } catch {
+ setFilename("");
+ }
+ }, [downloadResponse]);
+
+ return isFetching ? (
+
+
+
+ ) : (
+ filename && (
+
+ 첨부파일
+
+
+ )
+ );
+}
+
+export { FaqPage };
diff --git a/apps/cs/src/pages/(post)/faq/ui/modify-page.tsx b/apps/cs/src/pages/(post)/faq/ui/modify-page.tsx
new file mode 100644
index 000000000..1a0ed8006
--- /dev/null
+++ b/apps/cs/src/pages/(post)/faq/ui/modify-page.tsx
@@ -0,0 +1,53 @@
+"use client";
+
+import { useRouter } from "next/navigation";
+import { useForm } from "react-hook-form";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { useMutation, useQuery } from "@tanstack/react-query";
+import { PostForm } from "@/widgets/post";
+import {
+ PostApi,
+ postUpdateFormSchema,
+ type PostUpdateFormData,
+} from "@/entities/post";
+import { ENDPOINT } from "@/shared/config";
+import { useAlertStore, useUserStore } from "@/shared/lib";
+
+function ModifyPage({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
+ const router = useRouter();
+ const { setMessage: alert } = useAlertStore((state) => state);
+ const { userInfo } = useUserStore((state) => state);
+
+ const { data: postInfo } = useQuery({
+ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS, bbsId, pstNo],
+ queryFn: () => PostApi.getPostInfo(parseInt(bbsId), parseInt(pstNo)),
+ });
+
+ const { mutateAsync: updatePost } = useMutation({
+ mutationFn: (data: PostUpdateFormData) =>
+ PostApi.updatePost(parseInt(bbsId), parseInt(pstNo), data),
+ onSuccess: () => {
+ alert("수정되었습니다.", router.back);
+ },
+ });
+
+ const form = useForm({
+ resolver: zodResolver(postUpdateFormSchema),
+ values: {
+ ...postInfo,
+ pstTtl: postInfo?.pstTtl ?? "",
+ pstPswd: userInfo?.userUnqId ?? "",
+ },
+ });
+
+ return (
+
+ );
+}
+
+export { ModifyPage };
diff --git a/apps/cs/src/pages/(post)/image/ui/modify-page.tsx b/apps/cs/src/pages/(post)/image/ui/modify-page.tsx
index c721286e4..c2426c134 100644
--- a/apps/cs/src/pages/(post)/image/ui/modify-page.tsx
+++ b/apps/cs/src/pages/(post)/image/ui/modify-page.tsx
@@ -19,13 +19,13 @@ function ModifyPage({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
const { userInfo } = useUserStore((state) => state);
const { data: postInfo } = useQuery({
- queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, pstNo],
- queryFn: () => PostApi.getPostInfo(bbsId, pstNo),
+ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS, bbsId, pstNo],
+ queryFn: () => PostApi.getPostInfo(parseInt(bbsId), parseInt(pstNo)),
});
const { mutateAsync: updatePost } = useMutation({
mutationFn: (data: PostUpdateFormData) =>
- PostApi.updatePost(bbsId, pstNo, data),
+ PostApi.updatePost(parseInt(bbsId), parseInt(pstNo), data),
onSuccess: () => {
alert("수정되었습니다.", router.back);
},
diff --git a/apps/cs/src/pages/(post)/movie/ui/modify-page.tsx b/apps/cs/src/pages/(post)/movie/ui/modify-page.tsx
index 2f67e313c..bee473938 100644
--- a/apps/cs/src/pages/(post)/movie/ui/modify-page.tsx
+++ b/apps/cs/src/pages/(post)/movie/ui/modify-page.tsx
@@ -19,13 +19,13 @@ function ModifyPage({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
const { userInfo } = useUserStore((state) => state);
const { data: postInfo } = useQuery({
- queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, pstNo],
- queryFn: () => PostApi.getPostInfo(bbsId, pstNo),
+ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS, bbsId, pstNo],
+ queryFn: () => PostApi.getPostInfo(parseInt(bbsId), parseInt(pstNo)),
});
const { mutateAsync: updatePost } = useMutation({
mutationFn: (data: PostUpdateFormData) =>
- PostApi.updatePost(bbsId, pstNo, data),
+ PostApi.updatePost(parseInt(bbsId), parseInt(pstNo), data),
onSuccess: () => {
alert("수정되었습니다.", router.back);
},
diff --git a/apps/cs/src/pages/(post)/normal/ui/modify-page.tsx b/apps/cs/src/pages/(post)/normal/ui/modify-page.tsx
index d6114ab44..2e23f62a0 100644
--- a/apps/cs/src/pages/(post)/normal/ui/modify-page.tsx
+++ b/apps/cs/src/pages/(post)/normal/ui/modify-page.tsx
@@ -19,13 +19,13 @@ function ModifyPage({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
const { userInfo } = useUserStore((state) => state);
const { data: postInfo } = useQuery({
- queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, pstNo],
- queryFn: () => PostApi.getPostInfo(bbsId, pstNo),
+ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS, bbsId, pstNo],
+ queryFn: () => PostApi.getPostInfo(parseInt(bbsId), parseInt(pstNo)),
});
const { mutateAsync: updatePost } = useMutation({
mutationFn: (data: PostUpdateFormData) =>
- PostApi.updatePost(bbsId, pstNo, data),
+ PostApi.updatePost(parseInt(bbsId), parseInt(pstNo), data),
onSuccess: () => {
alert("수정되었습니다.", router.back);
},
diff --git a/apps/cs/src/pages/(post)/notice/ui/modify-page.tsx b/apps/cs/src/pages/(post)/notice/ui/modify-page.tsx
index bd014917f..fa12dbcce 100644
--- a/apps/cs/src/pages/(post)/notice/ui/modify-page.tsx
+++ b/apps/cs/src/pages/(post)/notice/ui/modify-page.tsx
@@ -19,13 +19,13 @@ function ModifyPage({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
const { userInfo } = useUserStore((state) => state);
const { data: postInfo } = useQuery({
- queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, pstNo],
- queryFn: () => PostApi.getPostInfo(bbsId, pstNo),
+ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS, bbsId, pstNo],
+ queryFn: () => PostApi.getPostInfo(parseInt(bbsId), parseInt(pstNo)),
});
const { mutateAsync: updatePost } = useMutation({
mutationFn: (data: PostUpdateFormData) =>
- PostApi.updatePost(bbsId, pstNo, data),
+ PostApi.updatePost(parseInt(bbsId), parseInt(pstNo), data),
onSuccess: () => {
alert("수정되었습니다.", router.back);
},
diff --git a/apps/cs/src/pages/bbs/model/table-columns.tsx b/apps/cs/src/pages/bbs/model/table-columns.tsx
index 5a6cb62f8..09933fb7c 100644
--- a/apps/cs/src/pages/bbs/model/table-columns.tsx
+++ b/apps/cs/src/pages/bbs/model/table-columns.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
import dayjs from "dayjs";
import { usePathname, useRouter } from "next/navigation";
import type { ColumnDef, Row } from "@tanstack/react-table";
@@ -61,6 +62,7 @@ const ManageButton = ({ row }: { row: Row }) => {
onClick={(e) => {
e.stopPropagation();
router.push(`${pathname}/${bbsTypeCd.toLowerCase()}/${bbsId}`);
+ // router.push(`/pst/${bbsTypeCd.toLowerCase()}/${bbsId}`); // 공통 개발용
setBbsInfo(JSON.stringify(row.original));
setStoreBbsInfo(row.original);
}}
diff --git a/apps/cs/src/pages/recent/index.ts b/apps/cs/src/pages/recent/index.ts
new file mode 100644
index 000000000..72b8579e1
--- /dev/null
+++ b/apps/cs/src/pages/recent/index.ts
@@ -0,0 +1 @@
+export { RecentPage } from "./ui/recent-page";
diff --git a/apps/cs/src/pages/recent/model/table-columns.tsx b/apps/cs/src/pages/recent/model/table-columns.tsx
new file mode 100644
index 000000000..272a7d149
--- /dev/null
+++ b/apps/cs/src/pages/recent/model/table-columns.tsx
@@ -0,0 +1,117 @@
+import dayjs from "dayjs";
+import type { ColumnDef } from "@tanstack/react-table";
+import { Button, Checkbox } from "@common/components";
+import { AttachmentApi } from "@/entities/attachment";
+import type { RecentPost } from "@/entities/post";
+
+export const columns: ColumnDef[] = [
+ {
+ id: "select",
+ header: ({ table }) => (
+ e.stopPropagation()}
+ onCheckedChange={(checked) =>
+ table.toggleAllPageRowsSelected(!!checked)
+ }
+ className="h-4 w-4 rounded border-gray-300"
+ />
+ ),
+ cell: ({ row }) => (
+ e.stopPropagation()}
+ onCheckedChange={(checked) => row.toggleSelected(!!checked)}
+ className="h-4 w-4 rounded border-gray-300"
+ />
+ ),
+ meta: {
+ width: 40,
+ },
+ },
+ {
+ accessorKey: "rowNo",
+ header: "NO",
+ meta: {
+ width: 80,
+ },
+ },
+ {
+ accessorKey: "bbsNm",
+ header: "게시판",
+ meta: {
+ width: 200,
+ },
+ },
+ {
+ accessorKey: "pstTtl",
+ header: "제목",
+ cell: ({ row }) => {row.original.pstTtl}
,
+ },
+ {
+ accessorKey: "atflCd",
+ header: "첨부파일",
+ cell: ({ row }) => {
+ const atflCd = row.original.atflCd;
+ if (!atflCd) return null;
+ return ;
+ },
+ meta: {
+ width: 100,
+ },
+ },
+ {
+ accessorKey: "rgtrNm",
+ header: "작성자",
+ meta: {
+ width: 120,
+ },
+ },
+ {
+ accessorKey: "regDt",
+ header: "등록일",
+ cell: ({ row }) => dayjs(row.original.regDt).format("YYYY-MM-DD"),
+ meta: {
+ width: 120,
+ },
+ },
+];
+
+const AttachmentButton = ({ atflCd }: { atflCd: string }) => {
+ const handleDownload = async (e: React.MouseEvent) => {
+ e.stopPropagation();
+ try {
+ let filename = "";
+ const response = await AttachmentApi.downloadAttachmentByAtflCd(atflCd);
+ const contentDisposition = response.headers["content-disposition"];
+ if (contentDisposition) {
+ const filenameMatch = contentDisposition.match(
+ /filename\*=UTF-8''([^;]+)/,
+ );
+ if (filenameMatch) {
+ filename = decodeURIComponent(filenameMatch[1]);
+ }
+ }
+
+ const blob = new Blob([response.data]);
+ const url = window.URL.createObjectURL(blob);
+ const link = document.createElement("a");
+
+ link.href = url;
+ link.download = filename;
+ document.body.appendChild(link);
+ link.click();
+
+ window.URL.revokeObjectURL(url);
+ document.body.removeChild(link);
+ } catch (error) {
+ console.error(error);
+ }
+ };
+
+ return (
+
+ );
+};
diff --git a/apps/cs/src/pages/recent/ui/move-post-dialog.tsx b/apps/cs/src/pages/recent/ui/move-post-dialog.tsx
new file mode 100644
index 000000000..64afef317
--- /dev/null
+++ b/apps/cs/src/pages/recent/ui/move-post-dialog.tsx
@@ -0,0 +1,68 @@
+import React, { useRef } from "react";
+import {
+ Button,
+ Dialog,
+ DialogContent,
+ DialogTrigger,
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@common/components";
+import type { Board } from "@/entities/board";
+import type { MovePost } from "@/entities/post";
+
+type MovePostDialogProps = {
+ selectedPosts: MovePost[];
+ boardList: Board[];
+ onMovePost: (data: MovePost[]) => void;
+};
+
+function MovePostDialog({
+ selectedPosts,
+ boardList,
+ onMovePost,
+}: MovePostDialogProps) {
+ const selectedPostsRef = useRef(selectedPosts);
+
+ const onSelectValueChange = (toBbsId: string) => {
+ selectedPostsRef.current = selectedPosts.map((post) => ({
+ ...post,
+ toBbsId: parseInt(toBbsId),
+ }));
+ };
+
+ return (
+
+ );
+}
+
+export { MovePostDialog };
diff --git a/apps/cs/src/pages/recent/ui/recent-page.tsx b/apps/cs/src/pages/recent/ui/recent-page.tsx
new file mode 100644
index 000000000..407b90d49
--- /dev/null
+++ b/apps/cs/src/pages/recent/ui/recent-page.tsx
@@ -0,0 +1,342 @@
+"use client";
+
+import dayjs from "dayjs";
+import { useState } from "react";
+import { useRouter } from "next/navigation";
+import { useConfirm } from "@frontend-opensource/use-react-hooks";
+import { keepPreviousData, useMutation, useQuery } from "@tanstack/react-query";
+import {
+ getCoreRowModel,
+ useReactTable,
+ type PaginationState,
+ type RowSelectionState,
+} from "@tanstack/react-table";
+import {
+ Button,
+ DateRangePicker,
+ Input,
+ Label,
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+ DataTable,
+} from "@common/components";
+import {
+ PostApi,
+ type DeletePost,
+ type MovePost,
+ type RecentPost,
+ type RecentPostParams,
+} from "@/entities/post";
+import { useAlertStore, useMenuStore, usePrompt } from "@/shared/lib";
+import { BoardApi } from "@/entities/board";
+import { ENDPOINT } from "@/shared/config";
+import { columns } from "../model/table-columns";
+import { MovePostDialog } from "./move-post-dialog";
+
+type DateRange = {
+ from: Date | undefined;
+ to?: Date | undefined;
+};
+
+function RecentPage() {
+ const router = useRouter();
+ const { prompt } = usePrompt();
+ const { confirm } = useConfirm();
+ const { setMessage: alert } = useAlertStore((state) => state);
+ const { pageMenuAuthority } = useMenuStore((state) => state);
+ const [dateRange, setDateRange] = useState();
+ const [pagination, setPagination] = useState({
+ pageIndex: 0,
+ pageSize: 10,
+ });
+ const [rowSelection, setRowSelection] = useState({});
+ const [recentPostParams, setRecentPostParams] = useState({
+ keywordType: "",
+ keyword: "",
+ bbsId: null,
+ delYn: "N",
+ frDateYmd: "",
+ toDateYmd: "",
+ });
+ const [isDeletePostData, setIsDeletePostData] = useState(false);
+
+ const { data: recentPostList, refetch } = useQuery({
+ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS, pagination],
+ queryFn: () =>
+ PostApi.getRecentPostList({
+ ...recentPostParams,
+ page: pagination.pageIndex,
+ size: pagination.pageSize,
+ }),
+ placeholderData: keepPreviousData,
+ });
+
+ const { data: boardList } = useQuery({
+ queryKey: [ENDPOINT.BOARD_SERVICE.BBS],
+ queryFn: () => BoardApi.getBoardList(),
+ });
+
+ const { mutate: movePost } = useMutation({
+ mutationFn: (data: MovePost[]) => PostApi.movePost(data),
+ onSuccess: () => {
+ alert("이동이 완료되었습니다.", refetch);
+ },
+ });
+
+ const table = useReactTable({
+ data: recentPostList?.content ?? [],
+ columns,
+ state: {
+ pagination,
+ rowSelection,
+ },
+ rowCount: recentPostList?.totalElements ?? 0,
+ manualPagination: true,
+ enableMultiRowSelection: true,
+ getCoreRowModel: getCoreRowModel(),
+ onPaginationChange: setPagination,
+ onRowSelectionChange: setRowSelection,
+ });
+
+ const isSelectedRow = table.getFilteredSelectedRowModel().rows.length > 0;
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsDeletePostData(recentPostParams.delYn === "Y");
+ refetch();
+ };
+
+ const handleRowClick = (row: RecentPost) => {
+ router.push(
+ `/bbs/${row.bbsTypeCd.toLowerCase()}/${row.bbsId}/${row.pstNo}`,
+ );
+ };
+
+ const handleRecentPostParamsChange =
+ (key: keyof RecentPostParams) => (value: unknown) => {
+ setRecentPostParams({ ...recentPostParams, [key]: value });
+ };
+
+ const handlePresetDateRange = (value: string) => {
+ let presetDateRange: DateRange | undefined;
+ switch (value) {
+ case "1W":
+ presetDateRange = {
+ from: dayjs().subtract(7, "day").toDate(),
+ to: dayjs().toDate(),
+ };
+ break;
+ case "1M":
+ presetDateRange = {
+ from: dayjs().subtract(30, "day").toDate(),
+ to: dayjs().toDate(),
+ };
+ break;
+ case "3M":
+ presetDateRange = {
+ from: dayjs().subtract(90, "day").toDate(),
+ to: dayjs().toDate(),
+ };
+ break;
+ default:
+ presetDateRange = undefined;
+ }
+ setDateRange(presetDateRange);
+ };
+
+ const onSoftDeletePost = async () => {
+ const { resolved, value: delRsn } =
+ await prompt("삭제 사유를 입력해주세요.");
+ if (!resolved) return;
+
+ const selectedPosts: DeletePost[] = table
+ .getFilteredSelectedRowModel()
+ .rows.map((row) => ({
+ bbsId: row.original.bbsId,
+ pstNo: row.original.pstNo,
+ delRsn,
+ }));
+ PostApi.softDeletePost(selectedPosts);
+ alert("삭제가 완료되었습니다.", refetch);
+ setRowSelection({});
+ };
+
+ const onHardDeletePost = async () => {
+ if (
+ await confirm(
+ "게시물을 완전 삭제하시겠습니까?\n이 작업은 되돌릴 수 없습니다.",
+ )
+ ) {
+ const selectedPosts: DeletePost[] = table
+ .getFilteredSelectedRowModel()
+ .rows.map((row) => ({
+ bbsId: row.original.bbsId,
+ pstNo: row.original.pstNo,
+ }));
+ PostApi.hardDeletePost(selectedPosts);
+ alert("삭제가 완료되었습니다.", refetch);
+ setRowSelection({});
+ }
+ };
+
+ const onRestorePost = async () => {
+ if (await confirm("게시물을 복원하시겠습니까?")) {
+ const selectedPosts: DeletePost[] = table
+ .getFilteredSelectedRowModel()
+ .rows.map((row) => ({
+ bbsId: row.original.bbsId,
+ pstNo: row.original.pstNo,
+ }));
+ PostApi.restorePost(selectedPosts);
+ alert("복원이 완료되었습니다.", refetch);
+ setRowSelection({});
+ }
+ };
+
+ return (
+
+
+
+
+
+
콘텐츠 목록
+
+ {pageMenuAuthority?.mngAuthrtYn === "Y" &&
+ (isDeletePostData ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+ ({
+ fromBbsId: row.original.bbsId,
+ pstNo: row.original.pstNo,
+ }))}
+ boardList={boardList?.content ?? []}
+ onMovePost={movePost}
+ />
+
+ >
+ ))}
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export { RecentPage };
diff --git a/apps/cs/src/shared/config/api.ts b/apps/cs/src/shared/config/api.ts
index 094bb3776..7aef8df12 100644
--- a/apps/cs/src/shared/config/api.ts
+++ b/apps/cs/src/shared/config/api.ts
@@ -42,7 +42,7 @@ export const ENDPOINT = {
BOARD_SERVICE: {
BBS: "/board-service/api/v1/bbs",
BBS_TEMPLATES: "/board-service/api/v1/bbsTmplt",
- POSTS_USER: "/board-service/api/v1/posts/user",
+ POSTS: "/board-service/api/v1/posts",
POSTS_COMMENTS: "/board-service/api/v1/posts-cmnts",
},
};
diff --git a/apps/cs/src/shared/lib/use-prompt.tsx b/apps/cs/src/shared/lib/use-prompt.tsx
index da9c4b386..f36858eb0 100644
--- a/apps/cs/src/shared/lib/use-prompt.tsx
+++ b/apps/cs/src/shared/lib/use-prompt.tsx
@@ -7,18 +7,18 @@ export const usePrompt = () => {
const prompt = (message: string) => {
setMessage(message);
- return new Promise((resolve) => {
+ return new Promise<{ resolved: boolean; value?: string }>((resolve) => {
setResolve(() => resolve);
});
};
const onSubmit = (value: string) => {
- resolve?.(value);
+ resolve?.({ resolved: true, value });
setMessage("");
};
const onCancel = () => {
- resolve?.("");
+ resolve?.({ resolved: false });
setMessage("");
};
diff --git a/apps/cs/src/shared/providers/index.ts b/apps/cs/src/shared/providers/index.ts
index f2e092170..fa8320fe7 100644
--- a/apps/cs/src/shared/providers/index.ts
+++ b/apps/cs/src/shared/providers/index.ts
@@ -1 +1,2 @@
export { StoreProvider } from "./store-provider";
+export { PromptProvider } from "./prompt-provider";
diff --git a/apps/cs/src/shared/providers/prompt-provider.tsx b/apps/cs/src/shared/providers/prompt-provider.tsx
index 267b7aafc..10338c338 100644
--- a/apps/cs/src/shared/providers/prompt-provider.tsx
+++ b/apps/cs/src/shared/providers/prompt-provider.tsx
@@ -2,9 +2,15 @@ import { createContext, useState } from "react";
interface PromptContext {
message?: string;
- resolve?: (value: string) => void;
+ resolve?: ({
+ resolved,
+ value,
+ }: {
+ resolved: boolean;
+ value?: string;
+ }) => void;
setMessage: (message: string) => void;
- setResolve: (resolve: (value: string) => void) => void;
+ setResolve: (resolve: () => void) => void;
}
export const PromptContext = createContext({
@@ -16,7 +22,10 @@ export const PromptContext = createContext({
export const PromptProvider = ({ children }: { children: React.ReactNode }) => {
const [message, setMessage] = useState();
- const [resolve, setResolve] = useState<(value: string) => void>();
+ const [resolve, setResolve] =
+ useState<
+ ({ resolved, value }: { resolved: boolean; value?: string }) => void
+ >();
return (
({
key={row.id}
onClick={() => onRowClick?.(row.original)}
className={cn(
- "rounded-md border border-border bg-background p-4 shadow-md",
+ "overflow-hidden rounded-md border border-border bg-background p-4 shadow-md",
onRowClick && "cursor-pointer hover:bg-accent",
)}
>
diff --git a/apps/cs/src/shared/ui/prompt-dialog.tsx b/apps/cs/src/shared/ui/prompt-dialog.tsx
new file mode 100644
index 000000000..54c2f3fcc
--- /dev/null
+++ b/apps/cs/src/shared/ui/prompt-dialog.tsx
@@ -0,0 +1,45 @@
+import { useState } from "react";
+import {
+ Button,
+ Dialog,
+ DialogContent,
+ DialogFooter,
+ DialogClose,
+ Input,
+} from "@common/components";
+import { usePrompt } from "@/shared/lib/use-prompt";
+
+function PromptDialog() {
+ const { message, isOpen, onSubmit, onCancel } = usePrompt();
+ const [value, setValue] = useState("");
+
+ return (
+
+ );
+}
+
+export { PromptDialog };
diff --git a/apps/cs/src/widgets/post/model/grid-view-table-columns.tsx b/apps/cs/src/widgets/post/model/grid-view-table-columns.tsx
index 96f7866db..dbe3b88eb 100644
--- a/apps/cs/src/widgets/post/model/grid-view-table-columns.tsx
+++ b/apps/cs/src/widgets/post/model/grid-view-table-columns.tsx
@@ -1,12 +1,19 @@
import dayjs from "dayjs";
import Image from "next/image";
import type { ColumnDef } from "@tanstack/react-table";
-import { Badge, Checkbox, Skeleton } from "@common/components";
+import { Badge, Checkbox, Skeleton, cn } from "@common/components";
import { AttachmentApi } from "@/entities/attachment";
import type { Post } from "@/entities/post";
import { useQuery } from "@tanstack/react-query";
import { ENDPOINT } from "@/shared/config";
-import { useMenuStore } from "@/shared/lib";
+import type { BbsType } from "@/shared/store/menu-store";
+
+declare module "@tanstack/react-table" {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ interface TableMeta {
+ bbsTypeCd?: BbsType;
+ }
+}
export const createColumns = (
thumbRefs: React.MutableRefObject