Files
frontend/apps/sn/app/(map-layout)/map/components/gisEdit/GisEditToolbar.tsx
T

167 lines
5.7 KiB
TypeScript

/**
* 화면명: 하수관로 편집 도구
* 관로 추가·이동·꼭지점 편집·삭제 도구를 선택하고 제어한다.
*/
"use client";
import { Check, Move, PenTool, Plus, Trash2, X } from "lucide-react";
import { Button } from "@common/components/ui";
import type { GisEditTool } from "./gisEditTypes";
import { useGisEditOperationLabels } from "./useGisEditCommonCodes";
type Props = {
isEditMode: boolean;
activeTool: GisEditTool | null;
isSnapEnabled: boolean;
canUseTools: boolean;
canSave: boolean;
isSaving?: boolean;
statusMessage: string;
allowedTools?: GisEditTool[];
onClose?: () => void;
onToggleSnap: () => void;
onSelectTool: (tool: GisEditTool) => void;
onSave: () => void;
};
const TOOL_BUTTONS: Array<{
tool: GisEditTool;
icon: typeof Plus;
}> = [
{ tool: "ADD", icon: Plus },
{ tool: "MOVE", icon: Move },
{ tool: "VERTEX_EDIT", icon: PenTool },
{ tool: "DELETE", icon: Trash2 },
];
export default function GisEditToolbar({
isEditMode,
activeTool,
isSnapEnabled,
canUseTools,
canSave,
isSaving = false,
statusMessage,
allowedTools = [],
onClose,
onToggleSnap,
onSelectTool,
onSave,
}: Props) {
// 버튼의 업무 코드값은 그대로 유지하고 CMS 공통코드명만 화면 라벨로 사용한다.
const operationLabels = useGisEditOperationLabels();
if (!isEditMode) return null;
return (
<div
data-testid="gis-edit-toolbar"
className="absolute bottom-4 left-1/2 z-[60] flex w-[min(980px,calc(100%-2rem))] -translate-x-1/2 flex-col"
>
<div className="card !m-0 flex !border-0 !bg-background !p-[0.8rem] shadow-[0_1px_2px_rgba(60,64,67,0.3),0_1px_3px_1px_rgba(60,64,67,0.15)]">
<div className="flex w-full items-center gap-3 overflow-hidden">
<div className="flex w-[168px] shrink-0 flex-col justify-center border-r border-border pr-3">
<span className="whitespace-nowrap text-[1.3rem] font-semibold leading-5 text-label">
하수관로 편집
</span>
<span
className="mt-0.5 truncate text-[1.05rem] text-muted-foreground"
title={statusMessage}
>
{statusMessage || "편집 도구를 선택하세요."}
</span>
</div>
<div className="flex min-w-0 flex-1 items-center justify-center gap-3">
<div className="flex items-center gap-1 rounded-md bg-container p-1">
{TOOL_BUTTONS.map(({ tool, icon: Icon }) => {
const isActive = activeTool === tool;
const isToolEnabled =
canUseTools && allowedTools.includes(tool);
const label = operationLabels[tool];
if (tool === "VERTEX_EDIT") {
return (
<div
key="vertex-edit-with-snap"
className="flex shrink-0 items-center"
>
<Button
type="button"
color={
activeTool === "VERTEX_EDIT" ? "primary" : "white"
}
className="min-w-[98px] px-2"
disabled={!isToolEnabled}
onClick={() => onSelectTool("VERTEX_EDIT")}
>
<span className="flex items-center justify-center gap-2 whitespace-nowrap">
<Icon className="h-4 w-4" />
<span>{label}</span>
</span>
</Button>
</div>
);
}
return (
<Button
key={tool}
type="button"
color={isActive ? "primary" : "white"}
className="min-w-[74px] shrink-0 px-2"
disabled={!isToolEnabled}
onClick={() => onSelectTool(tool)}
>
<span className="flex items-center justify-center gap-2 whitespace-nowrap">
<Icon className="h-4 w-4" />
<span>{label}</span>
</span>
</Button>
);
})}
</div>
<div className="h-8 w-px shrink-0 bg-border" />
<Button
type="button"
color={isSnapEnabled ? "primary" : "white"}
className="min-w-[82px] shrink-0 px-2"
disabled={!canUseTools}
onClick={onToggleSnap}
title="이동과 꼭지점편집에 스냅핑 적용"
>
<span className="flex items-center justify-center gap-2 whitespace-nowrap">
<Check className="h-4 w-4" />
<span>스냅핑</span>
</span>
</Button>
</div>
<div className="flex w-[140px] shrink-0 items-center justify-end gap-2 border-l border-border pl-3">
<Button
type="button"
color="primary"
className="min-w-[64px] shrink-0 px-2"
disabled={!canSave || isSaving}
onClick={onSave}
>
{isSaving ? "저장 중" : "저장"}
</Button>
<Button
type="button"
color="white"
className="min-w-[64px] shrink-0 px-2"
onClick={onClose}
title="하수관로 편집 취소"
>
<span className="flex items-center justify-center gap-2 whitespace-nowrap">
<X className="h-4 w-4" />
<span>취소</span>
</span>
</Button>
</div>
</div>
</div>
</div>
);
}