Merge branch 'main' of http://39.117.244.52:3000/kjs/ERP-node into feat/tableTypeMngHistFeat

This commit is contained in:
dohyeons 2025-10-21 15:13:06 +09:00
commit 7fe246bd93
1 changed files with 120 additions and 51 deletions

View File

@ -27,6 +27,24 @@ interface ScreenOption {
export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component, onUpdateProperty }) => { export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component, onUpdateProperty }) => {
const config = component.componentConfig || {}; const config = component.componentConfig || {};
// 로컬 상태 관리 (실시간 입력 반영)
const [localInputs, setLocalInputs] = useState({
text: config.text || "버튼",
modalTitle: config.action?.modalTitle || "",
editModalTitle: config.action?.editModalTitle || "",
editModalDescription: config.action?.editModalDescription || "",
targetUrl: config.action?.targetUrl || "",
});
const [localSelects, setLocalSelects] = useState({
variant: config.variant || "default",
size: config.size || "default",
actionType: config.action?.type || "save",
modalSize: config.action?.modalSize || "md",
editMode: config.action?.editMode || "modal",
});
const [screens, setScreens] = useState<ScreenOption[]>([]); const [screens, setScreens] = useState<ScreenOption[]>([]);
const [screensLoading, setScreensLoading] = useState(false); const [screensLoading, setScreensLoading] = useState(false);
const [modalScreenOpen, setModalScreenOpen] = useState(false); const [modalScreenOpen, setModalScreenOpen] = useState(false);
@ -34,6 +52,36 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
const [modalSearchTerm, setModalSearchTerm] = useState(""); const [modalSearchTerm, setModalSearchTerm] = useState("");
const [navSearchTerm, setNavSearchTerm] = useState(""); const [navSearchTerm, setNavSearchTerm] = useState("");
// 컴포넌트 변경 시 로컬 상태 동기화
useEffect(() => {
setLocalInputs({
text: config.text || "버튼",
modalTitle: config.action?.modalTitle || "",
editModalTitle: config.action?.editModalTitle || "",
editModalDescription: config.action?.editModalDescription || "",
targetUrl: config.action?.targetUrl || "",
});
setLocalSelects({
variant: config.variant || "default",
size: config.size || "default",
actionType: config.action?.type || "save",
modalSize: config.action?.modalSize || "md",
editMode: config.action?.editMode || "modal",
});
}, [
config.text,
config.variant,
config.size,
config.action?.type,
config.action?.modalTitle,
config.action?.modalSize,
config.action?.editMode,
config.action?.editModalTitle,
config.action?.editModalDescription,
config.action?.targetUrl,
]);
// 화면 목록 가져오기 // 화면 목록 가져오기
useEffect(() => { useEffect(() => {
const fetchScreens = async () => { const fetchScreens = async () => {
@ -86,8 +134,12 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
<Label htmlFor="button-text"> </Label> <Label htmlFor="button-text"> </Label>
<Input <Input
id="button-text" id="button-text"
value={config.text || "버튼"} value={localInputs.text}
onChange={(e) => onUpdateProperty("componentConfig.text", e.target.value)} onChange={(e) => {
const newValue = e.target.value;
setLocalInputs((prev) => ({ ...prev, text: newValue }));
onUpdateProperty("componentConfig.text", newValue);
}}
placeholder="버튼 텍스트를 입력하세요" placeholder="버튼 텍스트를 입력하세요"
/> />
</div> </div>
@ -95,8 +147,11 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
<div> <div>
<Label htmlFor="button-variant"> </Label> <Label htmlFor="button-variant"> </Label>
<Select <Select
value={config.variant || "default"} value={localSelects.variant}
onValueChange={(value) => onUpdateProperty("componentConfig.variant", value)} onValueChange={(value) => {
setLocalSelects((prev) => ({ ...prev, variant: value }));
onUpdateProperty("componentConfig.variant", value);
}}
> >
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="버튼 스타일 선택" /> <SelectValue placeholder="버튼 스타일 선택" />
@ -116,8 +171,11 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
<div> <div>
<Label htmlFor="button-size"> </Label> <Label htmlFor="button-size"> </Label>
<Select <Select
value={config.size || "default"} value={localSelects.size}
onValueChange={(value) => onUpdateProperty("componentConfig.size", value)} onValueChange={(value) => {
setLocalSelects((prev) => ({ ...prev, size: value }));
onUpdateProperty("componentConfig.size", value);
}}
> >
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="버튼 크기 선택" /> <SelectValue placeholder="버튼 크기 선택" />
@ -133,25 +191,27 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
<div> <div>
<Label htmlFor="button-action"> </Label> <Label htmlFor="button-action"> </Label>
<Select <Select
value={config.action?.type || "save"} value={localSelects.actionType}
defaultValue="save"
onValueChange={(value) => { onValueChange={(value) => {
// 액션 설정 업데이트 console.log("🔵 버튼 액션 변경:", {
onUpdateProperty("componentConfig.action", { type: value }); oldValue: localSelects.actionType,
newValue: value,
// 액션에 따른 라벨 색상 자동 설정 componentId: component.id,
if (value === 'delete') { });
// 로컬 상태 업데이트
setLocalSelects((prev) => ({ ...prev, actionType: value }));
// 액션 타입 업데이트
onUpdateProperty("componentConfig.action.type", value);
// 액션에 따른 라벨 색상 자동 설정 (별도 호출)
if (value === "delete") {
// 삭제 액션일 때 빨간색으로 설정 // 삭제 액션일 때 빨간색으로 설정
onUpdateProperty("style", { onUpdateProperty("style.labelColor", "#ef4444");
...component.style,
labelColor: '#ef4444'
});
} else { } else {
// 다른 액션일 때 기본 파란색으로 리셋 // 다른 액션일 때 기본색으로 리셋
onUpdateProperty("style", { onUpdateProperty("style.labelColor", "#212121");
...component.style,
labelColor: '#212121'
});
} }
}} }}
> >
@ -176,7 +236,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
</div> </div>
{/* 모달 열기 액션 설정 */} {/* 모달 열기 액션 설정 */}
{config.action?.type === "modal" && ( {localSelects.actionType === "modal" && (
<div className="mt-4 space-y-4 rounded-lg border bg-gray-50 p-4"> <div className="mt-4 space-y-4 rounded-lg border bg-gray-50 p-4">
<h4 className="text-sm font-medium text-gray-700"> </h4> <h4 className="text-sm font-medium text-gray-700"> </h4>
@ -185,26 +245,29 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
<Input <Input
id="modal-title" id="modal-title"
placeholder="모달 제목을 입력하세요" placeholder="모달 제목을 입력하세요"
value={config.action?.modalTitle || ""} value={localInputs.modalTitle}
onChange={(e) => onChange={(e) => {
const newValue = e.target.value;
setLocalInputs((prev) => ({ ...prev, modalTitle: newValue }));
onUpdateProperty("componentConfig.action", { onUpdateProperty("componentConfig.action", {
...config.action, ...config.action,
modalTitle: e.target.value, modalTitle: newValue,
}) });
} }}
/> />
</div> </div>
<div> <div>
<Label htmlFor="modal-size"> </Label> <Label htmlFor="modal-size"> </Label>
<Select <Select
value={config.action?.modalSize || "md"} value={localSelects.modalSize}
onValueChange={(value) => onValueChange={(value) => {
setLocalSelects((prev) => ({ ...prev, modalSize: value }));
onUpdateProperty("componentConfig.action", { onUpdateProperty("componentConfig.action", {
...config.action, ...config.action,
modalSize: value, modalSize: value,
}) });
} }}
> >
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="모달 크기 선택" /> <SelectValue placeholder="모달 크기 선택" />
@ -293,7 +356,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
)} )}
{/* 수정 액션 설정 */} {/* 수정 액션 설정 */}
{config.action?.type === "edit" && ( {localSelects.actionType === "edit" && (
<div className="mt-4 space-y-4 rounded-lg border bg-green-50 p-4"> <div className="mt-4 space-y-4 rounded-lg border bg-green-50 p-4">
<h4 className="text-sm font-medium text-gray-700"> </h4> <h4 className="text-sm font-medium text-gray-700"> </h4>
@ -375,13 +438,14 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
<div> <div>
<Label htmlFor="edit-mode"> </Label> <Label htmlFor="edit-mode"> </Label>
<Select <Select
value={config.action?.editMode || "modal"} value={localSelects.editMode}
onValueChange={(value) => onValueChange={(value) => {
setLocalSelects((prev) => ({ ...prev, editMode: value }));
onUpdateProperty("componentConfig.action", { onUpdateProperty("componentConfig.action", {
...config.action, ...config.action,
editMode: value, editMode: value,
}) });
} }}
> >
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="수정 모드 선택" /> <SelectValue placeholder="수정 모드 선택" />
@ -394,16 +458,17 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
</Select> </Select>
</div> </div>
{config.action?.editMode === "modal" && ( {localSelects.editMode === "modal" && (
<> <>
<div> <div>
<Label htmlFor="edit-modal-title"> </Label> <Label htmlFor="edit-modal-title"> </Label>
<Input <Input
id="edit-modal-title" id="edit-modal-title"
placeholder="모달 제목을 입력하세요 (예: 데이터 수정)" placeholder="모달 제목을 입력하세요 (예: 데이터 수정)"
value={config.action?.editModalTitle || ""} value={localInputs.editModalTitle}
onChange={(e) => { onChange={(e) => {
const newValue = e.target.value; const newValue = e.target.value;
setLocalInputs((prev) => ({ ...prev, editModalTitle: newValue }));
onUpdateProperty("componentConfig.action", { onUpdateProperty("componentConfig.action", {
...config.action, ...config.action,
editModalTitle: newValue, editModalTitle: newValue,
@ -420,9 +485,10 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
<Input <Input
id="edit-modal-description" id="edit-modal-description"
placeholder="모달 설명을 입력하세요 (예: 선택한 데이터를 수정합니다)" placeholder="모달 설명을 입력하세요 (예: 선택한 데이터를 수정합니다)"
value={config.action?.editModalDescription || ""} value={localInputs.editModalDescription}
onChange={(e) => { onChange={(e) => {
const newValue = e.target.value; const newValue = e.target.value;
setLocalInputs((prev) => ({ ...prev, editModalDescription: newValue }));
onUpdateProperty("componentConfig.action", { onUpdateProperty("componentConfig.action", {
...config.action, ...config.action,
editModalDescription: newValue, editModalDescription: newValue,
@ -437,13 +503,14 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
<div> <div>
<Label htmlFor="edit-modal-size"> </Label> <Label htmlFor="edit-modal-size"> </Label>
<Select <Select
value={config.action?.modalSize || "lg"} value={localSelects.modalSize}
onValueChange={(value) => onValueChange={(value) => {
setLocalSelects((prev) => ({ ...prev, modalSize: value }));
onUpdateProperty("componentConfig.action", { onUpdateProperty("componentConfig.action", {
...config.action, ...config.action,
modalSize: value, modalSize: value,
}) });
} }}
> >
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="모달 크기 선택" /> <SelectValue placeholder="모달 크기 선택" />
@ -463,7 +530,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
)} )}
{/* 페이지 이동 액션 설정 */} {/* 페이지 이동 액션 설정 */}
{config.action?.type === "navigate" && ( {localSelects.actionType === "navigate" && (
<div className="mt-4 space-y-4 rounded-lg border bg-gray-50 p-4"> <div className="mt-4 space-y-4 rounded-lg border bg-gray-50 p-4">
<h4 className="text-sm font-medium text-gray-700"> </h4> <h4 className="text-sm font-medium text-gray-700"> </h4>
@ -547,13 +614,15 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
<Input <Input
id="target-url" id="target-url"
placeholder="예: /admin/users 또는 https://example.com" placeholder="예: /admin/users 또는 https://example.com"
value={config.action?.targetUrl || ""} value={localInputs.targetUrl}
onChange={(e) => onChange={(e) => {
const newValue = e.target.value;
setLocalInputs((prev) => ({ ...prev, targetUrl: newValue }));
onUpdateProperty("componentConfig.action", { onUpdateProperty("componentConfig.action", {
...config.action, ...config.action,
targetUrl: e.target.value, targetUrl: newValue,
}) });
} }}
/> />
<p className="mt-1 text-xs text-gray-500">URL을 </p> <p className="mt-1 text-xs text-gray-500">URL을 </p>
</div> </div>
@ -564,7 +633,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
<div className="mt-8 border-t border-gray-200 pt-6"> <div className="mt-8 border-t border-gray-200 pt-6">
<div className="mb-4"> <div className="mb-4">
<h3 className="text-lg font-medium text-gray-900">🔧 </h3> <h3 className="text-lg font-medium text-gray-900">🔧 </h3>
<p className="mt-1 text-sm text-muted-foreground"> </p> <p className="text-muted-foreground mt-1 text-sm"> </p>
</div> </div>
<ImprovedButtonControlConfigPanel component={component} onUpdateProperty={onUpdateProperty} /> <ImprovedButtonControlConfigPanel component={component} onUpdateProperty={onUpdateProperty} />