-
+
);
}
@@ -217,8 +219,7 @@ function NtftalkTempTemplateSection() {
alert("삭제할 템플릿을 선택해 주세요.");
return;
}
- if (!(await confirm(`선택한 ${rows.length}건을 삭제하시겠습니까?`)))
- return;
+ if (!(await confirm(`선택한 ${rows.length}건을 삭제하시겠습니까?`))) return;
const codes = rows.map((r) => r.original.templateCode);
setPendingDeleteTemplateCodes((prev) => {
const next = new Set(prev);
@@ -420,10 +421,7 @@ function NtftalkTempTemplateSection() {
diff --git a/apps/cs/src/pages/ntftalk-temp/ui/ntftalk-temp-var-section.tsx b/apps/cs/src/pages/ntftalk-temp/ui/ntftalk-temp-var-section.tsx
index 7e517afc7..6077be8ac 100644
--- a/apps/cs/src/pages/ntftalk-temp/ui/ntftalk-temp-var-section.tsx
+++ b/apps/cs/src/pages/ntftalk-temp/ui/ntftalk-temp-var-section.tsx
@@ -1,7 +1,6 @@
"use client";
import { useCallback, useMemo, useState } from "react";
-import { useFieldArray, useForm, useWatch } from "react-hook-form";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import type { UseQueryResult } from "@tanstack/react-query";
@@ -19,7 +18,7 @@ import {
} from "@tanstack/react-table";
import { ENDPOINT } from "@/shared/config";
-import { useAlertStore, useMutationWrapper, useUserStore } from "@/shared/lib";
+import { useAlertStore, useMutationWrapper } from "@/shared/lib";
import { NoData } from "@/shared/ui/no-data";
import {
NtftalkVarApi,
@@ -30,13 +29,10 @@ import {
import { Button, DataTable, LoadingWithAnimation } from "@common/components";
import { buildNtftalkVarBatchPayload } from "../model/ntftalk-var-batch-payload";
-import {
- createEmptyVarDraft,
- type NtftalkVarGridRow,
- type VarDraftFormValues,
-} from "../model/ntftalk-var-grid";
+import { type NtftalkVarGridRow } from "../model/ntftalk-var-grid";
import { createVarColumns } from "../model/var-table-columns";
+import { NtftalkVarAddDialog } from "./ntftalk-var-add-dialog";
import { NtftalkVarEditDialog } from "./ntftalk-var-edit-dialog";
interface NtftalkVarTablePanelProps {
@@ -67,7 +63,6 @@ function NtftalkVarSection() {
const queryClient = useQueryClient();
const alert = useAlertStore((s) => s.setMessage);
const { confirm } = useConfirm();
- const userInfo = useUserStore((s) => s.userInfo);
const [varPagination, setVarPagination] = useState
({
pageIndex: 0,
@@ -81,16 +76,7 @@ function NtftalkVarSection() {
() => new Set(),
);
const [editTargetVarCd, setEditTargetVarCd] = useState(null);
-
- const varDraftForm = useForm({
- defaultValues: { draftVars: [] },
- });
- const { control, setValue, getValues } = varDraftForm;
- const { append, remove, replace } = useFieldArray({
- control,
- name: "draftVars",
- });
- const draftVars = useWatch({ control, name: "draftVars" }) ?? [];
+ const [addVarDialogOpen, setAddVarDialogOpen] = useState(false);
const varQuery = useQuery({
queryKey: [
@@ -107,48 +93,15 @@ function NtftalkVarSection() {
placeholderData: keepPreviousData,
});
- const draftIndexByClientId = useMemo(() => {
- const indexByClientId = new Map();
- draftVars.forEach((row, index) => {
- if (row.clientId) indexByClientId.set(row.clientId, index);
- });
- return indexByClientId;
- }, [draftVars]);
-
- const onDraftFieldChange = useCallback(
- (
- clientId: string,
- field: "varCd" | "varNm" | "varDesc" | "sender",
- value: string,
- ) => {
- const drafts = getValues("draftVars") ?? [];
- const draftIndex = drafts.findIndex(
- (r) => r.isDraft && r.clientId === clientId,
- );
- if (draftIndex === -1) return;
- setValue(`draftVars.${draftIndex}.${field}`, value, {
- shouldDirty: true,
- });
- },
- [getValues, setValue],
- );
-
- const varColumns = useMemo(
- () => createVarColumns({ onDraftFieldChange }),
- [onDraftFieldChange],
- );
-
const varTableRows = useMemo((): NtftalkVarGridRow[] => {
- const server = (varQuery.data?.content ?? []).filter(
+ return (varQuery.data?.content ?? []).filter(
(row) => !pendingDeleteVarCds.has(row.varCd),
);
- if (varPagination.pageIndex === 0) return [...server, ...draftVars];
- return server;
- }, [varQuery.data, draftVars, varPagination.pageIndex, pendingDeleteVarCds]);
+ }, [varQuery.data, pendingDeleteVarCds]);
const varTable = useReactTable({
data: varTableRows,
- columns: varColumns,
+ columns: createVarColumns(),
state: { pagination: varPagination, rowSelection: varRowSelection },
manualPagination: true,
rowCount: varQuery.data?.totalElements ?? 0,
@@ -158,17 +111,9 @@ function NtftalkVarSection() {
getCoreRowModel: getCoreRowModel(),
onPaginationChange: setVarPagination,
onRowSelectionChange: setVarRowSelection,
- getRowId: (row) =>
- row.isDraft && row.clientId
- ? `draft:${row.clientId}`
- : `srv:${row.varCd}`,
+ getRowId: (row) => `srv:${row.varCd}`,
});
- const handleAddVarRow = () => {
- append(createEmptyVarDraft(crypto.randomUUID()));
- setVarPagination((p) => ({ ...p, pageIndex: 0 }));
- };
-
const handleDeleteSelectedVars = async () => {
const selected = varTable.getSelectedRowModel().rows;
if (selected.length === 0) {
@@ -178,18 +123,9 @@ function NtftalkVarSection() {
if (!(await confirm(`선택한 ${selected.length}건을 삭제하시겠습니까?`)))
return;
- const serverCodes: string[] = [];
- const draftIndexes: number[] = [];
- selected.forEach((r) => {
- const o = r.original;
- if (o.isDraft && o.clientId) {
- const draftIndex = draftIndexByClientId.get(o.clientId);
- if (draftIndex !== undefined) draftIndexes.push(draftIndex);
- } else if (o.varCd) serverCodes.push(o.varCd);
- });
-
- if (draftIndexes.length)
- remove([...new Set(draftIndexes)].sort((a, b) => b - a));
+ const serverCodes = selected
+ .map((r) => r.original.varCd)
+ .filter((varCd): varCd is string => Boolean(varCd));
if (serverCodes.length) {
setPendingDeleteVarCds((prev) => {
@@ -208,29 +144,26 @@ function NtftalkVarSection() {
await queryClient.invalidateQueries({
queryKey: [ENDPOINT.NTFTALK_SERVICE.NTFTALK_VAR],
});
- replace([]);
setPendingDeleteVarCds(new Set());
setVarRowSelection({});
+ setAddVarDialogOpen(false);
alert("저장되었습니다.");
},
});
const handleVarRowClick = useCallback((row: NtftalkVarGridRow) => {
- if (row.isDraft) return;
setEditTargetVarCd(row.varCd);
}, []);
const handleSaveVars = () => {
- if (draftVars.length === 0 && pendingDeleteVarCds.size === 0) {
+ if (pendingDeleteVarCds.size === 0) {
alert("저장할 변경 사항이 없습니다.");
return;
}
let payload: NtftalkVarSavePayload[];
try {
payload = buildNtftalkVarBatchPayload({
- draftVars,
pendingDeleteVarCds,
- regr: userInfo?.userName ?? "",
});
} catch (e) {
alert(e instanceof Error ? e.message : "유효하지 않은 입력입니다.");
@@ -252,7 +185,7 @@ function NtftalkVarSection() {
type="button"
color="green"
className="h-[3.2rem]"
- onClick={handleAddVarRow}
+ onClick={() => setAddVarDialogOpen(true)}
>
변수추가
@@ -282,6 +215,11 @@ function NtftalkVarSection() {
onRowClick={handleVarRowClick}
/>
+