refactor: 코드 정리 및 가독성 향상
- numberingRuleController.ts에서 API 엔드포인트의 코드 스타일을 일관되게 정리하여 가독성을 높였습니다. - 불필요한 줄바꿈을 제거하고, 코드 블록을 명확하게 정리하여 유지보수성을 개선했습니다. - tableManagementService.ts와 ButtonConfigPanel.tsx에서 코드 정리를 통해 일관성을 유지하고, 가독성을 향상시켰습니다. - 전반적으로 코드의 깔끔함을 유지하고, 향후 개발 시 이해하기 쉽게 개선했습니다.
This commit is contained in:
@@ -65,7 +65,7 @@ export function TabsWidget({
|
||||
const [selectedTab, setSelectedTab] = useState<string>(getInitialTab());
|
||||
const [visibleTabs, setVisibleTabs] = useState<ExtendedTabItem[]>(tabs as ExtendedTabItem[]);
|
||||
const [mountedTabs, setMountedTabs] = useState<Set<string>>(() => new Set([getInitialTab()]));
|
||||
|
||||
|
||||
// 🆕 화면 진입 시 첫 번째 탭 자동 선택 및 마운트
|
||||
useEffect(() => {
|
||||
// 현재 선택된 탭이 유효하지 않거나 비어있으면 첫 번째 탭 선택
|
||||
@@ -92,7 +92,7 @@ export function TabsWidget({
|
||||
});
|
||||
}
|
||||
}, [tabs]); // tabs가 변경될 때마다 실행
|
||||
|
||||
|
||||
// screenId 기반 화면 로드 상태
|
||||
const [screenLayouts, setScreenLayouts] = useState<Record<string, ComponentData[]>>({});
|
||||
const [screenLoadingStates, setScreenLoadingStates] = useState<Record<string, boolean>>({});
|
||||
@@ -109,23 +109,28 @@ export function TabsWidget({
|
||||
for (const tab of visibleTabs) {
|
||||
const extTab = tab as ExtendedTabItem;
|
||||
// screenId가 있고, 아직 로드하지 않았으며, 인라인 컴포넌트가 없는 경우만 로드
|
||||
if (extTab.screenId && !screenLayouts[tab.id] && !screenLoadingStates[tab.id] && (!extTab.components || extTab.components.length === 0)) {
|
||||
setScreenLoadingStates(prev => ({ ...prev, [tab.id]: true }));
|
||||
if (
|
||||
extTab.screenId &&
|
||||
!screenLayouts[tab.id] &&
|
||||
!screenLoadingStates[tab.id] &&
|
||||
(!extTab.components || extTab.components.length === 0)
|
||||
) {
|
||||
setScreenLoadingStates((prev) => ({ ...prev, [tab.id]: true }));
|
||||
try {
|
||||
const layoutData = await screenApi.getLayout(extTab.screenId);
|
||||
if (layoutData && layoutData.components) {
|
||||
setScreenLayouts(prev => ({ ...prev, [tab.id]: layoutData.components }));
|
||||
setScreenLayouts((prev) => ({ ...prev, [tab.id]: layoutData.components }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`탭 "${tab.label}" 화면 로드 실패:`, error);
|
||||
setScreenErrors(prev => ({ ...prev, [tab.id]: "화면을 불러올 수 없습니다." }));
|
||||
setScreenErrors((prev) => ({ ...prev, [tab.id]: "화면을 불러올 수 없습니다." }));
|
||||
} finally {
|
||||
setScreenLoadingStates(prev => ({ ...prev, [tab.id]: false }));
|
||||
setScreenLoadingStates((prev) => ({ ...prev, [tab.id]: false }));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
loadScreenLayouts();
|
||||
}, [visibleTabs, screenLayouts, screenLoadingStates]);
|
||||
|
||||
@@ -180,11 +185,7 @@ export function TabsWidget({
|
||||
const getTabsListClass = () => {
|
||||
const baseClass = orientation === "vertical" ? "flex-col" : "";
|
||||
const variantClass =
|
||||
variant === "pills"
|
||||
? "bg-muted p-1 rounded-lg"
|
||||
: variant === "underline"
|
||||
? "border-b"
|
||||
: "bg-muted p-1";
|
||||
variant === "pills" ? "bg-muted p-1 rounded-lg" : variant === "underline" ? "border-b" : "bg-muted p-1";
|
||||
return `${baseClass} ${variantClass}`;
|
||||
};
|
||||
|
||||
@@ -192,47 +193,47 @@ export function TabsWidget({
|
||||
const renderTabContent = (tab: ExtendedTabItem) => {
|
||||
const extTab = tab as ExtendedTabItem;
|
||||
const inlineComponents = tab.components || [];
|
||||
|
||||
|
||||
// 1. screenId가 있고 인라인 컴포넌트가 없는 경우 -> 화면 로드 방식
|
||||
if (extTab.screenId && inlineComponents.length === 0) {
|
||||
// 로딩 중
|
||||
if (screenLoadingStates[tab.id]) {
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
||||
<span className="ml-2 text-muted-foreground">화면을 불러오는 중...</span>
|
||||
<Loader2 className="text-primary h-8 w-8 animate-spin" />
|
||||
<span className="text-muted-foreground ml-2">화면을 불러오는 중...</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// 에러 발생
|
||||
if (screenErrors[tab.id]) {
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center rounded border-2 border-dashed border-destructive/50 bg-destructive/5">
|
||||
<div className="border-destructive/50 bg-destructive/5 flex h-full w-full items-center justify-center rounded border-2 border-dashed">
|
||||
<p className="text-destructive text-sm">{screenErrors[tab.id]}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// 화면 레이아웃이 로드된 경우
|
||||
const loadedComponents = screenLayouts[tab.id];
|
||||
if (loadedComponents && loadedComponents.length > 0) {
|
||||
return renderScreenComponents(loadedComponents);
|
||||
}
|
||||
|
||||
|
||||
// 아직 로드되지 않은 경우
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
||||
<Loader2 className="text-primary h-8 w-8 animate-spin" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// 2. 인라인 컴포넌트가 있는 경우 -> 기존 v2 방식
|
||||
if (inlineComponents.length > 0) {
|
||||
return renderInlineComponents(tab, inlineComponents);
|
||||
}
|
||||
|
||||
|
||||
// 3. 둘 다 없는 경우
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center rounded border-2 border-dashed border-gray-300 bg-gray-50">
|
||||
@@ -246,22 +247,17 @@ export function TabsWidget({
|
||||
// screenId로 로드한 화면 컴포넌트 렌더링
|
||||
const renderScreenComponents = (components: ComponentData[]) => {
|
||||
// InteractiveScreenViewerDynamic 동적 로드
|
||||
const InteractiveScreenViewerDynamic = require("@/components/screen/InteractiveScreenViewerDynamic").InteractiveScreenViewerDynamic;
|
||||
|
||||
const InteractiveScreenViewerDynamic =
|
||||
require("@/components/screen/InteractiveScreenViewerDynamic").InteractiveScreenViewerDynamic;
|
||||
|
||||
// 컴포넌트들의 최대 위치를 계산하여 스크롤 가능한 영역 확보
|
||||
const maxBottom = Math.max(
|
||||
...components.map((c) => (c.position?.y || 0) + (c.size?.height || 100)),
|
||||
300
|
||||
);
|
||||
const maxRight = Math.max(
|
||||
...components.map((c) => (c.position?.x || 0) + (c.size?.width || 200)),
|
||||
400
|
||||
);
|
||||
|
||||
const maxBottom = Math.max(...components.map((c) => (c.position?.y || 0) + (c.size?.height || 100)), 300);
|
||||
const maxRight = Math.max(...components.map((c) => (c.position?.x || 0) + (c.size?.width || 200)), 400);
|
||||
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
className="relative h-full w-full overflow-auto"
|
||||
style={{
|
||||
style={{
|
||||
minHeight: maxBottom + 20,
|
||||
minWidth: maxRight + 20,
|
||||
}}
|
||||
@@ -295,17 +291,17 @@ export function TabsWidget({
|
||||
// 컴포넌트들의 최대 위치를 계산하여 스크롤 가능한 영역 확보
|
||||
const maxBottom = Math.max(
|
||||
...components.map((c) => (c.position?.y || 0) + (c.size?.height || 100)),
|
||||
300 // 최소 높이
|
||||
300, // 최소 높이
|
||||
);
|
||||
const maxRight = Math.max(
|
||||
...components.map((c) => (c.position?.x || 0) + (c.size?.width || 200)),
|
||||
400 // 최소 너비
|
||||
400, // 최소 너비
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative"
|
||||
style={{
|
||||
<div
|
||||
className="relative"
|
||||
style={{
|
||||
minHeight: maxBottom + 20,
|
||||
minWidth: maxRight + 20,
|
||||
}}
|
||||
@@ -319,7 +315,7 @@ export function TabsWidget({
|
||||
className={cn(
|
||||
"absolute",
|
||||
isDesignMode && "cursor-move",
|
||||
isDesignMode && isSelected && "ring-2 ring-primary ring-offset-2"
|
||||
isDesignMode && isSelected && "ring-primary ring-2 ring-offset-2",
|
||||
)}
|
||||
style={{
|
||||
left: comp.position?.x || 0,
|
||||
@@ -380,9 +376,7 @@ export function TabsWidget({
|
||||
<TabsTrigger value={tab.id} disabled={tab.disabled} className="relative pr-8">
|
||||
{tab.label}
|
||||
{tab.components && tab.components.length > 0 && (
|
||||
<span className="ml-1 text-xs text-muted-foreground">
|
||||
({tab.components.length})
|
||||
</span>
|
||||
<span className="text-muted-foreground ml-1 text-xs">({tab.components.length})</span>
|
||||
)}
|
||||
</TabsTrigger>
|
||||
{allowCloseable && (
|
||||
@@ -390,7 +384,7 @@ export function TabsWidget({
|
||||
onClick={(e) => handleCloseTab(tab.id, e)}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="absolute right-1 top-1/2 h-5 w-5 -translate-y-1/2 p-0 hover:bg-destructive/10"
|
||||
className="hover:bg-destructive/10 absolute top-1/2 right-1 h-5 w-5 -translate-y-1/2 p-0"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user