diff --git a/apps/cs/src/pages/image/api/posting-service.ts b/apps/cs/src/pages/image/api/posting-service.ts new file mode 100644 index 000000000..a50afe5d3 --- /dev/null +++ b/apps/cs/src/pages/image/api/posting-service.ts @@ -0,0 +1,31 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { PageableList } from "@/shared/model"; +import type { + PostService, + PostingParams, + Post, + WithModePostData, +} from "../model/posting-interface"; + +export class PostingApiService implements PostService { + public async getPostingHistory( + params: PostingParams, + ): Promise> { + const response = await client.get>( + `${ENDPOINT.CMS_SERVICE.SITE_PSTGS}`, + { params }, + ); + return response.data; + } + + public async requestPosting(data: WithModePostData[]): Promise { + const response = await client.post( + `${ENDPOINT.CMS_SERVICE.SITE_PSTGS}`, + data, + ); + return response.data; + } +} + +export const PostingApi = new PostingApiService(); diff --git a/apps/cs/src/pages/image/model/table-columns.tsx b/apps/cs/src/pages/image/model/image-table-columns.tsx similarity index 100% rename from apps/cs/src/pages/image/model/table-columns.tsx rename to apps/cs/src/pages/image/model/image-table-columns.tsx diff --git a/apps/cs/src/pages/image/model/posting-interface.ts b/apps/cs/src/pages/image/model/posting-interface.ts new file mode 100644 index 000000000..0708bb29f --- /dev/null +++ b/apps/cs/src/pages/image/model/posting-interface.ts @@ -0,0 +1,27 @@ +import type { PageableList, PageableParams } from "@/shared/model"; + +export interface PostingParams extends PageableParams { + pstgTrgtNo: number; +} + +export interface Post { + siteId: string; + siteNm: string; + pstgTypeCd: string; + pstgTypeNm: string; + pstgTrgtNo: number; + pstgBgngDt: string; + pstgEndDt: string; + pstgPrdSeCd: string; + pstgPrdSeNm: string; + delYn: string; +} + +export interface WithModePostData extends Post { + mode: string; +} + +export interface PostService { + getPostingHistory: (params: PostingParams) => Promise>; + requestPosting: (data: WithModePostData[]) => Promise; +} diff --git a/apps/cs/src/pages/image/model/posting-table-columns.tsx b/apps/cs/src/pages/image/model/posting-table-columns.tsx new file mode 100644 index 000000000..c3a0830a1 --- /dev/null +++ b/apps/cs/src/pages/image/model/posting-table-columns.tsx @@ -0,0 +1,44 @@ +"use client"; + +import dayjs from "dayjs"; +import { type ColumnDef } from "@tanstack/react-table"; +import { Checkbox } from "@common/components/ui"; +import { type Post } from "./posting-interface"; + +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" + /> + ), + }, + { + accessorKey: "siteNm", + header: "사이트", + }, + { + accessorKey: "pstgPrdSeNm", + header: "게시기간", + cell: ({ row }) => { + const pstgPrdSeNm = row.original.pstgPrdSeNm; + const pstgBgngDt = row.original.pstgBgngDt; + const pstgEndDt = row.original.pstgEndDt; + return `${pstgPrdSeNm} (${dayjs(pstgBgngDt).format("YYYY-MM-DD")} ~ ${dayjs(pstgEndDt).format("YYYY-MM-DD")})`; + }, + }, +]; diff --git a/apps/cs/src/pages/image/ui/image-page.tsx b/apps/cs/src/pages/image/ui/image-page.tsx index 48ffcb55c..810cb0b5c 100644 --- a/apps/cs/src/pages/image/ui/image-page.tsx +++ b/apps/cs/src/pages/image/ui/image-page.tsx @@ -11,7 +11,7 @@ import { import { Button, DataTable, Input, Label } from "@common/components"; import { ENDPOINT } from "@/shared/config"; import { ImageApi } from "../api/image-service"; -import { columns } from "../model/table-columns"; +import { columns } from "../model/image-table-columns"; import { type Image, type ImageParams } from "../model/image-interface"; function ImagePage() { diff --git a/apps/cs/src/pages/image/ui/modify-page.tsx b/apps/cs/src/pages/image/ui/modify-page.tsx index c440c56f9..4ab21de5a 100644 --- a/apps/cs/src/pages/image/ui/modify-page.tsx +++ b/apps/cs/src/pages/image/ui/modify-page.tsx @@ -1,24 +1,46 @@ "use client"; +import { useState } from "react"; 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 { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { + getCoreRowModel, + useReactTable, + type RowSelectionState, +} from "@tanstack/react-table"; +import { useConfirm } from "@frontend-opensource/use-react-hooks"; +import { Button, DataTable } from "@common/components/ui"; import { ENDPOINT } from "@/shared/config"; -import { imageFormSchema, type ImageFormData } from "../model/image-interface"; -import { ImageApi } from "../api/image-service"; -import { ImageForm } from "./image-form"; import { useAlertStore } from "@/shared/lib/use-alert-store"; +import { ConfirmDialog } from "@/shared/ui/confirm-dialog"; +import { imageFormSchema, type ImageFormData } from "../model/image-interface"; +import type { WithModePostData } from "../model/posting-interface"; +import { columns } from "../model/posting-table-columns"; +import { ImageApi } from "../api/image-service"; +import { PostingApi } from "../api/posting-service"; +import { ImageForm } from "./image-form"; function ModifyPage({ serial }: { serial: string }) { const router = useRouter(); + const { confirm } = useConfirm(); + const queryClient = useQueryClient(); const { setMessage: alert } = useAlertStore((state) => state); + const [onConfirm, setOnConfirm] = useState(false); + const [rowSelection, setRowSelection] = useState({}); + const { data: imageDetail } = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.IMAGES, serial], queryFn: () => ImageApi.getImageInfo(serial), }); + const { data: postHistory } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.SITE_PSTGS, serial], + queryFn: () => PostingApi.getPostingHistory({ pstgTrgtNo: Number(serial) }), + }); + const { mutateAsync: updateImage } = useMutation({ mutationFn: (data: ImageFormData) => ImageApi.updateImage(serial, data), onSuccess: () => { @@ -33,23 +55,83 @@ function ModifyPage({ serial }: { serial: string }) { }, }); + const { mutateAsync: requestPosting } = useMutation({ + mutationFn: (data: WithModePostData[]) => PostingApi.requestPosting(data), + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: [ENDPOINT.CMS_SERVICE.SITE_PSTGS, serial], + }); + }, + }); + const form = useForm({ resolver: zodResolver(imageFormSchema), values: imageDetail, }); + const table = useReactTable({ + data: postHistory?.content ?? [], + columns, + state: { + rowSelection, + }, + enableMultiRowSelection: true, + getCoreRowModel: getCoreRowModel(), + onRowSelectionChange: setRowSelection, + }); + + const handleDeletePostingHistory = async () => { + const data = table.getFilteredSelectedRowModel().flatRows.map((row) => ({ + ...row.original, + mode: "D", + })); + + setOnConfirm(true); + if (await confirm("삭제하시겠습니까?")) { + setOnConfirm(false); + await requestPosting(data); + alert("삭제되었습니다."); + } + setOnConfirm(false); + }; + return ( -
-
-

