"use client"; import React, { useState, useEffect, useMemo } from "react"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; import { Button } from "@/components/ui/button"; import { Check, ChevronsUpDown, Search } from "lucide-react"; import { cn } from "@/lib/utils"; import { ComponentData } from "@/types/screen"; import { apiClient } from "@/lib/api/client"; import { ButtonDataflowConfigPanel } from "./ButtonDataflowConfigPanel"; import { ImprovedButtonControlConfigPanel } from "./ImprovedButtonControlConfigPanel"; import { FlowVisibilityConfigPanel } from "./FlowVisibilityConfigPanel"; interface ButtonConfigPanelProps { component: ComponentData; onUpdateProperty: (path: string, value: any) => void; allComponents?: ComponentData[]; // ๐Ÿ†• ํ”Œ๋กœ์šฐ ์œ„์ ฏ ๊ฐ์ง€์šฉ currentTableName?: string; // ํ˜„์žฌ ํ™”๋ฉด์˜ ํ…Œ์ด๋ธ”๋ช… (์ž๋™ ๊ฐ์ง€์šฉ) } interface ScreenOption { id: number; name: string; description?: string; } export const ButtonConfigPanel: React.FC = ({ component, onUpdateProperty, allComponents = [], // ๐Ÿ†• ๊ธฐ๋ณธ๊ฐ’ ๋นˆ ๋ฐฐ์—ด currentTableName, // ํ˜„์žฌ ํ™”๋ฉด์˜ ํ…Œ์ด๋ธ”๋ช… }) => { // ๐Ÿ”ง component์—์„œ ์ง์ ‘ ์ฝ๊ธฐ (useMemo ์ œ๊ฑฐ) const config = component.componentConfig || {}; const currentAction = component.componentConfig?.action || {}; // ๋กœ์ปฌ ์ƒํƒœ ๊ด€๋ฆฌ (์‹ค์‹œ๊ฐ„ ์ž…๋ ฅ ๋ฐ˜์˜) const [localInputs, setLocalInputs] = useState({ text: config.text !== undefined ? config.text : "๋ฒ„ํŠผ", modalTitle: config.action?.modalTitle || "", editModalTitle: config.action?.editModalTitle || "", editModalDescription: config.action?.editModalDescription || "", targetUrl: config.action?.targetUrl || "", }); const [screens, setScreens] = useState([]); const [screensLoading, setScreensLoading] = useState(false); const [modalScreenOpen, setModalScreenOpen] = useState(false); const [navScreenOpen, setNavScreenOpen] = useState(false); const [modalSearchTerm, setModalSearchTerm] = useState(""); const [navSearchTerm, setNavSearchTerm] = useState(""); // ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ ๋ชฉ๋ก ์ƒํƒœ const [tableColumns, setTableColumns] = useState([]); const [columnsLoading, setColumnsLoading] = useState(false); const [displayColumnOpen, setDisplayColumnOpen] = useState(false); const [displayColumnSearch, setDisplayColumnSearch] = useState(""); // ์ปดํฌ๋„ŒํŠธ prop ๋ณ€๊ฒฝ ์‹œ ๋กœ์ปฌ ์ƒํƒœ ๋™๊ธฐํ™” (Input๋งŒ) useEffect(() => { const latestConfig = component.componentConfig || {}; const latestAction = latestConfig.action || {}; setLocalInputs({ text: latestConfig.text !== undefined ? latestConfig.text : "๋ฒ„ํŠผ", modalTitle: latestAction.modalTitle || "", editModalTitle: latestAction.editModalTitle || "", editModalDescription: latestAction.editModalDescription || "", targetUrl: latestAction.targetUrl || "", }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [component.id]); // ํ™”๋ฉด ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ (์ „์ฒด ๋ชฉ๋ก) useEffect(() => { const fetchScreens = async () => { try { setScreensLoading(true); // ์ „์ฒด ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด size๋ฅผ ํฐ ๊ฐ’์œผ๋กœ ์„ค์ • const response = await apiClient.get("/screen-management/screens", { params: { page: 1, size: 9999, // ๋งค์šฐ ํฐ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•˜์—ฌ ์ „์ฒด ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ }, }); if (response.data.success && Array.isArray(response.data.data)) { const screenList = response.data.data.map((screen: any) => ({ id: screen.screenId, name: screen.screenName, description: screen.description, })); setScreens(screenList); } } catch (error) { // console.error("โŒ ํ™”๋ฉด ๋ชฉ๋ก ๋กœ๋”ฉ ์‹คํŒจ:", error); } finally { setScreensLoading(false); } }; fetchScreens(); }, []); // ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ (ํ…Œ์ด๋ธ” ์ด๋ ฅ ๋ณด๊ธฐ ์•ก์…˜์ผ ๋•Œ) useEffect(() => { const fetchTableColumns = async () => { // ํ…Œ์ด๋ธ” ์ด๋ ฅ ๋ณด๊ธฐ ์•ก์…˜์ด ์•„๋‹ˆ๋ฉด ์Šคํ‚ต if (config.action?.type !== "view_table_history") { return; } // 1. ์ˆ˜๋™ ์ž…๋ ฅ๋œ ํ…Œ์ด๋ธ”๋ช… ์šฐ์„  // 2. ์—†์œผ๋ฉด ํ˜„์žฌ ํ™”๋ฉด์˜ ํ…Œ์ด๋ธ”๋ช… ์‚ฌ์šฉ const tableName = config.action?.historyTableName || currentTableName; // ํ…Œ์ด๋ธ”๋ช…์ด ์—†์œผ๋ฉด ์Šคํ‚ต if (!tableName) { return; } try { setColumnsLoading(true); const response = await apiClient.get(`/table-management/tables/${tableName}/columns`, { params: { page: 1, size: 9999, // ์ „์ฒด ์ปฌ๋Ÿผ ๊ฐ€์ ธ์˜ค๊ธฐ }, }); // API ์‘๋‹ต ๊ตฌ์กฐ: { success, data: { columns: [...], total, page, totalPages } } const columnData = response.data.data?.columns; if (!columnData || !Array.isArray(columnData)) { console.error("โŒ ์ปฌ๋Ÿผ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐฐ์—ด์ด ์•„๋‹™๋‹ˆ๋‹ค:", columnData); setTableColumns([]); return; } if (response.data.success) { // ID ์ปฌ๋Ÿผ๊ณผ ๋‚ ์งœ ๊ด€๋ จ ์ปฌ๋Ÿผ ์ œ์™ธ const filteredColumns = columnData .filter((col: any) => { const colName = col.columnName.toLowerCase(); const dataType = col.dataType?.toLowerCase() || ""; // ID ์ปฌ๋Ÿผ ์ œ์™ธ (id, _id๋กœ ๋๋‚˜๋Š” ์ปฌ๋Ÿผ) if (colName === "id" || colName.endsWith("_id")) { return false; } // ๋‚ ์งœ/์‹œ๊ฐ„ ํƒ€์ž… ์ œ์™ธ (๋ฐ์ดํ„ฐ ํƒ€์ž… ๊ธฐ์ค€) if (dataType.includes("date") || dataType.includes("time") || dataType.includes("timestamp")) { return false; } // ๋‚ ์งœ/์‹œ๊ฐ„ ๊ด€๋ จ ์ปฌ๋Ÿผ๋ช… ์ œ์™ธ (์ปฌ๋Ÿผ๋ช…์— date, time, at ํฌํ•จ) if ( colName.includes("date") || colName.includes("time") || colName.endsWith("_at") || colName.startsWith("created") || colName.startsWith("updated") ) { return false; } return true; }) .map((col: any) => col.columnName); setTableColumns(filteredColumns); } } catch (error) { console.error("โŒ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ ๋กœ๋”ฉ ์‹คํŒจ:", error); } finally { setColumnsLoading(false); } }; fetchTableColumns(); }, [config.action?.type, config.action?.historyTableName, currentTableName]); // ๊ฒ€์ƒ‰ ํ•„ํ„ฐ๋ง ํ•จ์ˆ˜ const filterScreens = (searchTerm: string) => { if (!searchTerm.trim()) return screens; return screens.filter( (screen) => screen.name.toLowerCase().includes(searchTerm.toLowerCase()) || (screen.description && screen.description.toLowerCase().includes(searchTerm.toLowerCase())), ); }; // console.log("๐Ÿ”ง config-panels/ButtonConfigPanel ๋ Œ๋”๋ง:", { // component, // config, // action: config.action, // actionType: config.action?.type, // screensCount: screens.length, // }); return (
{ const newValue = e.target.value; setLocalInputs((prev) => ({ ...prev, text: newValue })); onUpdateProperty("componentConfig.text", newValue); }} placeholder="๋ฒ„ํŠผ ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”" />
{/* ๋ชจ๋‹ฌ ์—ด๊ธฐ ์•ก์…˜ ์„ค์ • */} {(component.componentConfig?.action?.type || "save") === "modal" && (

๋ชจ๋‹ฌ ์„ค์ •

{ const newValue = e.target.value; setLocalInputs((prev) => ({ ...prev, modalTitle: newValue })); onUpdateProperty("componentConfig.action.modalTitle", newValue); }} />
setModalSearchTerm(e.target.value)} className="border-0 p-0 focus-visible:ring-0" />
{(() => { const filteredScreens = filterScreens(modalSearchTerm); if (screensLoading) { return
ํ™”๋ฉด ๋ชฉ๋ก์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘...
; } if (filteredScreens.length === 0) { return
๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
; } return filteredScreens.map((screen, index) => (
{ onUpdateProperty("componentConfig.action.targetScreenId", screen.id); setModalScreenOpen(false); setModalSearchTerm(""); }} >
{screen.name} {screen.description && {screen.description}}
)); })()}
)} {/* ์ˆ˜์ • ์•ก์…˜ ์„ค์ • */} {(component.componentConfig?.action?.type || "save") === "edit" && (

์ˆ˜์ • ์„ค์ •

setModalSearchTerm(e.target.value)} className="border-0 p-0 focus-visible:ring-0" />
{(() => { const filteredScreens = filterScreens(modalSearchTerm); if (screensLoading) { return
ํ™”๋ฉด ๋ชฉ๋ก์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘...
; } if (filteredScreens.length === 0) { return
๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
; } return filteredScreens.map((screen, index) => (
{ onUpdateProperty("componentConfig.action.targetScreenId", screen.id); setModalScreenOpen(false); setModalSearchTerm(""); }} >
{screen.name} {screen.description && {screen.description}}
)); })()}

