fix(onboarding): derive step counter from STEP_ORDER

All six step panels previously hard-coded "X / 5" or "X / 6" in their
header captions, which drifted out of sync with the 7-step STEP_ORDER in
OnboardingHero. Export STEP_ORDER / TOTAL_STEPS / getStepNumber from
OnboardingHero and consume them in every step so the counter is always
the single source of truth.
This commit is contained in:
ZacharyZhang-NY committed 2026-04-16 22:03:57 -04:00
1 parent 5a5587c2a1
commit 183f22e922
7 files changed
+23 -9

No files matched your search

@@ -3,6 +3,7 @@ import { Buildings, FolderOpen } from "@phosphor-icons/react";
import type { ConnectorId, ProfileSnapshot } from "@shared/types";
import type { AppLocale } from "@shared/locale";
import { ActionButton, Input, TextArea, Select } from "../ui";
import { getStepNumber, TOTAL_STEPS } from "./OnboardingHero";
interface CompanyStepProps {
companyName: string;
@@ -57,7 +58,7 @@ export function CompanyStep({
className="bg-card border border-border shadow-sm w-full rounded-lg p-7"
>
<div className="mb-2 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
{t("onboarding.stepLabelCompany")} 3 / 6
{t("onboarding.stepLabelCompany")} {getStepNumber("company")} / {TOTAL_STEPS}
</div>
<div className="mb-1 text-[18px] font-semibold tracking-[-0.01em] text-foreground">
{t("onboarding.step1Title")}
@@ -1,6 +1,7 @@
import { motion } from "framer-motion";
import { ArrowRight, Brain, UserCircle, type Icon } from "@phosphor-icons/react";
import type { ExecutionMode } from "@shared/types";
import { getStepNumber, TOTAL_STEPS } from "./OnboardingHero";
interface ExecutionModeStepProps {
executionMode: ExecutionMode;
@@ -27,7 +28,7 @@ export function ExecutionModeStep({
className="bg-card border border-border shadow-sm w-full rounded-lg p-7"
>
<div className="mb-2 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
{t("onboarding.stepLabelMode")} 5 / 6
{t("onboarding.stepLabelMode")} {getStepNumber("executionmode")} / {TOTAL_STEPS}
</div>
<div className="mb-1 text-[18px] font-semibold tracking-[-0.01em] text-foreground">
{t("onboarding.modeStepTitle")}
@@ -1,6 +1,7 @@
import { motion } from "framer-motion";
import { Cpu, Lightning } from "@phosphor-icons/react";
import { ActionButton, Input, TextArea } from "../ui";
import { getStepNumber, TOTAL_STEPS } from "./OnboardingHero";
interface MissionStepProps {
goalTitle: string;
@@ -35,7 +36,7 @@ export function MissionStep({
className="bg-card border border-border shadow-sm w-full rounded-lg p-7"
>
<div className="mb-2 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
{t("onboarding.stepLabelMission")} 6 / 6
{t("onboarding.stepLabelMission")} {getStepNumber("mission")} / {TOTAL_STEPS}
</div>
<div className="mb-1 text-[18px] font-semibold tracking-[-0.01em] text-foreground">
{t("onboarding.step2Title")}
@@ -4,6 +4,7 @@ import type { ConnectorId, ProfileSnapshot } from "@shared/types";
import type { AppLocale } from "@shared/locale";
import { ActionButton } from "../ui";
import { ModelToggleList, StatusBadge } from "../execution/ModelManagementShared";
import { getStepNumber, TOTAL_STEPS } from "./OnboardingHero";
interface ModelPoolStepProps {
currentLocale: AppLocale;
@@ -52,7 +53,7 @@ export function ModelPoolStep({
className="w-full rounded-lg border border-border bg-card p-7 shadow-sm"
>
<div className="mb-2 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
{t("onboarding.stepLabelModelPool")} 4 / 6
{t("onboarding.stepLabelModelPool")} {getStepNumber("modelpool")} / {TOTAL_STEPS}
</div>
<div className="mb-1 text-[18px] font-semibold tracking-[-0.01em] text-foreground">
{t("onboarding.modelPoolStepTitle")}
@@ -8,6 +8,7 @@ import {
} from "@phosphor-icons/react";
import { ActionButton } from "../ui";
import type { TerminalCommandKey } from "@shared/contracts";
import { getStepNumber, TOTAL_STEPS } from "./OnboardingHero";
interface NodeCheckStepProps {
nodeStatus: { installed: boolean; version: string | null } | null;
@@ -69,7 +70,7 @@ export function NodeCheckStep({
className="bg-card border border-border shadow-sm w-full rounded-lg p-7"
>
<div className="mb-2 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
{t("onboarding.stepLabel1")} 1 / 5 — {t("onboarding.nodeCheckStep")}
{t("onboarding.stepLabel1")} {getStepNumber("nodecheck")} / {TOTAL_STEPS} — {t("onboarding.nodeCheckStep")}
</div>
<div className="mb-1 text-[18px] font-semibold tracking-[-0.01em] text-foreground">
{t("onboarding.nodeCheckTitle")}
@@ -31,7 +31,7 @@ const STEP_LABELS_CONFIG = [
{ key: "onboarding.stepLabelLaunch", icon: Rocket, step: "launch" as const },
] as const;
const STEP_ORDER: OnboardingStep[] = [
export const STEP_ORDER = [
"nodecheck",
"providers",
"company",
@@ -39,7 +39,15 @@ const STEP_ORDER: OnboardingStep[] = [
"executionmode",
"mission",
"launch",
];
] as const satisfies readonly OnboardingStep[];
export type OnboardingStepName = (typeof STEP_ORDER)[number];
export const TOTAL_STEPS = STEP_ORDER.length;
export function getStepNumber(step: OnboardingStepName): number {
return STEP_ORDER.indexOf(step) + 1;
}
interface OnboardingHeroProps {
step: OnboardingStep;
@@ -52,7 +60,7 @@ export function OnboardingHero({
currentLocale: _currentLocale,
t,
}: OnboardingHeroProps) {
const stepIndex = STEP_ORDER.indexOf(step);
const stepIndex = (STEP_ORDER as readonly OnboardingStep[]).indexOf(step);
const stepLabels = STEP_LABELS_CONFIG.map((cfg) => ({
label: t(cfg.key),
@@ -11,6 +11,7 @@ import {
StatusBadge,
INPUT_CLS,
} from "./ProvidersStepShared";
import { getStepNumber, TOTAL_STEPS } from "./OnboardingHero";
/* ------------------------------------------------------------------ */
/* Props */
@@ -104,7 +105,7 @@ export function ProvidersStep({
className="w-full rounded-lg border border-border bg-card p-7 shadow-sm"
>
<div className="mb-2 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
{t("onboarding.stepLabelProviders")} 2 / 6
{t("onboarding.stepLabelProviders")} {getStepNumber("providers")} / {TOTAL_STEPS}
</div>
<div className="mb-1 text-[18px] font-semibold tracking-[-0.01em] text-foreground">
{t("onboarding.providersTitle")}