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