์„ ํƒ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ด ํผ ํ™”๋ฉด์— ์ž๋™์œผ๋กœ ๋กœ๋“œ๋˜์–ด ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

{(component.componentConfig?.action?.editMode || "modal") === "modal" && ( <>
{ const newValue = e.target.value; setLocalInputs((prev) => ({ ...prev, editModalTitle: newValue })); onUpdateProperty("componentConfig.action.editModalTitle", newValue); onUpdateProperty("webTypeConfig.editModalTitle", newValue); }} />

๋น„์›Œ๋‘๋ฉด ๊ธฐ๋ณธ ์ œ๋ชฉ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค

{ const newValue = e.target.value; setLocalInputs((prev) => ({ ...prev, editModalDescription: newValue })); onUpdateProperty("componentConfig.action.editModalDescription", newValue); onUpdateProperty("webTypeConfig.editModalDescription", newValue); }} />

๋น„์›Œ๋‘๋ฉด ์„ค๋ช…์ด ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

)}
)} {/* ํ…Œ์ด๋ธ” ์ด๋ ฅ ๋ณด๊ธฐ ์•ก์…˜ ์„ค์ • */} {(component.componentConfig?.action?.type || "save") === "view_table_history" && (

๐Ÿ“œ ํ…Œ์ด๋ธ” ์ด๋ ฅ ๋ณด๊ธฐ ์„ค์ •

{!config.action?.historyTableName && !currentTableName ? (

โš ๏ธ ๋จผ์ € ํ…Œ์ด๋ธ”๋ช…์„ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜, ํ˜„์žฌ ํ™”๋ฉด์— ํ…Œ์ด๋ธ”์„ ์—ฐ๊ฒฐํ•ด์ฃผ์„ธ์š”.

) : ( <> {!config.action?.historyTableName && currentTableName && (

โœ“ ํ˜„์žฌ ํ™”๋ฉด์˜ ํ…Œ์ด๋ธ” {currentTableName}์„(๋ฅผ) ์ž๋™์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

)} ์ปฌ๋Ÿผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. {tableColumns.map((column) => ( { onUpdateProperty("componentConfig.action.historyDisplayColumn", currentValue); setDisplayColumnOpen(false); }} className="text-sm" > {column} ))}

์ „์ฒด ํ…Œ์ด๋ธ” ์ด๋ ฅ์—์„œ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ์ปฌ๋Ÿผ์ž…๋‹ˆ๋‹ค.
์˜ˆ: device_code๋ฅผ ์„ค์ •ํ•˜๋ฉด ์ด๋ ฅ์— "DTG-001"๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
์ด ์ปฌ๋Ÿผ์œผ๋กœ ๊ฒ€์ƒ‰๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

{tableColumns.length === 0 && !columnsLoading && (

โš ๏ธ ID ๋ฐ ๋‚ ์งœ ํƒ€์ž… ์ปฌ๋Ÿผ์„ ์ œ์™ธํ•œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปฌ๋Ÿผ์ด ์—†์Šต๋‹ˆ๋‹ค.

)} )}
)} {/* ํŽ˜์ด์ง€ ์ด๋™ ์•ก์…˜ ์„ค์ • */} {(component.componentConfig?.action?.type || "save") === "navigate" && (

ํŽ˜์ด์ง€ ์ด๋™ ์„ค์ •

setNavSearchTerm(e.target.value)} className="border-0 p-0 focus-visible:ring-0" />
{(() => { const filteredScreens = filterScreens(navSearchTerm); if (screensLoading) { return
ํ™”๋ฉด ๋ชฉ๋ก์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘...
; } if (filteredScreens.length === 0) { return
๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
; } return filteredScreens.map((screen, index) => (
{ onUpdateProperty("componentConfig.action.targetScreenId", screen.id); setNavScreenOpen(false); setNavSearchTerm(""); }} >
{screen.name} {screen.description && {screen.description}}
)); })()}

์„ ํƒํ•œ ํ™”๋ฉด์œผ๋กœ /screens/{"{"}ํ™”๋ฉดID{"}"} ํ˜•ํƒœ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค

{ const newValue = e.target.value; setLocalInputs((prev) => ({ ...prev, targetUrl: newValue })); onUpdateProperty("componentConfig.action.targetUrl", newValue); }} />

URL์„ ์ž…๋ ฅํ•˜๋ฉด ํ™”๋ฉด ์„ ํƒ๋ณด๋‹ค ์šฐ์„  ์ ์šฉ๋ฉ๋‹ˆ๋‹ค

)} {/* ์ œ์–ด ๊ธฐ๋Šฅ ์„น์…˜ */}
{/* ๐Ÿ†• ํ”Œ๋กœ์šฐ ๋‹จ๊ณ„๋ณ„ ํ‘œ์‹œ ์ œ์–ด ์„น์…˜ */}
); };