Files
Aislo/0_old/frontend/src/WorkflowBar.tsx
T

136 lines
4.5 KiB
TypeScript

import React from "react";
import { Check } from "lucide-react";
export type StageKey = "scan" | "route" | "section" | "design" | "quantity" | "document";
export interface WorkflowState {
current_stage: StageKey;
completed: StageKey[];
stale_from: StageKey | null;
stage1_confirmed: any | null;
}
interface StageInfo {
key: StageKey;
label: string;
}
const STAGES: StageInfo[] = [
{ key: "scan", label: "지표면 모델 분석" },
{ key: "route", label: "경로 설계 (BP/EP/CP)" },
{ key: "section", label: "종·횡단 생성" },
{ key: "design", label: "예정 설계" },
{ key: "quantity", label: "수량 산출" },
{ key: "document", label: "견적/문서" },
];
interface WorkflowBarProps {
state: WorkflowState;
onNavigate: (stage: StageKey) => void;
}
export function WorkflowBar({ state, onNavigate }: WorkflowBarProps) {
return (
<div className="workflow-bar" style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
background: "#1e293b",
padding: "12px 24px",
borderRadius: "8px",
marginBottom: "20px",
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
border: "1px solid #334155"
}}>
<div style={{ display: "flex", alignItems: "center", gap: "16px", flex: 1 }}>
{STAGES.map((stage, idx) => {
const isCurrent = state.current_stage === stage.key;
const isCompleted = state.completed.includes(stage.key);
const isStale = state.stale_from !== null && STAGES.findIndex(s => s.key === state.stale_from) <= idx;
const canClick = stage.key === "scan"
|| (stage.key === "route" && state.completed.includes("scan"))
|| (stage.key === "section" && state.completed.includes("route"))
|| isCompleted;
// 현재는 1~3단계까지 활성화한다.
const isSupported = stage.key === "scan" || stage.key === "route" || stage.key === "section";
const activeClick = canClick && isSupported;
return (
<React.Fragment key={stage.key}>
<div
onClick={() => activeClick && onNavigate(stage.key)}
style={{
display: "flex",
alignItems: "center",
gap: "8px",
cursor: activeClick ? "pointer" : "not-allowed",
opacity: isSupported ? 1 : 0.4,
position: "relative"
}}
>
<div style={{
width: "28px",
height: "28px",
borderRadius: "50%",
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: "12px",
fontWeight: "bold",
background: isCurrent
? "#38bdf8"
: isCompleted
? "#10b981"
: "#475569",
color: isCurrent || isCompleted ? "#0f172a" : "#cbd5e1",
border: isCurrent ? "2px solid #ffffff" : "none",
transition: "all 0.2s ease"
}}>
{isCompleted ? <Check size={14} /> : idx + 1}
</div>
<span style={{
fontSize: "14px",
fontWeight: isCurrent ? "bold" : "normal",
color: isCurrent
? "#38bdf8"
: isCompleted
? "#f8fafc"
: "#94a3b8"
}}>
{stage.label}
</span>
{isStale && (
<span style={{
position: "absolute",
top: "-10px",
right: "-15px",
background: "#f59e0b",
color: "#0f172a",
fontSize: "9px",
fontWeight: "bold",
padding: "1px 4px",
borderRadius: "4px",
whiteSpace: "nowrap"
}}>
stale
</span>
)}
</div>
{idx < STAGES.length - 1 && (
<div style={{
flex: 1,
height: "2px",
background: isCompleted ? "#10b981" : "#475569",
margin: "0 12px"
}} />
)}
</React.Fragment>
);
})}
</div>
</div>
);
}