feat: 콘텐츠 메뉴 등록 작업

This commit is contained in:
2025-03-27 18:20:29 +09:00
parent 050ce81481
commit c221a4537e
8 changed files with 169 additions and 48 deletions
@@ -0,0 +1,19 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type {
ContentService,
ContentParams,
ContentList,
} from "../model/content-interface";
export class ContentApiService implements ContentService {
public async getContentList(params: ContentParams): Promise<ContentList> {
const response = await client.get<ContentList>(
`${ENDPOINT.CMS_SERVICE.CONTENTS}`,
{ params },
);
return response.data;
}
}
export const ContentApi = new ContentApiService();
@@ -0,0 +1,23 @@
import type { PageableList, PageableParams } from "@/shared/model";
export interface ContentParams extends PageableParams {
siteId?: string;
menuKornNm?: string;
urlPath?: string;
useYn?: string;
}
export interface Content {
contsSn: number;
contsTtl: string;
aprvContsVer: number;
useYn: string;
rgtr: string;
regDt: string;
}
export type ContentList = PageableList<Content>;
export interface ContentService {
getContentList(params: ContentParams): Promise<ContentList>;
}
@@ -1,12 +1,12 @@
import { z } from "zod";
export const MENU_TYPE = {
EMPTY: "empty",
CONTENTS: "contents",
BOARD: "board",
INSIDE: "inside",
OUTSIDE: "outside",
BOTTOM: "bottom",
EMPTY: "EMPTY",
CONTENTS: "CONTENTS",
BOARD: "BOARD",
INSIDE: "INSIDE",
OUTSIDE: "OUTSIDE",
BOTTOM: "BOTTOM",
} as const;
export type MenuType = (typeof MENU_TYPE)[keyof typeof MENU_TYPE];
@@ -0,0 +1,32 @@
import { createColumnHelper } from "@tanstack/react-table";
import { Checkbox } from "@common/components/ui";
import type { Content } from "../model/content-interface";
const columnHelper = createColumnHelper<Content>();
const columns = [
columnHelper.accessor((_, index) => index + 1, {
id: "no",
header: "NO",
}),
columnHelper.accessor("contsTtl", {
id: "contsTtl",
header: "콘텐츠명",
}),
// TODO: 최종수정자, 최종수정일, 승인일시 추가
columnHelper.display({
id: "select",
header: "선택",
cell: ({ row }) => {
return (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={row.getToggleSelectedHandler()}
className="mx-4 flex justify-center"
/>
);
},
}),
];
export { columns };
@@ -0,0 +1,73 @@
import { useEffect, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import {
getCoreRowModel,
useReactTable,
type RowSelectionState,
} from "@tanstack/react-table";
import {
Button,
DataTable,
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
} from "@common/components/ui";
import { ENDPOINT } from "@/shared/config";
import { ContentApi } from "../api/content-service";
import type { Content } from "../model/content-interface";
import { columns } from "../model/table-colums";
type ContentDialogProps = {
handleContentSelect: (content: Content) => void;
} & React.ComponentProps<typeof Dialog>;
function ContentDialog({ handleContentSelect, ...props }: ContentDialogProps) {
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const { data: contentList } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS],
queryFn: () =>
ContentApi.getContentList({ useYn: "Y", page: 0, size: 100 }),
});
const table = useReactTable({
data: contentList?.content ?? [],
columns,
state: {
rowSelection,
},
enableMultiRowSelection: false,
getCoreRowModel: getCoreRowModel(),
onRowSelectionChange: setRowSelection,
});
useEffect(() => {
const contentData = table.getSelectedRowModel().rows[0]
?.original as Content;
if (!contentData) return;
handleContentSelect(contentData);
}, [table.getSelectedRowModel().rows]);
return (
<Dialog {...props}>
<DialogTrigger asChild>
<Button className="gap-3">
<i className="diveicon di-search" />
조회
</Button>
</DialogTrigger>
<DialogContent className="max-w-[60rem]" aria-describedby={undefined}>
<DialogHeader>
<DialogTitle>콘텐츠 선택</DialogTitle>
</DialogHeader>
<div className="mt-4 h-[40rem] overflow-y-auto">
<DataTable table={table} />
</div>
</DialogContent>
</Dialog>
);
}
export { ContentDialog };
+13 -33
View File
@@ -16,9 +16,16 @@ import {
FormMessage,
} from "@/shared/ui/form";
import type { MenuFormData } from "../model/menu-interface";
import type { Content } from "../model/content-interface";
import { BaseTypeMenuForm } from "./base-type-menu-form";
import { ContentDialog } from "./content-dialog";
function ContentMenuForm({ form }: { form: UseFormReturn<MenuFormData> }) {
const handleContentSelect = (content: Content) => {
form.setValue("menuLnkgSn", content.contsSn);
form.setValue("menuLnkgSnNm", content.contsTtl);
};
return (
<Table variant="secondary">
<colgroup>
@@ -29,42 +36,15 @@ function ContentMenuForm({ form }: { form: UseFormReturn<MenuFormData> }) {
<TableRow>
<TableHead>콘텐츠</TableHead>
<TableCell className="border">
<div className="h-[3.2rem] w-[21.5rem] cursor-not-allowed rounded-md border border-input bg-form px-3 py-2 text-[1.3rem] opacity-50">
{form.watch("menuLnkgSn")}
<div className="flex items-center gap-2">
<div className="h-[3.2rem] w-1/2 cursor-not-allowed overflow-hidden whitespace-nowrap break-keep rounded-md border border-input bg-form px-3 py-2 text-[1.3rem] opacity-50">
{form.watch("menuLnkgSnNm")}
</div>
<ContentDialog handleContentSelect={handleContentSelect} />
</div>
</TableCell>
</TableRow>
<TableRow>
<TableHead>연결 형태</TableHead>
<TableCell className="border">
<FormField
control={form.control}
name="evlUseYn"
render={({ field }) => (
<FormItem>
<FormControl>
<RadioGroup
value={field.value ?? ""}
onValueChange={field.onChange}
>
<div className="flex items-center space-x-4">
<div className="flex items-center space-x-2">
<RadioGroupItem value="self" id="self" />
<Label htmlFor="self">현재창</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="blank" id="blank" />
<Label htmlFor="blank">새창</Label>
</div>
</div>
</RadioGroup>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</TableCell>
</TableRow>
{/* TODO: 연결 형태 추가 */}
<TableRow>
<TableHead>메뉴 평가 사용 여부</TableHead>
<TableCell className="border">
+1
View File
@@ -14,6 +14,7 @@ export const ENDPOINT = {
IPS: "/cms-service/api/v1/site-ips",
DOMAINS: "/cms-service/api/v1/site-dmns",
MENUS: "/cms-service/api/v1/menus",
CONTENTS: "/cms-service/api/v1/contents",
},
};
@@ -79,11 +79,7 @@ const TableHead = React.forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<th
ref={ref}
className={cn("align-middle [&:has([role=checkbox])]:pr-0", className)}
{...props}
/>
<th ref={ref} className={cn("align-middle", className)} {...props} />
));
TableHead.displayName = "TableHead";
@@ -93,10 +89,7 @@ const TableCell = React.forwardRef<
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn(
"align-middle text-foreground [&:has([role=checkbox])]:pr-0",
className,
)}
className={cn("align-middle text-foreground", className)}
{...props}
/>
));