-
-
setKeyword(e.target.value)}
- />
-
+
+
@@ -116,6 +134,16 @@ function OrganizationSearchDialog({
+
+
+
+
+
+
+
+
);
diff --git a/apps/cs/src/pages/menu/ui/qrcode-dialog.tsx b/apps/cs/src/pages/menu/ui/qrcode-dialog.tsx
new file mode 100644
index 000000000..042c48911
--- /dev/null
+++ b/apps/cs/src/pages/menu/ui/qrcode-dialog.tsx
@@ -0,0 +1,81 @@
+import React, { useEffect, useRef, useState } from "react";
+import { useQRCode } from "next-qrcode";
+import {
+ Button,
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+ Tooltip,
+ TooltipContent,
+ TooltipTrigger,
+} from "@common/components";
+import { useClipboard } from "@frontend-opensource/use-react-hooks";
+
+function QRCodeDialog({ url }: { url: string }) {
+ const { Canvas } = useQRCode();
+ const { copied: isCopied, copyText } = useClipboard();
+ const canvasRef = useRef
(null);
+ const [originUrl, setOriginUrl] = useState("");
+ const qrCodeUrl = originUrl + url;
+
+ const handleDownload = () => {
+ const canvas = canvasRef.current?.querySelector("canvas");
+ if (!canvas) return;
+ const url = canvas.toDataURL("image/png");
+ const link = document.createElement("a");
+ link.href = url;
+ link.download = "qr-code.png";
+ link.click();
+ };
+
+ useEffect(() => {
+ if (typeof window === "undefined") return;
+ setOriginUrl(window.location.origin);
+ }, []);
+
+ return (
+
+ );
+}
+
+export { QRCodeDialog };
diff --git a/apps/cs/src/pages/menu/ui/type-menu-form.tsx b/apps/cs/src/pages/menu/ui/type-menu-form.tsx
index 1f0483d1b..41c0741e8 100644
--- a/apps/cs/src/pages/menu/ui/type-menu-form.tsx
+++ b/apps/cs/src/pages/menu/ui/type-menu-form.tsx
@@ -1,5 +1,5 @@
import dayjs from "dayjs";
-import { type UseFormReturn } from "react-hook-form";
+import type { UseFormReturn } from "react-hook-form";
import {
DatePicker,
IconFinder,
@@ -16,11 +16,12 @@ import {
import type { BoardPopup } from "@/entities/board";
import type { Contents } from "@/entities/content";
import type { TreeUser } from "@/entities/user-organization";
+import type { MenuFormData, MenuType } from "@/entities/menu";
import { FormItem, FormControl, FormField } from "@/shared/ui/form";
-import type { MenuFormData, MenuType } from "../model/menu-interface";
import { OrganizationSearchDialog } from "./organization-search-dialog";
import { ContentSearchDialog } from "./content-search-dialog";
import { BoardSearchDialog } from "./board-search-dialog";
+import { QRCodeDialog } from "./qrcode-dialog";
type TypeMenuFormProps = {
form: UseFormReturn;
@@ -33,6 +34,7 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
};
const handleContentSelect = (content: Contents) => {
+ form.setValue("urlPath", `/cms/cntns/${content.contsSn}`);
form.setValue("menuLnkgSn", content.contsSn);
form.setValue("menuLnkgSnNm", content.contsTtl);
};
@@ -43,6 +45,10 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
};
const handleBoardSelect = (board: BoardPopup) => {
+ form.setValue(
+ "urlPath",
+ `/cms/${board.bbsTypeCd.toLowerCase()}/${board.bbsId}`,
+ );
form.setValue("menuLnkgSn", board.bbsId);
form.setValue("menuLnkgSnNm", board.bbsNm);
};
@@ -52,6 +58,14 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
form.setValue("menuPicDsgnYmd", dayjs(date).format("YYYYMMDD"));
};
+ const getUrlPathPlaceholder = () => {
+ if (menuType === "CONTENTS") return "콘텐츠 선택 시 자동으로 입력됩니다.";
+ if (menuType === "BOARD") return "게시판 선택 시 자동으로 입력됩니다.";
+ if (menuType === "INSIDE")
+ return "메뉴에 연결된 페이지의 경로를 입력하십시오.";
+ return "'http://' 또는 'https://'를 포함하여 입력하십시오.";
+ };
+
return (
@@ -91,7 +105,10 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
)}
- {(menuType === "INSIDE" || menuType === "OUTSIDE") && (
+ {(menuType === "CONTENTS" ||
+ menuType === "BOARD" ||
+ menuType === "INSIDE" ||
+ menuType === "OUTSIDE") && (
연결 URL
@@ -105,10 +122,9 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
{...field}
value={field.value ?? ""}
className="!text-[1.3rem]"
- placeholder={
- menuType === "INSIDE"
- ? "메뉴에 연결된 페이지의 경로를 입력하십시오."
- : "'http://' 또는 'https://'를 포함하여 입력하십시오."
+ placeholder={getUrlPathPlaceholder()}
+ disabled={
+ menuType === "CONTENTS" || menuType === "BOARD"
}
/>
@@ -155,7 +171,7 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
)}
{(menuType === "CONTENTS" || menuType === "BOARD") && (
- 메뉴 평가 사용 여부
+ 메뉴 평가 사용 여부
- 출력 여부
+ 출력 여부
- 사용 여부
+ 사용 여부
(
-
-
-
-
-
-
-
+
-
-
-
+
+
+
+ {field.value === "Y" && (
+
+ )}
+
)}
/>
diff --git a/apps/cs/src/pages/module/model/authorizations-table-columns.tsx b/apps/cs/src/pages/module/model/authorizations-table-columns.tsx
index 359afab19..c99d4145c 100644
--- a/apps/cs/src/pages/module/model/authorizations-table-columns.tsx
+++ b/apps/cs/src/pages/module/model/authorizations-table-columns.tsx
@@ -7,7 +7,12 @@ export const columns: ColumnDef
[] = [
{
id: "no",
header: "NO",
- cell: ({ row }) => row.index + 1,
+ cell: ({ row, table }) => {
+ const totalRows = table.getRowCount();
+ const currentPage = table.getState().pagination.pageIndex;
+ const pageSize = table.getState().pagination.pageSize;
+ return totalRows - (currentPage * pageSize + row.index);
+ },
},
{
accessorKey: "authorizationName",
diff --git a/apps/cs/src/pages/module/ui/management-authority-dialog.tsx b/apps/cs/src/pages/module/ui/management-authority-dialog.tsx
index 8ca38a570..0459ba804 100644
--- a/apps/cs/src/pages/module/ui/management-authority-dialog.tsx
+++ b/apps/cs/src/pages/module/ui/management-authority-dialog.tsx
@@ -2,15 +2,10 @@ import { useState, memo } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useQuery } from "@tanstack/react-query";
-import {
- getCoreRowModel,
- useReactTable,
- type RowSelectionState,
-} from "@tanstack/react-table";
+import { getCoreRowModel, type RowSelectionState } from "@tanstack/react-table";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import {
Button,
- DataTable,
Dialog,
DialogClose,
DialogContent,
@@ -32,7 +27,7 @@ import {
type RoleAuthorizationsData,
} from "@/entities/role-authorization";
import { ENDPOINT } from "@/shared/config";
-import { useAlertStore, useMutationWrapper } from "@/shared/lib";
+import { useAlertStore, useMutationWrapper, useDataTable } from "@/shared/lib";
import { createColumns } from "../model/role-authorizations-table-columns";
import type { Authorizations } from "@/entities/authorization";
@@ -42,25 +37,25 @@ type ManagementAuthorityDialogProps = {
} & React.ComponentProps;
const ManagementAuthorityDialog = memo(
- ({ authorizationNo, rowData, ...props }: ManagementAuthorityDialogProps) => {
+ ({ authorizationNo, rowData }: ManagementAuthorityDialogProps) => {
const { confirm } = useConfirm();
const alert = useAlertStore((state) => state.setMessage);
- const [isOpened, setIsOpened] = useState(false);
+ const [open, setOpen] = useState(false);
const [rowSelection, setRowSelection] = useState({});
- const { data: roleAuthorizationList } = useQuery({
+ const query = useQuery({
queryKey: [ENDPOINT.USER_SERVICE.ROLE_AUTHORIZATIONS, authorizationNo],
queryFn: () =>
RoleAuthorizationsApi.getRoleAuthorizationsList({ authorizationNo }),
- enabled: !!authorizationNo && isOpened,
+ enabled: !!authorizationNo && open,
});
const { mutateAsync: saveRoleAuthorization } = useMutationWrapper({
mutationFn: (data: RoleAuthorizationsData) =>
RoleAuthorizationsApi.createRoleAuthorizations(data),
onSuccess: () => {
- alert("저장되었습니다.");
+ alert("저장되었습니다.", () => setOpen(false));
},
});
@@ -68,24 +63,24 @@ const ManagementAuthorityDialog = memo(
resolver: zodResolver(roleAuthorizationsFormSchema),
values: {
roleAuthorizations:
- roleAuthorizationList?.content.map(
- ({ roleId, authorizationNo, useYn }) => ({
- roleId,
- authorizationNo,
- authYn: useYn,
- }),
- ) ?? [],
+ query.data?.content.map(({ roleId, authorizationNo, useYn }) => ({
+ roleId,
+ authorizationNo,
+ authYn: useYn,
+ })) ?? [],
},
});
- const table = useReactTable({
- data: roleAuthorizationList?.content ?? [],
- columns: createColumns(form),
- state: {
- rowSelection,
+ const { tableComponent } = useDataTable({
+ query,
+ tableOptions: {
+ columns: createColumns(form),
+ state: {
+ rowSelection,
+ },
+ getCoreRowModel: getCoreRowModel(),
+ onRowSelectionChange: setRowSelection,
},
- getCoreRowModel: getCoreRowModel(),
- onRowSelectionChange: setRowSelection,
});
const handleSave = async () => {
@@ -96,11 +91,9 @@ const ManagementAuthorityDialog = memo(
};
return (
-
-
-
-
+ {tableComponent}