버튼 비활성화 로직
This commit is contained in:
parent
b45f4870e8
commit
c78326bae1
|
|
@ -3081,6 +3081,79 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
/>
|
||||
)}
|
||||
|
||||
{/* 🆕 행 선택 시에만 활성화 설정 */}
|
||||
<div className="mt-4 space-y-4 rounded-lg border bg-muted/50 p-4">
|
||||
<h4 className="text-sm font-medium text-foreground">행 선택 활성화 조건</h4>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
테이블 리스트나 분할 패널에서 데이터가 선택되었을 때만 버튼을 활성화합니다.
|
||||
</p>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-0.5">
|
||||
<Label>행 선택 시에만 활성화</Label>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
체크하면 테이블에서 행을 선택해야만 버튼이 활성화됩니다.
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={component.componentConfig?.action?.requireRowSelection || false}
|
||||
onCheckedChange={(checked) => {
|
||||
onUpdateProperty("componentConfig.action.requireRowSelection", checked);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{component.componentConfig?.action?.requireRowSelection && (
|
||||
<div className="space-y-3 pl-4 border-l-2 border-primary/20">
|
||||
<div>
|
||||
<Label htmlFor="row-selection-source">선택 데이터 소스</Label>
|
||||
<Select
|
||||
value={component.componentConfig?.action?.rowSelectionSource || "auto"}
|
||||
onValueChange={(value) => {
|
||||
onUpdateProperty("componentConfig.action.rowSelectionSource", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue placeholder="데이터 소스 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="auto">자동 감지 (권장)</SelectItem>
|
||||
<SelectItem value="tableList">테이블 리스트 선택</SelectItem>
|
||||
<SelectItem value="splitPanelLeft">분할 패널 좌측 선택</SelectItem>
|
||||
<SelectItem value="flowWidget">플로우 위젯 선택</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
자동 감지: 테이블, 분할 패널, 플로우 위젯 중 선택된 항목이 있으면 활성화
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-0.5">
|
||||
<Label>다중 선택 허용</Label>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
여러 행이 선택되어도 활성화 (기본: 1개 이상 선택 시 활성화)
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={component.componentConfig?.action?.allowMultiRowSelection ?? true}
|
||||
onCheckedChange={(checked) => {
|
||||
onUpdateProperty("componentConfig.action.allowMultiRowSelection", checked);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{!(component.componentConfig?.action?.allowMultiRowSelection ?? true) && (
|
||||
<div className="rounded-md bg-yellow-50 p-2 dark:bg-yellow-950/20">
|
||||
<p className="text-xs text-yellow-800 dark:text-yellow-200">
|
||||
정확히 1개의 행만 선택되어야 버튼이 활성화됩니다.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 제어 기능 섹션 */}
|
||||
<div className="mt-8 border-t border-border pt-6">
|
||||
<ImprovedButtonControlConfigPanel component={component} onUpdateProperty={onUpdateProperty} />
|
||||
|
|
|
|||
|
|
@ -296,6 +296,84 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
|||
return false;
|
||||
}, [component.componentConfig?.action, formData, vehicleStatus, statusLoading, component.label]);
|
||||
|
||||
// 🆕 행 선택 기반 비활성화 조건 계산
|
||||
const isRowSelectionDisabled = useMemo(() => {
|
||||
const actionConfig = component.componentConfig?.action;
|
||||
|
||||
// requireRowSelection이 활성화되어 있지 않으면 비활성화하지 않음
|
||||
if (!actionConfig?.requireRowSelection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rowSelectionSource = actionConfig.rowSelectionSource || "auto";
|
||||
const allowMultiRowSelection = actionConfig.allowMultiRowSelection ?? true;
|
||||
|
||||
// 선택된 데이터 확인
|
||||
let hasSelection = false;
|
||||
let selectionCount = 0;
|
||||
|
||||
// 1. 자동 감지 모드 또는 특정 소스 모드
|
||||
if (rowSelectionSource === "auto" || rowSelectionSource === "tableList") {
|
||||
// TableList에서 선택된 행 확인 (props로 전달됨)
|
||||
if (selectedRowsData && selectedRowsData.length > 0) {
|
||||
hasSelection = true;
|
||||
selectionCount = selectedRowsData.length;
|
||||
}
|
||||
// 또는 selectedRows prop 확인
|
||||
else if (selectedRows && selectedRows.length > 0) {
|
||||
hasSelection = true;
|
||||
selectionCount = selectedRows.length;
|
||||
}
|
||||
}
|
||||
|
||||
if (rowSelectionSource === "auto" || rowSelectionSource === "splitPanelLeft") {
|
||||
// 분할 패널 좌측 선택 데이터 확인
|
||||
if (!hasSelection && splitPanelContext?.selectedLeftData) {
|
||||
hasSelection = true;
|
||||
selectionCount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (rowSelectionSource === "auto" || rowSelectionSource === "flowWidget") {
|
||||
// 플로우 위젯 선택 데이터 확인
|
||||
if (!hasSelection && flowSelectedData && flowSelectedData.length > 0) {
|
||||
hasSelection = true;
|
||||
selectionCount = flowSelectedData.length;
|
||||
}
|
||||
}
|
||||
|
||||
// 선택된 데이터가 없으면 비활성화
|
||||
if (!hasSelection) {
|
||||
console.log("🚫 [ButtonPrimary] 행 선택 필요 → 비활성화:", component.label, {
|
||||
rowSelectionSource,
|
||||
hasSelection,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// 다중 선택 허용하지 않는 경우, 정확히 1개만 선택되어야 함
|
||||
if (!allowMultiRowSelection && selectionCount !== 1) {
|
||||
console.log("🚫 [ButtonPrimary] 정확히 1개 행 선택 필요 → 비활성화:", component.label, {
|
||||
selectionCount,
|
||||
allowMultiRowSelection,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log("✅ [ButtonPrimary] 행 선택 조건 충족:", component.label, {
|
||||
selectionCount,
|
||||
rowSelectionSource,
|
||||
});
|
||||
return false;
|
||||
}, [
|
||||
component.componentConfig?.action,
|
||||
component.label,
|
||||
selectedRows,
|
||||
selectedRowsData,
|
||||
splitPanelContext?.selectedLeftData,
|
||||
flowSelectedData,
|
||||
]);
|
||||
|
||||
// 확인 다이얼로그 상태
|
||||
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
|
||||
const [pendingAction, setPendingAction] = useState<{
|
||||
|
|
@ -1096,17 +1174,26 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
|||
}
|
||||
}
|
||||
|
||||
// 🆕 최종 비활성화 상태 (설정 + 조건부 비활성화)
|
||||
const finalDisabled = componentConfig.disabled || isOperationButtonDisabled || statusLoading;
|
||||
// 🆕 최종 비활성화 상태 (설정 + 조건부 비활성화 + 행 선택 필수)
|
||||
const finalDisabled = componentConfig.disabled || isOperationButtonDisabled || isRowSelectionDisabled || statusLoading;
|
||||
|
||||
// 공통 버튼 스타일
|
||||
// 🔧 component.style에서 background/backgroundColor 충돌 방지
|
||||
const userStyle = component.style
|
||||
? Object.fromEntries(
|
||||
Object.entries(component.style).filter(
|
||||
([key]) => !["width", "height", "background", "backgroundColor"].includes(key)
|
||||
)
|
||||
)
|
||||
: {};
|
||||
|
||||
const buttonElementStyle: React.CSSProperties = {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
minHeight: "40px",
|
||||
border: "none",
|
||||
borderRadius: "0.5rem",
|
||||
background: finalDisabled ? "#e5e7eb" : buttonColor,
|
||||
backgroundColor: finalDisabled ? "#e5e7eb" : buttonColor, // 🔧 background → backgroundColor로 변경
|
||||
color: finalDisabled ? "#9ca3af" : "white",
|
||||
// 🔧 크기 설정 적용 (sm/md/lg)
|
||||
fontSize: componentConfig.size === "sm" ? "0.75rem" : componentConfig.size === "lg" ? "1rem" : "0.875rem",
|
||||
|
|
@ -1122,10 +1209,8 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
|
|||
margin: "0",
|
||||
lineHeight: "1.25",
|
||||
boxShadow: finalDisabled ? "none" : "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
|
||||
// 디자인 모드와 인터랙티브 모드 모두에서 사용자 스타일 적용 (width/height 제외)
|
||||
...(component.style
|
||||
? Object.fromEntries(Object.entries(component.style).filter(([key]) => key !== "width" && key !== "height"))
|
||||
: {}),
|
||||
// 디자인 모드와 인터랙티브 모드 모두에서 사용자 스타일 적용 (width/height/background 제외)
|
||||
...userStyle,
|
||||
};
|
||||
|
||||
const buttonContent = processedConfig.text !== undefined ? processedConfig.text : component.label || "버튼";
|
||||
|
|
|
|||
Loading…
Reference in New Issue