이미지 수정

+ <> +
+
+
+

이미지 수정

+
+ +
+
+
+

+ 사이트 게시 이력 +

+
+
+
+ +
+ +
+
- -
+ + ); } diff --git a/apps/cs/src/pages/menu/ui/content-search-dialog.tsx b/apps/cs/src/pages/menu/ui/content-search-dialog.tsx index 66d939842..1cfa122a2 100644 --- a/apps/cs/src/pages/menu/ui/content-search-dialog.tsx +++ b/apps/cs/src/pages/menu/ui/content-search-dialog.tsx @@ -33,8 +33,7 @@ function ContentSearchDialog({ const { data: contentList, refetch } = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS], - queryFn: () => - ContentApi.getContentList({ contsTtl, useYn: "Y", page: 0, size: 100 }), + queryFn: () => ContentApi.getContentList({ contsTtl }), enabled: false, }); diff --git a/apps/cs/src/pages/menu/ui/menu-page.tsx b/apps/cs/src/pages/menu/ui/menu-page.tsx index 71ad0042b..56d2a086c 100644 --- a/apps/cs/src/pages/menu/ui/menu-page.tsx +++ b/apps/cs/src/pages/menu/ui/menu-page.tsx @@ -179,6 +179,7 @@ function MenuPage() { setOnConfirm(false); deleteMenu(selectedMenu!.menuCd!); } + setOnConfirm(false); }; const handleAddMenu = () => { diff --git a/apps/cs/src/pages/site/ui/ip-management-dialog.tsx b/apps/cs/src/pages/site/ui/ip-management-dialog.tsx index dd9ee3748..5895d0be3 100644 --- a/apps/cs/src/pages/site/ui/ip-management-dialog.tsx +++ b/apps/cs/src/pages/site/ui/ip-management-dialog.tsx @@ -90,6 +90,7 @@ function IPManagementDialog({ await mutateAsync(data.ips); alert("저장되었습니다."); } + setOnConfirm(false); }; const handleAddIP = () => { diff --git a/apps/cs/src/shared/config/api.ts b/apps/cs/src/shared/config/api.ts index 4430285d8..0a1ec0122 100644 --- a/apps/cs/src/shared/config/api.ts +++ b/apps/cs/src/shared/config/api.ts @@ -21,6 +21,7 @@ export const ENDPOINT = { CONTENTS: "/cms-service/api/v1/contents", USER_OGNZ: "/cms-service/api/v1/user-ognz", IMAGES: "/cms-service/api/v1/images", + SITE_PSTGS: "/cms-service/api/v1/site-pstgs", }, BOARD_SERVICE: { BBS: "/board-service/api/v1/bbs",